Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AVAudioPlayer - Metering - Want to build a waveform (graph)

I need to build a visual graph that represents voice levels (dB) in a recorded file. I tried to do it this way:

NSError *error = nil;
AVAudioPlayer *meterPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:self.recording.fileName] error:&error];

if (error) {
    _lcl_logger(lcl_cEditRecording, lcl_vError, @"Cannot initialize AVAudioPlayer with file %@ due to: %@ (%@)", self.recording.fileName, error, error.userInfo);
} else {
    [meterPlayer prepareToPlay];
    meterPlayer.meteringEnabled = YES;
    
    for (NSTimeInterval i = 0; i <= meterPlayer.duration; ++i) {
        meterPlayer.currentTime = i;
        [meterPlayer updateMeters];
        float averagePower = [meterPlayer averagePowerForChannel:0];
        _lcl_logger(lcl_cEditRecording, lcl_vTrace, @"Second: %f, Level: %f dB", i, averagePower);
    }
}
[meterPlayer release];

It would be cool if it worked out however it didn't. I always get -160 dB. Any other ideas on how to implement that?

UPD: Here is what I got finally:

alt text http://img22.imageshack.us/img22/5778/waveform.png

like image 925
Aleks N. Avatar asked Nov 19 '09 23:11

Aleks N.


2 Answers

I just want to help the others who have come into this same question and used a lot of time to search. To save your time, I put out my answer. I dislike somebody here who treat this as kind of secret...

After search around the articles about extaudioservice, audio queue and avfoundation.

I realised that i should use AVFoundation, reason is simple, it is the latest bundle and it is Objective C but not so cpp style.

So the steps to do it is not complicated:

  1. Create AVAsset from the audio file
  2. Create avassetreader from the avasset
  3. Create avassettrack from avasset
  4. Create avassetreadertrackoutput from avassettrack
  5. Add the avassetreadertrackoutput to the previous avassetreader to start reading out the audio data

From the avassettrackoutput you can copyNextSampleBuffer one by one (it is a loop to read all data out).

Each copyNextSampleBuffer gives you a CMSampleBufferRef which can be used to get AudioBufferList by CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer. AudioBufferList is array of AudioBuffer. AudioBuffer is the a bunch of audio data which is stored in its mData part.

You can implement the above in extAudioService as well. But i think the above avfoundation approach is easier.

So next question, what to do with the mData? Note that when you get the avassetreadertrackoutput, you can specify its output format, so we specify the output is lpcm.

Then the mData you finally get is actually a float format amplitude value.

Easy right? Though i used a lot of time to organise this from piece here and there.

Two useful resource for share: Read this article to know basic terms and conceptions: https://www.mikeash.com/pyblog/friday-qa-2012-10-12-obtaining-and-interpreting-audio-data.html

Sample code: https://github.com/iluvcapra/JHWaveform You can copy most of the above mentioned code from this sample directly and used for your own purpose.

like image 75
elephant.lyh Avatar answered Nov 05 '22 08:11

elephant.lyh


I haven't used it myself, but Apple's avTouch iPhone sample has bar graphs powered by AVAudioPlayer, and you can easily check to see how they do it.

like image 3
mahboudz Avatar answered Nov 05 '22 08:11

mahboudz