Reputation: 3750
I've been trying without success to manipulate the samples produced by kAudioUnitType_Generator audio units by attaching an AURenderCallbackStruct to the input of the audio unit right after. I managed to get this working on OS X using the following simple graph:
(input callback) -> multichannel mixer -> (intput callback) -> default output
But I've failed with the following (even simpler) graphs that start with a generator unit:
speech synthesis -> (intput callback) -> default output | fails in render callback with kAudioUnitErr_Uninitialized
audiofile player -> (intput callback) -> default output | fails when scheduling file region with kAudioUnitErr_Uninitialized
I've tried just about everything I can think of, from setting ASBD format to sample rates, but I always get these errors. Does anyone know how to setup a graph where we can manipulate samples from these nice generator units?
Below is the failing render callback function and graph instantiation method for the attempt using speech synthesis. The audiofile player is almost identical for this, except setting up the file playback, of course. Both of these setups work if I remove the callback and add an AUGraphConnectNodeInput in it's place...
static OSStatus RenderCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData) {
AppDelegate *app = (AppDelegate *)inRefCon;
AudioUnit inputUnit = app->_speechUnit;
OSStatus status = noErr;
status = AudioUnitRender(inputUnit, ioActionFlags, inTimeStamp, 0, inNumberFrames, ioData);
// *** ERROR *** kAudioUnitErr_Uninitialized, code: -10867
// ... insert processing code here...
return status;
}
- (int)createSynthGraph {
AUGRAPH_CHECK( NewAUGraph( &_graph ) );
AUNode speechNode, outputNode;
// speech synthesizer
AudioComponentDescription speechCD = {0};
speechCD.componentType = kAudioUnitType_Generator;
speechCD.componentSubType = kAudioUnitSubType_SpeechSynthesis;
speechCD.componentManufacturer = kAudioUnitManufacturer_Apple;
// output device (speakers)
AudioComponentDescription outputCD = {0};
outputCD.componentType = kAudioUnitType_Output;
outputCD.componentSubType = kAudioUnitSubType_DefaultOutput;
outputCD.componentManufacturer = kAudioUnitManufacturer_Apple;
AUGRAPH_CHECK( AUGraphAddNode( _graph, &outputCD, &outputNode ) );
AUGRAPH_CHECK( AUGraphAddNode( _graph, &speechCD, &speechNode ) );
AUGRAPH_CHECK( AUGraphOpen( _graph ) );
AUGRAPH_CHECK( AUGraphNodeInfo( _graph, outputNode, NULL, &_outputUnit ) );
AUGRAPH_CHECK( AUGraphNodeInfo( _graph, speechNode, NULL, &_speechUnit ) );
// setup stream formats:
AudioStreamBasicDescription streamFormat = [self streamFormat];
AU_CHECK( AudioUnitSetProperty( _speechUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &streamFormat, sizeof(streamFormat) ) );
// setup callback:
AURenderCallbackStruct callback;
callback.inputProc = RenderCallback;
callback.inputProcRefCon = self;
AUGRAPH_CHECK( AUGraphSetNodeInputCallback ( _graph, outputNode, 0, &callback ) );
// init and start
AUGRAPH_CHECK( AUGraphInitialize( _graph ) );
AUGRAPH_CHECK( AUGraphStart( _graph ) );
return 0;
}
Upvotes: 3
Views: 1939
Reputation: 7260
kAudioUnitErr_Uninitialized error appears when your audio unit is not initialized. Just initialize your graph before setting problem properties. This will initialize all opened audio units in graph. From AUGraphInitialize discussion in AUGraph.h:
AudioUnitInitialize() is called on each opened node/AudioUnit (get ready to render) and SubGraph that are involved in a interaction.
Upvotes: 1
Reputation: 9464
You must connect these nodes together with AUGraphConnectNodeInput
. The AUGraph
will not initialize AudioUnits within it unless they are connected. Units in a graph that are not connected to other units will not be initialized.
You could also try manually initing them before starting the graph.
Upvotes: 1