Thursday, June 6, 2013

AVAudioPlayer peakPowerForChannel example in Objective C (iOS).

AVAudioPlayer peakPowerForChannel

Returns the peak power for a given channel, in decibels, for the sound being played.

- (float)peakPowerForChannel:(NSUInteger)channelNumber

The audio channel whose peak power value you want to obtain. Channel numbers are zero-indexed. A monaural signal, or the left channel of a stereo signal, has channel number 0.

Return Value of [AVAudioPlayer peakPowerForChannel]
A floating-point representation, in decibels, of a given audio channel’s current peak power. A return value of 0 dB indicates full scale, or maximum power; a return value of -160 dB indicates minimum power (that is, near silence).

If the signal provided to the audio player exceeds ±full scale, then the return value may exceed 0 (that is, it may enter the positive range).

Discussion of [AVAudioPlayer peakPowerForChannel]
To obtain a current peak power value, you must call the updateMeters method before calling this method.

AVAudioPlayer peakPowerForChannel example.
You're updating and then asking for the value of the meters almost immediately after the sound starts -- that updateMeters is probably running a few tens of milliseconds after you send play. So if there's any silence at the beginning of the clip, you could very well be getting the correct reading. You should trying delaying your inspection, and you may also need to send updateMeters inside the loop, right before you inspect the values.

You're also never actually getting the meter values for channels > 0, because you pass 0 no matter what the value of i is in the loop. I think you meant to do this:

for (int currChan = 0; currChan < channels; currChan++) {
    //Log the peak and average power
    NSLog(@"%d %0.2f %0.2f", currChan, [audioPlayer peakPowerForChannel:currChan], [audioPlayer averagePowerForChannel:currChan]);

Example of [AVAudioPlayer peakPowerForChannel].
I have used the AVAudioPlayer's peakPowerForChannel and averagePowerForChannel method for getting the decibles

  AVAudioPlayer *avPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:recordedTmpFile error:&error];
    avPlayer.delegate = self;

    avPlayer.meteringEnabled = YES;
     [avPlayer prepareToPlay];
     [avPlayer play];

 NSTimer *levelTimer = [NSTimer scheduledTimerWithTimeInterval: 0.03 target: self selector: @selector(levelTimerCallback:) userInfo: nil repeats: YES];
This method is return the peakPowerForChannel and averagePowerForChannel

- (void)levelTimerCallback:(NSTimer *)timer {

    [avPlayer updateMeters];
    NSLog(@"Peak left: %f Avg right: %f", [avPlayer peakPowerForChannel:0],[avPlayer averagePowerForChannel:0]);


AVAudioPlayer peakPowerForChannel example.
audioPlayer.meteringEnabled = YES;
audioPlayer.delegate = self;

if (!playerTimer)
    playerTimer = [NSTimer scheduledTimerWithTimeInterval:0.001
                  target:self selector:@selector(monitorAudioPlayer)

[audioPlayer play];
Add this two methods to your class:

-(void) monitorAudioPlayer
    [audioPlayer updateMeters];
    for (int i=0; i<audioPlayer.numberOfChannels; i++)
        //Log the peak and average power
         NSLog(@"%d %0.2f %0.2f", i, [audioPlayer peakPowerForChannel:i],[audioPlayer averagePowerForChannel:i]);

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
    NSLog (@"audioPlayerDidFinishPlaying:");
    [playerTimer invalidate];
    playerTimer = nil;

End of AVAudioPlayer peakPowerForChannel example article.