CoreAudioOutput::~CoreAudioOutput()
{
	OSSpinLockLock(_spinlockAU);
	
	if(_au != NULL)
	{
		AudioOutputUnitStop(_au);
		AudioUnitUninitialize(_au);
#if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
		if (IsOSXVersionSupported(10, 6, 0))
		{
			AudioComponentInstanceDispose(_au);
		}
		else
		{
			CloseComponent(_au);
		}
#else
		CloseComponent(_au);
#endif
		_au = NULL;
	}
	
	OSSpinLockUnlock(_spinlockAU);
	
	delete _buffer;
	_buffer = NULL;
	
	free(_spinlockAU);
	_spinlockAU = NULL;
}
uint8_t WhiteNoiseGenerator::generateSample()
{
#ifdef __APPLE__
	#ifdef MAC_OS_X_VERSION_10_7
	if (IsOSXVersionSupported(10, 7, 0))
	{
		return (uint8_t)(arc4random_uniform(0x00000080) & 0x7F);
	}
	return (uint8_t)((arc4random() % 0x00000080) & 0x7F);
	#else
	return (uint8_t)((arc4random() % 0x00000080) & 0x7F);
	#endif
#else
	return (uint8_t)(rand() & 0x7F);
#endif
}
CoreAudioOutput::CoreAudioOutput(size_t bufferSamples, size_t sampleSize)
{
	OSStatus error = noErr;
	
	_spinlockAU = (OSSpinLock *)malloc(sizeof(OSSpinLock));
	*_spinlockAU = OS_SPINLOCK_INIT;
	
	_buffer = new RingBuffer(bufferSamples, sampleSize);
	_volume = 1.0f;
	
	// Create a new audio unit
#if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
	if (IsOSXVersionSupported(10, 6, 0))
	{
		AudioComponentDescription audioDesc;
		audioDesc.componentType = kAudioUnitType_Output;
		audioDesc.componentSubType = kAudioUnitSubType_DefaultOutput;
		audioDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
		audioDesc.componentFlags = 0;
		audioDesc.componentFlagsMask = 0;
		
		AudioComponent audioComponent = AudioComponentFindNext(NULL, &audioDesc);
		if (audioComponent == NULL)
		{
			return;
		}
		
		error = AudioComponentInstanceNew(audioComponent, &_au);
		if (error != noErr)
		{
			return;
		}
	}
	else
	{
		ComponentDescription audioDesc;
		audioDesc.componentType = kAudioUnitType_Output;
		audioDesc.componentSubType = kAudioUnitSubType_DefaultOutput;
		audioDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
		audioDesc.componentFlags = 0;
		audioDesc.componentFlagsMask = 0;
		
		Component audioComponent = FindNextComponent(NULL, &audioDesc);
		if (audioComponent == NULL)
		{
			return;
		}
		
		error = OpenAComponent(audioComponent, &_au);
		if (error != noErr)
		{
			return;
		}
	}
#else
	ComponentDescription audioDesc;
	audioDesc.componentType = kAudioUnitType_Output;
	audioDesc.componentSubType = kAudioUnitSubType_DefaultOutput;
	audioDesc.componentManufacturer = kAudioUnitManufacturer_Apple;
	audioDesc.componentFlags = 0;
	audioDesc.componentFlagsMask = 0;
	
	Component audioComponent = FindNextComponent(NULL, &audioDesc);
	if (audioComponent == NULL)
	{
		return;
	}
	
	error = OpenAComponent(audioComponent, &_au);
	if (error != noErr)
	{
		return;
	}
#endif
	
	// Set the render callback
	AURenderCallbackStruct callback;
	callback.inputProc = &CoreAudioOutputRenderCallback;
	callback.inputProcRefCon = _buffer;
	
	error = AudioUnitSetProperty(_au,
								 kAudioUnitProperty_SetRenderCallback,
								 kAudioUnitScope_Input,
								 0,
								 &callback,
								 sizeof(callback) );
	
	if(error != noErr)
	{
		return;
	}
	
	// Set up the audio unit for audio streaming
	AudioStreamBasicDescription outputFormat;
	outputFormat.mSampleRate = SPU_SAMPLE_RATE;
	outputFormat.mFormatID = kAudioFormatLinearPCM;
	outputFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagsNativeEndian | kLinearPCMFormatFlagIsPacked;
	outputFormat.mBytesPerPacket = SPU_SAMPLE_SIZE;
	outputFormat.mFramesPerPacket = 1;
	outputFormat.mBytesPerFrame = SPU_SAMPLE_SIZE;
	outputFormat.mChannelsPerFrame = SPU_NUMBER_CHANNELS;
	outputFormat.mBitsPerChannel = SPU_SAMPLE_RESOLUTION;
	
	error = AudioUnitSetProperty(_au,
								 kAudioUnitProperty_StreamFormat,
								 kAudioUnitScope_Input,
								 0,
								 &outputFormat,
								 sizeof(outputFormat) );
	
	if(error != noErr)
	{
		return;
	}
	
	// Initialize our new audio unit
	error = AudioUnitInitialize(_au);
	if(error != noErr)
	{
		return;
	}
}