I'm writing a little c based synthesizer. I'm having a problem when I try to enqueue buffers with the function AudioQueueEnqueueBuffer. In different executions i'm having different errors, like malloc-error of the buffer or BAD_ISTRUCTION or BAD_ACCESS(code=EXC_I386_...). Sometimes the callback encode successfully enqueue buffers, but the program crashes when is trying to start the AudioQueue or when is copying data into the buffer. Here there is the code, I hope you can help me.
Xcode print to me also this strange warning when my code go into the callback: "warning: could not load any Objective-C class information. This will significantly reduce the quality of type information available.", but I'don't now why...
synthesis.h
#include <stdio.h>
#include <stdlib.h>
#include <AudioToolBox/AudioQueue.h>
#include <CoreAudio/CoreAudioTypes.h>
#include <math.h>
#include <stdbool.h>
#include <MacTypes.h>
#include <string.h>
#include <CoreFoundation/CoreFoundation.h>
#define PI 3.141592
#define DBG(func, ex) fprintf(stderr, "Error in %s. n. %d\n", func, ex); exit(ex);
static const UInt8 nOfBuffer = 3;
struct wave {
Float64 samplingRate;
Float64 phase;
UInt32 frequency;
SInt16 *samples;
UInt16 seconds;
};
typedef struct wave Wave;
struct stream {
Wave sine;
AudioStreamBasicDescription asbd;
AudioQueueRef audioQueue;
AudioQueueBufferRef audioBuffer[nOfBuffer];
UInt32 bufferSizeByte;
UInt32 counter;
UInt32 lastPos;
Boolean isRunning;
UInt32 nOfPacketToRead;
};
typedef struct stream Stream;
void init(
Stream *sine
);
static void fillBuffer(
void *userData,
AudioQueueRef aQ,
AudioQueueBufferRef inBuf
);
void generateSine(
Stream *sine
);
main.c
#include "synthesis.h"
int main() {
Stream *sine = (Stream *)malloc(sizeof(Stream));
init(sine);
generateSine(sine);
return 0;
}
synthesis.c
#include "synthesis.h"
#include <limits.h>
static void fillBuffer(void *userData, AudioQueueRef aQ, AudioQueueBufferRef buf) {
/*
callback for fill audioqueue's buffers
*/
Stream *sine = (Stream *)userData;
if(!sine->isRunning) return;
OSStatus err = noErr;
UInt32 dif = 0;
UInt32 i = 0;
SInt16 *data = (SInt16 *)buf->mAudioData;
UInt32 lenght = buf->mAudioDataBytesCapacity / sizeof(SInt16);
/* fill the buffer with the samples creates in generateSine */
while (sine->counter - sine->lastPos < lenght && sine->counter < (sine->sine.samplingRate *
sine->sine.seconds)) {
data[i] = sine->sine.samples[sine->counter];
i++;
sine->counter++;
}
dif = sine->counter - sine->lastPos;
buf->mAudioDataByteSize = dif * sizeof(SInt16);
if(dif > 0) {
err = AudioQueueEnqueueBuffer(aQ, buf, 0, NULL);
if(err != noErr) {
DBG("aQenqueuebuffer", err);
}
sine->lastPos = sine->counter;
} else {
sine->isRunning = false;
err = AudioQueueStop(aQ, false);
if(err != noErr) {
DBG("aQstop", err);
}
}
}
void init(Stream *sine) {
/*
initialize all var and set the ASBD for an integer 16 bit linear PCM
*/
OSStatus err = noErr;
sine->sine.frequency = 440;
sine->sine.phase = 0.0;
sine->sine.samplingRate = 96000;
sine->counter = 0;
sine->lastPos = 0;
sine->bufferSizeByte = 0x4000;
sine->sine.seconds = 2;
sine->sine.samples = (SInt16 *)malloc(sizeof(SInt16) * sine->sine.seconds * sine->asbd.mSampleRate);
sine->asbd.mBytesPerPacket = 2;
sine->asbd.mFramesPerPacket = 1;
sine->asbd.mBytesPerFrame = 2;
sine->asbd.mChannelsPerFrame = 1;
sine->asbd.mBitsPerChannel = 16;
sine->asbd.mSampleRate = 96000;
sine->asbd.mFormatID = 'lpcm';
sine->asbd.mReserved = 0;
sine->asbd.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
err = AudioQueueNewOutput(&sine->asbd, fillBuffer, sine, CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0,
&sine->audioQueue);
if(err != noErr) {
DBG("aQnewOutput", err);
}
for(int i = 0; i < nOfBuffer; i++) {
err = AudioQueueAllocateBuffer(sine->audioQueue, sine->bufferSizeByte, &sine->audioBuffer[i]);
if(err != noErr) {
DBG("aQallocatebuffer", err);
}
}
}
void generateSine(Stream *sine) {
OSStatus err = noErr;
UInt32 lenght = sine->sine.samplingRate * sine->sine.seconds;
for(int i = 0; i < lenght; i++) {
sine->sine.samples[i] = sin(2 * PI * sine->sine.frequency * i + sine->sine.phase) * SHRT_MAX;
}
sine->isRunning = true;
for(int i = 0; i < nOfBuffer; i++) {
fillBuffer((void *)sine, sine->audioQueue, sine->audioBuffer[i]);
}
err = AudioQueueStart(sine->audioQueue, NULL);
if(err != noErr) {
DBG("aQstart", err);
}
do {
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.25, false);
}while(sine->isRunning);
AudioQueueDispose(sine->audioQueue, false);
free(sine->sine.samples);
free(sine);
}