Thursday, June 6, 2013

AVAudioPlayer updateMeters example in Objective C (iOS).


AVAudioPlayer updateMeters

Refreshes the average and peak power values for all channels of an audio player.

- (void)updateMeters

Discussion of [AVAudioPlayer updateMeters]
To obtain current audio power values, you must call this method before calling averagePowerForChannel: or peakPowerForChannel:.

AVAudioPlayer updateMeters 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:

[audioPlayer updateMeters];


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 updateMeters].
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 updateMeters example.
audioPlayer.meteringEnabled = YES;
audioPlayer.delegate = self;

if (!playerTimer)
{
    playerTimer = [NSTimer scheduledTimerWithTimeInterval:0.001
                  target:self selector:@selector(monitorAudioPlayer)
                userInfo:nil
                 repeats:YES];
}

[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 updateMeters example article.