How to write AUGraph output to a file?

I am trying to write (what should be) a simple application that has a sequence of audio devices sequentially in an AUGraph and then writes the output to a file. I added a callback using AUGraphAddRenderNotify. Here is my callback function:

OSStatus MyAURenderCallback(void *inRefCon, AudioUnitRenderActionFlags *actionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) { if (*actionFlags & kAudioUnitRenderAction_PostRender) { ExtAudioFileRef outputFile = (ExtAudioFileRef)inRefCon; ExtAudioFileWriteAsync(outputFile, inNumberFrames, ioData); } } 

Such work. The file is playing, and I can hear what I recorded, but there is a terrible amount of static that makes it barely audible.

Does anyone know what's wrong with that? Or does anyone know the best way to write AUGraph output to a file?

Thanks for the help.

+5
source share
3 answers

I had an epiphany regarding Audio Units just now, which helped me solve my own problem. I had a misconception about how audio unit connections and rendering callbacks work. I thought they were completely different things, but it turns out that a connection is just a short hand for a render callback.

Executing kAudioUnitProperty_MakeConnection from the output of audio device A to the input of audio device B is the same as kAudioUnitProperty_SetRenderCallback at the input of device B and the call function of the call function AudioUnitRender at the output of audio block A.

I tested this by making a make connection after setting the visualization callback, and the render callback was no longer called.

Therefore, I was able to solve my problem by following these steps:

 AURenderCallbackStruct callbackStruct = {0}; callbackStruct.inputProc = MyAURenderCallback; callbackStruct.inputProcRefCon = mixerUnit; AudioUnitSetProperty(ioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callbackStruct, sizeof(callbackStruct)); 

And their callback function did something like this:

 OSStatus MyAURenderCallback(void *inRefCon, AudioUnitRenderActionFlags *actionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) { AudioUnit mixerUnit = (AudioUnit)inRefCon; AudioUnitRender(mixerUnit, actionFlags, inTimeStamp, 0, inNumberFrames, ioData); ExtAudioFileWriteAsync(outputFile, inNumberFrames, ioData); return noErr; } 

This probably should have been obvious to me, but since I was not sure that there were others who were confused in the same way, so I hope this is also useful to them.

I'm still not sure why I am having problems with the AUGraphAddRenderNotify callback. I will delve into this later, but at the moment I have found a solution that seems to work.

+6
source

Here is a sample code from Apple (the project is PlaySequence, but it is not MIDI specific) that might help:

 { CAStreamBasicDescription clientFormat = CAStreamBasicDescription(); ca_require_noerr (result = AudioUnitGetProperty(outputUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &clientFormat, &size), fail); size = sizeof(clientFormat); ca_require_noerr (result = ExtAudioFileSetProperty(outfile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat), fail); { MusicTimeStamp currentTime; AUOutputBL outputBuffer (clientFormat, numFrames); AudioTimeStamp tStamp; memset (&tStamp, 0, sizeof(AudioTimeStamp)); tStamp.mFlags = kAudioTimeStampSampleTimeValid; int i = 0; int numTimesFor10Secs = (int)(10. / (numFrames / srate)); do { outputBuffer.Prepare(); AudioUnitRenderActionFlags actionFlags = 0; ca_require_noerr (result = AudioUnitRender (outputUnit, &actionFlags, &tStamp, 0, numFrames, outputBuffer.ABL()), fail); tStamp.mSampleTime += numFrames; ca_require_noerr (result = ExtAudioFileWrite(outfile, numFrames, outputBuffer.ABL()), fail); ca_require_noerr (result = MusicPlayerGetTime (player, &currentTime), fail); if (shouldPrint && (++i % numTimesFor10Secs == 0)) printf ("current time: %6.2f beats\n", currentTime); } while (currentTime < sequenceLength); } } 
+1
source

Perhaps try this. Copy data from the audio device callback to a long buffer. Play the buffer to check it, then write the entire buffer to a file after you confirm that the entire buffer is in order.

0
source

Source: https://habr.com/ru/post/917293/


All Articles