sample decibel level for the current song playing in the background
I'm trying to get the decibel level in my app开发者_开发问答 for the song that is being played by IOS's iPod. I know i can get info about the song with [[[MPMusicPlayerController iPodMusicPlayer] nowPlayingItem], and I know I can tell the decibel level of a song using the AVAudioPlayer peakPowerForChannel method, but I have not had luck stringing the two together to sample the decibel level for the current playing song.
I was looking for the same thing and I was able to do it but it was not a straight forward process.
First I used the TSLibraryExport to export the song from the iPod into my app directory. The reason is that after many attempts, 1) AVPlayer and MPMusicPlayerController simply won't give you the decibel levels. 2) AVAudioPlayer won't read the MPMediaItemPropertyAssetURL from the MediaPicker no matter what. Seems like the NSURL from the iPod is not the real file path, therefore it just won't read it. At least I couldn't do it this way.
So,
1) Downlaod the TSLibraryExport and you will see the methods for exporting from the iPod to your app. I just used these from that library:
-(IBAction) handleExportTapped {}
-(void) updateExportProgress: (NSTimer*) timer {} //this is actually nice to display the progress
-(void) setUpAVPlayerForURL: (NSURL*) url {} //this is triggered after the export is done
static BOOL coreAudioCanOpenURL (NSURL* url) {}
static NSString* myDocumentsDirectory() {}
2) Once you are able to export from iPod to your app, initialize the AVAudioPlayer in the setUpAVPlayerForURL or whatever your method name is.
-(void) setUpAVPlayerForURL: (NSURL*) url {
newPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL: url error: nil];
[newPlayer setMeteringEnabled:YES];
[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(getLevel:) userInfo:nil repeats: YES];
[newPlayer play];}
newPlayer is an AVAudioPlayer instance variable declared in your header file.
3) Now that you have imported the song into your app and it's playing you can show the decibels how you want. In my test I just dumped them into a Label.
- (void)getLevel:(NSTimer *)timer {
if (newPlayer.playing == YES) {
[newPlayer updateMeters];
dBLevel = [newPlayer averagePowerForChannel:1]; //dBlevel is a float ivar declared in my header file
dBLabel.text = [NSString stringWithFormat:@"%.01f",dBLevel]; //%.01f is just to show 2 decimals
nowPlayingLabel.text = [NSString stringWithFormat:@"%.01f",[newPlayer peakPowerForChannel:1]];
}
The bad thing about this is that since you are copying the file, your app would need more space, and second, I think the user might have a file that won't export because of different file types, compatibility, blah blah blah...
I hope this helps. I've spent a few days trying to come up with a solution after reading a lot online but this seemed the only one that made it possible.
The answer can be found in this question: How can I implement a volume meter for a song currently playing? (iPhone OS 3.1.3)
It is done using averagePowerForChannel
of AVAudioPlayer
There is also a code sample: AvTouch
If you want to integrate this by choosing tracks from the media player, the following links advise on this process:
iphone - Using MPMediaItems with AVAudioPlayer - Stack Overflow
Use MPMediaPicker selections as AVAudioPlayer inputs
I was able to do what you want mixing both in a much simpler way.
The code is simple and I guess you were trying a similar thing. This worked for me:
MPMediaItem *item = musicPlayer.nowPlayingItem;
NSURL *url = [item valueForProperty:MPMediaItemPropertyAssetURL];
[self playSong:url];
_audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
[_audioPlayer setNumberOfLoops:-1];
[_audioPlayer setMeteringEnabled:YES];
精彩评论