0

I'm creating a Mac OS X CoreAudio command-line program with proprietary rendering of some alphanumeric terminal input into a live audio signal, by means of AudioUnits, trying to stay as simple as possible. All works fine up to matching output sample rate.

As a starting point I'm using the Chapter 07 tutorial code of Addisson Wesley's "Learning Core Audio", CH07_AUGraphSineWave.

I initialize the AudioComponent "by the book":

void CreateAndConnectOutputUnit (MyGenerator *generator) 
{

AudioComponentDescription theoutput = {0}; 

theoutput.componentType = kAudioUnitType_Output;
theoutput.componentSubType = kAudioUnitSubType_DefaultOutput;
theoutput.componentManufacturer = kAudioUnitManufacturer_Apple;

AudioComponent comp = AudioComponentFindNext (NULL, &theoutput);
if (comp == NULL) {
    printf ("can't get output unit");
    exit (-1);
}
CheckError (AudioComponentInstanceNew(comp, &generator->outputUnit),
            "Couldn't open component for outputUnit");
AURenderCallbackStruct input;
input.inputProc = MyRenderProc;
input.inputProcRefCon = generator;
CheckError(AudioUnitSetProperty(generator->outputUnit,
                                kAudioUnitProperty_SetRenderCallback, 
                                kAudioUnitScope_Input,
                                0,
                                &input, 
                                sizeof(input)),
           "AudioUnitSetProperty failed");

CheckError (AudioUnitInitialize(generator->outputUnit),
            "Couldn't initialize output unit");

}

My main problem is in my not knowing how to retreive the output hardware sample rate for the rendering AURenderCallbackStruct since it does play a vital part in the signal generating process. I can't afford having the sample rate hard-coded into the rendering callback, although knowing it's the easiest way, since rate mismatch causes the signal being played at wrong pitch.

Is there a way of getting the default output's sample rate on such a low-level API? Is there a way of matching it somehow, without getting overly complicated? Have I missed something?

Thanks in advance.

Regards,

Tom

user3078414
  • 1,942
  • 2
  • 16
  • 24

2 Answers2

3

When calling AudioUnitGetProperty, the 6th parameter must be a pointer to a variable that will get the size of the answer.

Float64 sampleRate;
UInt32 sampleRateSize;
CheckError(AudioUnitGetProperty(generator->outputUnit,
                            kAudioUnitProperty_SampleRate, 
                            kAudioUnitScope_Input,
                            0,
                            &sampleRate, 
                            &sampleRateSize),
"AudioUnitGetProperty failed");

However, as long as the sample rate has not been set, the function does not return a value (but there is also no error!) You can however set the sample rate with for instance:

Float64 sampleRate = 48000;

CheckError(AudioUnitSetProperty(generator->outputUnit,
                                kAudioUnitProperty_SampleRate,
                                kAudioUnitScope_Input,
                                0,
                                &sampleRate,
                                sizeof(sampleRate)),
"AudioUnitGetProperty failed");

From now on you can also read the value with the Get-call. This does not answer the question, what the default value is. As far as I know that is always 44100 Hz.

Rinus
  • 41
  • 2
  • Just for future reference the sample rate is not always 44100hz. I'm currently using a 2017 MBP that defaults to 48khz. – mindTree Mar 27 '18 at 12:04
  • does `GetProperty` always return what has been set in `SetProperty` or will it return the actual sample rate? It seems like on some devices 44100 is not supported, so I am wondering whether in this case it will return the 44100 that were (tried) to set, or whether it returns 48000 (or whatever their default / fallback is) – N4ppeL Mar 01 '22 at 15:16
0

The sample-rate is a property of all AudioUnits - see kAudioUnitProperty_SampleRate (documentation here) - although ultimately it's the IO Unit (RemoteIO on iOS or HAL unit on MacOSX) that drives the sample-rate at the audio interface. This is not available in the call-back structure; you need to read this property with AudioUnitGetProperty() in your initialisation code.

In your case, the following would probably do it:

Float64 sampleRate;
CheckError(AudioUnitGetProperty(generator->outputUnit,
                                kAudioUnitProperty_SampleRate, 
                                kAudioUnitScope_Input,
                                0,
                                &sampleRate, 
                                sizeof(sampleRate)),

If you're targeting iOS, you also need to interact with the Audio Session.

marko
  • 9,029
  • 4
  • 30
  • 46