Question

I'm a total noob when it comes to core audio so bear with me. Basically what I want to do is record audio data from a machine's default mic, record until the user decides to stop, and then do some analysis on the entire recording. I've been learning from the book "Learning Core Audio" by Chis Adamson and Kevin Avila (which is an awesome book, found it here: http://www.amazon.com/Learning-Core-Audio-Hands-On-Programming/dp/0321636848/ref=sr_1_1?ie=UTF8&qid=1388956621&sr=8-1&keywords=learning+core+audio ). I see how the AudioQueue works, but I'm not sure how to get data as it's coming from the buffers and store it in a global array.

The biggest problem is that I can't allocate an array a priori because we have no idea how long the user wants to record for. I'm guessing that a global array would have to be passed to the AudioQueue's callback where it would then append data from the latest buffer, however I'm not exactly sure how to do that, or if that's the correct place to be doing so.

If using AudioUnits I'm guessing that I would need to create two audio units, one a remote IO unit to get the microphone data and one generic output audio unit that would do the data appending in the unit's (I'm guessing here, really not sure) AudioUnitRender() function.

If you know where I need to be doing these things or know any resources that could help explain how this works, that would be awesome.

I eventually want to learn how to do this in iOS and Mac OS platforms. For the time being I'm just working in the Mac OS.

Was it helpful?

Solution 2

Ok everyone, so I figured out the answer to my own question, and I only had to add about 10 lines of code to get it to work. Basically what I did was in the user data struct, or as Apple calls it the client data struct I added a variable to keep track of the total number of recorded samples, the sample rate (just so I would have access to the value inside the callback) and a pointer that would point to the audio data. In the callback function, I reallocated memory for the pointer and then copied the contents of the buffer into the newly allocated memory.

I'll post the code for my client recorder struct and the lines of code inside the callback function. I would like to post code for the entire program, but much of it was borrowed from the book "Learning Core Audio" by Chis Adamson and Kevin Avila and I don't want to infringe on any copyrights held by the book (can someone tell me if it's legal to post that here or not? if it is I'd be more than happy to post the whole program).

the client recorder struct code:

//user info struct for recording audio queue callbacks
typedef struct MyRecorder{
    AudioFileID recordFile;
    SInt64 recordPacket;
    Boolean running;
    UInt32 totalRecordedSamples;
    Float32 * allData;
    Float64 sampleRate;
}MyRecorder;

This struct needs to be initialized in the main loop of the program. It would look something like this:

MyRecorder recoder = {0};

I know I spelled "recorder" incorrectly.

Next, what I did inside the callback function:

//now let's also write the data to a buffer that can be accessed in the rest of the program
//first calculate the number of samples in the buffer
Float32 nSamples = RECORD_SECONDS * recorder->sampleRate;
nSamples = (UInt32) nSamples;

//so first we need to reallocate memory that the recorder.allData pointer is pointing to
//pretty simple, just add the amount of samples we just recorded to the number that we already had
//to get the current total number of samples, and the size of each sample, which we get from
//sizeof(Float32).
recorder->allData = realloc(recorder->allData, sizeof(Float32) * (nSamples + recorder->totalRecordedSamples));


//now we need to copy what's in the current buffer into the memory that we just allocated
//however, rememeber that we don't want to overwrite what we already just recorded
//so using pointer arith, we need to offset the recorder->allData pointer in memcpy by
//the current value of totalRecordedSamples
memcpy((recorder->allData) + (recorder->totalRecordedSamples), inBuffer->mAudioData, sizeof(Float32) * nSamples);

//update the number of total recorded samples
recorder->totalRecordedSamples += nSamples;

And of course at the end of my program I freed the memory in the recoder.allData pointer.

Also, my experience with C is very limited, so if I'm making some mistakes especially with memory management, please let me know. Some of the malloc, realloc, memcpy etc. type functions in C sort of freak me out.

EDIT: Also I'm now working on how to do the same thing using AudioUnits, I'll post the solution to that when done.

OTHER TIPS

Since you know the sample rate, your app can pre-allocated a sufficient number of new buffers (for example, in a linked list) in the UI run-loop (for example, periodically, based on an NSTimer or CADisplayLink), into which you can then just copy data during the Audio Queue callbacks.

There are also a few async file write functions that are safe to call inside an audio callback. After recording you can copy the data back out of the file into a now-known-sized memory array (or just mmap the file).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top