1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-20 15:31:10 +00:00
CLK/OSBindings/Mac/Clock Signal/Wrappers/AudioQueue.m

137 lines
3.4 KiB
Mathematica
Raw Normal View History

//
// AudioQueue.m
// Clock Signal
//
// Created by Thomas Harte on 14/01/2016.
// Copyright © 2016 Thomas Harte. All rights reserved.
//
#import "AudioQueue.h"
@import AudioToolbox;
#define AudioQueueNumAudioBuffers 3
#define AudioQueueStreamLength 2048
#define AudioQueueBufferLength 512
@implementation AudioQueue
{
AudioQueueRef _audioQueue;
AudioQueueBufferRef _audioBuffers[AudioQueueNumAudioBuffers];
unsigned int _audioStreamReadPosition, _audioStreamWritePosition, _queuedAudioStreamSegments;
int16_t _audioStream[AudioQueueStreamLength];
BOOL _isOutputtingAudio;
}
#pragma mark -
#pragma mark AudioQueue callbacks and setup; for pushing audio out
- (void)audioQueue:(AudioQueueRef)theAudioQueue didCallbackWithBuffer:(AudioQueueBufferRef)buffer
{
@synchronized(self)
{
if(_queuedAudioStreamSegments > AudioQueueNumAudioBuffers-1) _isOutputtingAudio = YES;
if(_isOutputtingAudio && _queuedAudioStreamSegments)
{
_queuedAudioStreamSegments--;
memcpy(buffer->mAudioData, &_audioStream[_audioStreamReadPosition], buffer->mAudioDataByteSize);
_audioStreamReadPosition = (_audioStreamReadPosition + AudioQueueBufferLength)%AudioQueueStreamLength;
}
else
{
memset(buffer->mAudioData, 0, buffer->mAudioDataByteSize);
_isOutputtingAudio = NO;
}
AudioQueueEnqueueBuffer(theAudioQueue, buffer, 0, NULL);
}
}
static void audioOutputCallback(
void *inUserData,
AudioQueueRef inAQ,
AudioQueueBufferRef inBuffer)
{
[(__bridge AudioQueue *)inUserData audioQueue:inAQ didCallbackWithBuffer:inBuffer];
}
- (instancetype)init
{
self = [super init];
if(self)
{
/*
Describe a mono, 16bit, 44.1Khz audio format
*/
AudioStreamBasicDescription outputDescription;
outputDescription.mSampleRate = 44100;
outputDescription.mFormatID = kAudioFormatLinearPCM;
outputDescription.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
outputDescription.mBytesPerPacket = 2;
outputDescription.mFramesPerPacket = 1;
outputDescription.mBytesPerFrame = 2;
outputDescription.mChannelsPerFrame = 1;
outputDescription.mBitsPerChannel = 16;
outputDescription.mReserved = 0;
// create an audio output queue along those lines
if(!AudioQueueNewOutput(
&outputDescription,
audioOutputCallback,
(__bridge void *)(self),
NULL,
kCFRunLoopCommonModes,
0,
&_audioQueue))
{
_audioStreamWritePosition = AudioQueueBufferLength;
UInt32 bufferBytes = AudioQueueBufferLength * sizeof(int16_t);
int c = AudioQueueNumAudioBuffers;
while(c--)
{
AudioQueueAllocateBuffer(_audioQueue, bufferBytes, &_audioBuffers[c]);
memset(_audioBuffers[c]->mAudioData, 0, bufferBytes);
_audioBuffers[c]->mAudioDataByteSize = bufferBytes;
AudioQueueEnqueueBuffer(_audioQueue, _audioBuffers[c], 0, NULL);
}
AudioQueueStart(_audioQueue, NULL);
}
}
return self;
}
2016-01-15 01:35:36 +00:00
- (void)dealloc
{
if(_audioQueue) AudioQueueDispose(_audioQueue, NO);
}
- (void)enqueueAudioBuffer:(const int16_t *)buffer numberOfSamples:(unsigned int)lengthInSamples
{
@synchronized(self)
{
memcpy(&_audioStream[_audioStreamWritePosition], buffer, lengthInSamples * sizeof(int16_t));
_audioStreamWritePosition = (_audioStreamWritePosition + lengthInSamples)%AudioQueueStreamLength;
if(_queuedAudioStreamSegments == (AudioQueueStreamLength/AudioQueueBufferLength))
{
_audioStreamReadPosition = (_audioStreamReadPosition + lengthInSamples)%AudioQueueStreamLength;
}
else
{
_queuedAudioStreamSegments++;
}
}
}
@end