I get a cracking at the beginning and end of a core audio output queue. The code should simply generate an inaudible tone.
i created a simplified version on github:
https://github.com/MrMatthias/CoreAudioCrackle
the output looks like this:
http://i63.tinypic.com/160yexw.jpg (Frequency is 10kHz in this image instead of 20kHz )
Source:
import "ViewController.h"
#import <stdlib.h>
#import <AudioToolbox/AudioToolbox.h>
#import <Accelerate/Accelerate.h>
#import <objc/runtime.h>
#define BUFFERS 3
#define DURATION 0.5
typedef struct UserData {
AudioQueueRef outputQueue;
UInt32 outputSamplePosition;
AudioQueueBufferRef outputBuffers[BUFFERS];
AudioStreamBasicDescription outputDesc;
/
} UserData;
@interface ViewController () {
UserData userData;
}
@end
@implementation ViewController
- (IBAction)togglePlay:(NSButton*)sender {
if(sender.tag == 0) { /
[self startOutputQueue];
sender.tag = 1;
sender.title = @"Stop";
} else { /
[self stopOutputQueue];
sender.tag = 0;
sender.title = @"Start";
}
}
- (void)viewDidLoad {
[super viewDidLoad];
[self setupOutputQueue];
/
}
-(void)viewWillDisappear {
[self tearDown];
}
#pragma mark - Output Queue
-(void) startOutputQueue {
if(userData.outputQueue != NULL) {
if(!checkError(AudioQueuePrime(userData.outputQueue, 0, NULL), "AudioQueuePrime")) {
NSLog(@"Error priming QutputQueue");
}
if(!checkError(AudioQueueStart(userData.outputQueue, NULL), "AudioQueueStart Output")) {
NSLog(@"Error starting OutputQueue");
}
}
}
-(void) setupOutputQueue {
memset(&userData.outputDesc, 0, sizeof(userData.outputDesc));
userData.outputDesc.mFormatID = kAudioFormatLinearPCM;
userData.outputDesc.mFramesPerPacket = 1;
userData.outputDesc.mFormatFlags = kAudioFormatFlagIsBigEndian | kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
userData.outputDesc.mChannelsPerFrame = 1;
userData.outputDesc.mSampleRate = 44100;
userData.outputDesc.mBitsPerChannel = 16;
userData.outputDesc.mBytesPerFrame = userData.outputDesc.mBytesPerPacket = 2;
userData.outputSamplePosition = 0;
if (userData.outputQueue == NULL) {
if(!checkError(AudioQueueNewOutput(&userData.outputDesc, outputCallback, &userData, CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &userData.outputQueue), "AudioQueueNewOutput")) {
return;
}
UInt32 bufferSize = userData.outputDesc.mBytesPerFrame * userData.outputDesc.mSampleRate * DURATION;
for (int i=0; i<3; i++) {
if(!checkError(AudioQueueAllocateBuffer(userData.outputQueue, bufferSize, &userData.outputBuffers[i]), "AudioQueueAllocateBuffer")) {
return;
}
outputCallback(&userData, userData.outputQueue, userData.outputBuffers[i]);
}
}
}
-(void)stopOutputQueue {
if(userData.outputQueue != NULL) {
checkError(AudioQueueStop(userData.outputQueue, TRUE), "AudioQueueStop");
}
}
-(void)tearDown {
[self stopOutputQueue];
[self deleteOutputQueue];
[self freeOutputBuffers];
}
-(void) deleteOutputQueue {
if(userData.outputQueue != NULL) {
[self freeOutputBuffers];
checkError(AudioQueueDispose(userData.outputQueue, TRUE), "AudioQueueDispose");
userData.outputQueue = NULL;
}
}
-(void) freeOutputBuffers {
for (int i=0; i<BUFFERS; ++i) {
checkError(AudioQueueFreeBuffer(userData.outputQueue, userData.outputBuffers[i]), "AudioQueueFreeBuffer");
}
}
static void outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) {
UserData *userData = (UserData*) inUserData;
UInt32 sampleCount = DURATION * userData->outputDesc.mSampleRate;
double f1 = userData->outputDesc.mSampleRate / 20000;
for (int i=0; i<sampleCount; i++) {
SInt16 sample = CFSwapInt16HostToBig((SInt16)(SHRT_MAX * ( sin((userData->outputSamplePosition + i) * 2.0f * M_PI / f1) )));
((SInt16*)inBuffer->mAudioData)[i] = sample;
}
userData->outputSamplePosition += sampleCount;
inBuffer->mAudioDataByteSize = sampleCount * 2;
AudioQueueEnqueueBuffer(userData->outputQueue, inBuffer, 0, NULL);
}
#pragma mark utility
static BOOL checkError(OSStatus error, const char* location) {
if (error == noErr) {
return YES;
}
/
UInt32 swap = CFSwapInt32HostToBig(error);
char *pSwap =(char*) &swap;
if (isprint(pSwap[0]) && isprint(pSwap[1]) && isprint(pSwap[2]) && isprint(pSwap[3])) {
char errorString[7];
errorString[0] = errorString[5] = '\'';
sprintf((errorString+1), "%s", pSwap);
errorString[6] = '\0';
printf("%s at %s", errorString, location);
}
/
CFErrorRef cferror = CFErrorCreate(kCFAllocatorDefault, kCFErrorDomainOSStatus, error, NULL);
NSLog(@"Error at %s: %@", location, cferror);
return NO;
}
@end