syedhali / EZAudio

An iOS and macOS audio visualization framework built upon Core Audio useful for anyone doing real-time, low-latency audio processing and visualizations.
Other
4.94k stars 821 forks source link

EZAudioFile Help #323

Closed nick-thompson closed 8 years ago

nick-thompson commented 8 years ago

Hi, I'm trying to follow the readme for getting audio data from file via EZAudioFile: https://github.com/syedhali/EZAudio#EZAudioFile, and I'm confused about the correct way to do this.

When the following lines execute, can subsequent lines assume that the entire file has been read and that the AudioBufferList is complete?

// Read the frames from the EZAudioFile into the AudioBufferList
UInt32 framesRead;
UInt32 isEndOfFile;
[self.audioFile readFrames:numberOfFramesToRead
           audioBufferList:bufferList
                bufferSize:&framesRead
                       eof:&isEndOfFile]

If not, I would presume that the appropriate way of waiting & checking for completion there is to use the delegate:

-(void)     audioFile:(EZAudioFile *)audioFile
            readAudio:(float **)buffer
       withBufferSize:(UInt32)bufferSize
 withNumberOfChannels:(UInt32)numberOfChannels
{
...
}

But it's unclear to me how to implement that callback. Will it be called multiple times for each chunk of data read? Will it be called once with the entire float ** buffer? Must I retain my own reference to isEndOfFile and check that repeatedly until it turns true? Any help here would be greatly appreciated, thank you!

dxclancy commented 8 years ago

Every time you call readFrames, it will read a certain number of frames and call through to the delegate method with the data for those frames.

One approach you can take is to loop and read until eof while you process the data in the delegate.

nick-thompson commented 8 years ago

I see, that makes much more sense. Thank you!

nick-thompson commented 8 years ago

One more question @dxclancy: within the loop issuing calls to readFrames, can I assume that once eof is reached that the AudioBufferList has been fully populated? Or is the actual read operation happening off on another thread or something? That is, must I wait for the final delegate call before I can assume the AudioBufferList has been fully populated?

dxclancy commented 8 years ago

I always find it instructive to look at the code when I have questions like this.

You can see that readFrames calls ExtAudioFileRead, which is documented to be synchronous.

After that, you can see that the AudioBufferList is filled, and you could, upon the completion of readFrames, access this buffer list. However, readFrames additionally calls convertDataFromAudioBufferList toFloatBuffers. These float buffers are what you receive in the delegate callback, and is what the rest of the EZAudio library uses for graphing/fft calculation etc... It looks to me that the delegate will get called even before the completion of read frames, so that when you get the eof result, the AudioBufferList is full and your delegate has already been called with float buffers.

If you are using the data directly from the AudioBufferList, you needn't even use the delegate. However, I think that part of the point of EZAudio is the conversion it provides.

That's my interpretation anyway. I'm not one of the collaborators :)

I'm not very experienced with audio data, so it isn't clear to me what format either the AudioBuffers or the Float buffers really represent. For my own uses, I use EZAudio to process audio files and determine frequency and intensity using various EZAudio calls, so the data is "opaque" to me.

nick-thompson commented 8 years ago

Thank you @dxclancy! That was super helpful. I got everything working now; I'll go ahead and close this issue.