Last active
April 3, 2024 04:23
-
-
Save gcatlin/0dd61f19d40804173d015c01a80461b8 to your computer and use it in GitHub Desktop.
Core Audio sine wave example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// To run: | |
// clang core-audio-sine-wave.c -framework AudioUnit && ./a.out | |
#include <AudioUnit/AudioUnit.h> | |
#define SAMPLE_RATE 48000 | |
#define TONE_FREQUENCY 440 | |
#define M_TAU 2.0 * M_PI | |
OSStatus RenderSineWave( | |
void *inRefCon, | |
AudioUnitRenderActionFlags *ioActionFlags, | |
const AudioTimeStamp *inTimeStamp, | |
UInt32 inBusNumber, | |
UInt32 inNumberFrames, | |
AudioBufferList *ioData) | |
{ | |
static float theta; | |
SInt16 *left = (SInt16 *)ioData->mBuffers[0].mData; | |
for (UInt32 frame = 0; frame < inNumberFrames; ++frame) { | |
left[frame] = (SInt16)(sin(theta) * 32767.0f); | |
theta += M_TAU * TONE_FREQUENCY / SAMPLE_RATE; | |
if (theta > M_TAU) { | |
theta -= M_TAU; | |
} | |
} | |
// Copy left channel to right channel | |
memcpy(ioData->mBuffers[1].mData, left, ioData->mBuffers[1].mDataByteSize); | |
return noErr; | |
} | |
int main() { | |
OSErr err; | |
AudioComponentDescription acd = { | |
.componentType = kAudioUnitType_Output, | |
.componentSubType = kAudioUnitSubType_DefaultOutput, | |
.componentManufacturer = kAudioUnitManufacturer_Apple, | |
}; | |
AudioComponent output = AudioComponentFindNext(NULL, &acd); | |
if (!output) printf("Can't find default output\n"); | |
AudioUnit toneUnit; | |
err = AudioComponentInstanceNew(output, &toneUnit); | |
if (err) fprintf(stderr, "Error creating unit: %d\n", err); | |
AURenderCallbackStruct input = { .inputProc = RenderSineWave }; | |
err = AudioUnitSetProperty(toneUnit, kAudioUnitProperty_SetRenderCallback, | |
kAudioUnitScope_Input, 0, &input, sizeof(input)); | |
if (err) printf("Error setting callback: %d\n", err); | |
AudioStreamBasicDescription asbd = { | |
.mFormatID = kAudioFormatLinearPCM, | |
.mFormatFlags = 0 | |
| kAudioFormatFlagIsSignedInteger | |
| kAudioFormatFlagIsPacked | |
| kAudioFormatFlagIsNonInterleaved, | |
.mSampleRate = 48000, | |
.mBitsPerChannel = 16, | |
.mChannelsPerFrame = 2, | |
.mFramesPerPacket = 1, | |
.mBytesPerFrame = 2, | |
.mBytesPerPacket = 2, | |
}; | |
err = AudioUnitSetProperty(toneUnit, kAudioUnitProperty_StreamFormat, | |
kAudioUnitScope_Input, 0, &asbd, sizeof(asbd)); | |
if (err) printf("Error setting stream format: %d\n", err); | |
err = AudioUnitInitialize(toneUnit); | |
if (err) printf("Error initializing unit: %d\n", err); | |
err = AudioOutputUnitStart(toneUnit); | |
if (err) printf("Error starting unit: %d\n", err); | |
usleep(500000); | |
AudioOutputUnitStop(toneUnit); | |
AudioUnitUninitialize(toneUnit); | |
AudioComponentInstanceDispose(toneUnit); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks! Great example!
I'd suggest some optimization of the rendering callback:
You can replace
float
back toSInt16
. I use float because all my audio unit logic is based on float values. I hear pure and beautiful sine wave!