I'd like to play a synthesised sound in an iPhone. Instead of using a pre-recorded sound and using SystemSoundID to play an existing binary, I'd like to synthesise it. Partially, that's because I want to be able to play the sound continuously (e.g. when the user's finger is on the screen) instead of a one-off sound sample.
If I wanted to synthesise a Middle A+1 (A4) (440Hz), I can calculate a sine wave using sin(); what I don't know is how to arrange those bits into a packet which CoreAudio can then play. Most of the tutorials that exist on the net are concerned with simply playing existing binaries.
Can anyone help me with a simple synthesised sine sound wave at 440Hz?
What you want to do it probably to setup an AudioQueue. It allows you to fill a buffer with synthesized audio data in a callback. You would setup the AudeioQueue to run in a new thread as such:
#define BUFFER_SIZE 16384
#define BUFFER_COUNT 3
static AudioQueueRef audioQueue;
void SetupAudioQueue() {
OSStatus err = noErr;
// Setup the audio device.
AudioStreamBasicDescription deviceFormat;
deviceFormat.mSampleRate = 44100;
deviceFormat.mFormatID = kAudioFormatLinearPCM;
deviceFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
deviceFormat.mBytesPerPacket = 4;
deviceFormat.mFramesPerPacket = 1;
deviceFormat.mBytesPerFrame = 4;
deviceFormat.mChannelsPerFrame = 2;
deviceFormat.mBitsPerChannel = 16;
deviceFormat.mReserved = 0;
// Create a new output AudioQueue for the device.
err = AudioQueueNewOutput(&deviceFormat, AudioQueueCallback, NULL,
CFRunLoopGetCurrent(), kCFRunLoopCommonModes,
0, &audioQueue);
// Allocate buffers for the AudioQueue, and pre-fill them.
for (int i = 0; i < BUFFER_COUNT; ++i) {
AudioQueueBufferRef mBuffer;
err = AudioQueueAllocateBuffer(audioQueue, BUFFER_SIZE, mBuffer);
if (err != noErr) break;
AudioQueueCallback(NULL, audioQueue, mBuffer);
}
if (err == noErr) err = AudioQueueStart(audioQueue, NULL);
if (err == noErr) CFRunLoopRun();
}
You callback method AudioQueueCallback will then be called whenever the AudioQueue needs more data. Implement with something like:
void AudioQueueCallback(void* inUserData, AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer) {
void* pBuffer = inBuffer->mAudioData;
UInt32 bytes = inBuffer->mAudioDataBytesCapacity;
// Write max <bytes> bytes of audio to <pBuffer>
outBuffer->mAudioDataByteSize = actualNumberOfBytesWritten
err = AudioQueueEnqueueBuffer(audioQueue, inBuffer, 0, NULL);
}