I'm building a simple AudioUnit app which should use an AUGraph
to connect a generator (which generates, say, a sine wave) to a format converter (because that seems like what I need) to an output device.
Code snippets:
{
AudioComponentDescription desc ;
desc.componentType = kAudioUnitType_Generator ;
desc.componentSubType = kAudioUnitSubType_ScheduledSoundPlayer ;
desc.componentFlags = 0 ;
desc.componentFlagsMask = 0 ;
desc.componentManufacturer = kAudioUnitManufacturer_Apple ;
status = AUGraphAddNode ( mGraph , &desc , &mGeneratorNode ) ;
checkOSStatus ( "creating generator node" , status ) ;
}
I do similarly for mConverterNode
with kAudioUnitType_FormatConverter
/kAudioUnitSubType_AUConverter
and for mOutputNode
with kAudioUnitType_Output
/kAudioUnitSubType_DefaultOutput
.
I then open the graph:
AUGraphOpen ( mGraph ) ; // error checking code omitted from example
I then get references to them:
AUGraphNodeInfo ( mGraph , mGeneratorNode , 0,&mGeneratorRef ) ; // error checking code omitted from example
I then set the format:
{
AudioStreamBasicDescription format ;
format.mSampleRate = mSamplingRate ;
format.mFormatID = kAudioFormatLinearPCM ;
format.mFormatFlags = kAudioFormatFlagIsSignedInteger ;
format.mFramesPerPacket = 1 ;
format.mChannelsPerFrame = 1 ; // mono
format.mBitsPerChannel = 16 ;
format.mBytesPerFrame = format.mBitsPerChannel*format.mChannelsPerFrame/8 ;
format.mBytesPerPacket = format.mBytesPerFrame*format.mFramesPerPacket ;
status = AudioUnitSetProperty ( mGeneratorRef , kAudioUnitProperty_StreamFormat , kAudioUnitScope_Output , kOutputBus , &format,sizeof(format) ) ;
checkOSStatus ( "setting output format" , status ) ;
}
(Note: kOutputBus
is an enum to 0; it's an anachronism from a previous example I found. Also, mSamplingRate
is a size_t
whose value is 48000
)
And set the render callback:
{
AURenderCallbackStruct cb ;
cb.inputProc = &_callbackProxy ;
cb.inputProcRefCon = static_cast<void*> ( this ) ;
status = AudioUnitSetProperty ( mGeneratorRef , kAudioUnitProperty_SetRenderCallback , kAudioUnitScope_Output , 0 , &cb,sizeof(cb) ) ;
checkOSStatus ( "setting the generator callback" , status ) ;
}
However, for both the stream format and the render callback I get kAudio_ParamError
back as the resultant status.
No matter what I do (mono/stereo, when I place that command, etc), I cannot make it work.
Note: I later do this:
AUGraphConnectNodeInput ( mGraph , mGeneratorNode,0 , mConverterNode,0 ) ;
AUGraphConnectNodeInput ( mGraph , mConverterNode,0 , mOutputNode,0 ) ;
AUGraphInitialize ( mGraph ) ;
AUGraphStart ( mGraph ) ;
// again, error-checking code omitted from example
And it works........ But I can't set those properties and therefore can't generate audio.
What am I missing?
(To people with 1500+ reputation: please make an "osx-sierra" tag; I'm a bit shy of that mark)
From an obscure comment at the end of this:
https://discussions.apple.com/thread/1989797?tstart=0
I ran
AUGraphOpen
at the very beginning before creating things (why?) and it worked.But then I was getting invalid format errors, so I set the format on the input of the converter instead of the output of the generator.
But then it wasn't calling the render callback, so I removed the generator altogether and put the render callback on the input of the converter.
At this point, it worked and is generating my sound.
I hope this helps somebody else in the future with this so-horribly-documented API.