2005-12-11 10:25:27 +00:00
|
|
|
/* $Id$ */
|
|
|
|
|
2009-08-21 20:21:05 +00:00
|
|
|
/*
|
|
|
|
* This file is part of OpenTTD.
|
|
|
|
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
|
|
|
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2008-05-06 15:11:33 +00:00
|
|
|
/** @file cocoa_s.cpp Sound driver for cocoa. */
|
|
|
|
|
2006-02-01 09:08:25 +00:00
|
|
|
/*****************************************************************************
|
|
|
|
* Cocoa sound driver *
|
|
|
|
* Known things left to do: *
|
|
|
|
* - Might need to do endian checking for it to work on both ppc and x86 *
|
|
|
|
*****************************************************************************/
|
2005-12-10 11:16:45 +00:00
|
|
|
|
|
|
|
#ifdef WITH_COCOA
|
|
|
|
|
|
|
|
#include "../stdafx.h"
|
|
|
|
#include "../debug.h"
|
|
|
|
#include "../driver.h"
|
|
|
|
#include "../mixer.h"
|
2008-06-17 19:38:00 +00:00
|
|
|
#include "../core/endian_type.hpp"
|
2005-12-10 11:16:45 +00:00
|
|
|
#include "cocoa_s.h"
|
|
|
|
|
2009-07-14 16:43:45 +00:00
|
|
|
#define Rect OTTDRect
|
|
|
|
#define Point OTTDPoint
|
|
|
|
#include <AudioUnit/AudioUnit.h>
|
2005-12-10 11:16:45 +00:00
|
|
|
#undef Rect
|
2009-07-14 16:43:45 +00:00
|
|
|
#undef Point
|
2005-12-10 11:16:45 +00:00
|
|
|
|
2007-07-05 12:23:54 +00:00
|
|
|
static FSoundDriver_Cocoa iFSoundDriver_Cocoa;
|
2005-12-10 11:16:45 +00:00
|
|
|
|
|
|
|
static AudioUnit _outputAudioUnit;
|
|
|
|
|
|
|
|
/* The CoreAudio callback */
|
2007-11-07 21:35:33 +00:00
|
|
|
static OSStatus audioCallback(void *inRefCon, AudioUnitRenderActionFlags *inActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList * ioData)
|
2005-12-10 11:16:45 +00:00
|
|
|
{
|
2007-11-07 21:35:33 +00:00
|
|
|
MxMixSamples(ioData->mBuffers[0].mData, ioData->mBuffers[0].mDataByteSize / 4);
|
2005-12-10 11:16:45 +00:00
|
|
|
|
|
|
|
return noErr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-07-05 12:23:54 +00:00
|
|
|
const char *SoundDriver_Cocoa::Start(const char * const *parm)
|
2005-12-10 11:16:45 +00:00
|
|
|
{
|
|
|
|
Component comp;
|
|
|
|
ComponentDescription desc;
|
2007-11-07 21:35:33 +00:00
|
|
|
struct AURenderCallbackStruct callback;
|
2005-12-10 11:16:45 +00:00
|
|
|
AudioStreamBasicDescription requestedDesc;
|
|
|
|
|
|
|
|
/* Setup a AudioStreamBasicDescription with the requested format */
|
|
|
|
requestedDesc.mFormatID = kAudioFormatLinearPCM;
|
|
|
|
requestedDesc.mFormatFlags = kLinearPCMFormatFlagIsPacked;
|
|
|
|
requestedDesc.mChannelsPerFrame = 2;
|
2009-08-09 23:04:08 +00:00
|
|
|
requestedDesc.mSampleRate = GetDriverParamInt(parm, "hz", 44100);
|
2005-12-10 11:16:45 +00:00
|
|
|
|
|
|
|
requestedDesc.mBitsPerChannel = 16;
|
|
|
|
requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
|
2006-01-07 13:21:04 +00:00
|
|
|
|
2008-06-17 19:38:00 +00:00
|
|
|
#if TTD_ENDIAN == TTD_BIG_ENDIAN
|
2005-12-10 11:16:45 +00:00
|
|
|
requestedDesc.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
|
2008-06-17 19:38:00 +00:00
|
|
|
#endif /* TTD_ENDIAN == TTD_BIG_ENDIAN */
|
2005-12-10 11:16:45 +00:00
|
|
|
|
|
|
|
requestedDesc.mFramesPerPacket = 1;
|
|
|
|
requestedDesc.mBytesPerFrame = requestedDesc.mBitsPerChannel * requestedDesc.mChannelsPerFrame / 8;
|
|
|
|
requestedDesc.mBytesPerPacket = requestedDesc.mBytesPerFrame * requestedDesc.mFramesPerPacket;
|
|
|
|
|
2009-07-10 18:22:04 +00:00
|
|
|
MxInitialize(requestedDesc.mSampleRate);
|
2005-12-10 11:16:45 +00:00
|
|
|
|
|
|
|
/* Locate the default output audio unit */
|
2007-11-07 21:35:33 +00:00
|
|
|
desc.componentType = kAudioUnitType_Output;
|
|
|
|
desc.componentSubType = kAudioUnitSubType_HALOutput;
|
|
|
|
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
2005-12-10 11:16:45 +00:00
|
|
|
desc.componentFlags = 0;
|
|
|
|
desc.componentFlagsMask = 0;
|
|
|
|
|
|
|
|
comp = FindNextComponent (NULL, &desc);
|
2006-06-27 21:25:53 +00:00
|
|
|
if (comp == NULL) {
|
2005-12-10 11:16:45 +00:00
|
|
|
return "cocoa_s: Failed to start CoreAudio: FindNextComponent returned NULL";
|
2006-06-27 21:25:53 +00:00
|
|
|
}
|
2005-12-10 11:16:45 +00:00
|
|
|
|
|
|
|
/* Open & initialize the default output audio unit */
|
2006-06-27 21:25:53 +00:00
|
|
|
if (OpenAComponent(comp, &_outputAudioUnit) != noErr) {
|
2005-12-10 11:16:45 +00:00
|
|
|
return "cocoa_s: Failed to start CoreAudio: OpenAComponent";
|
2006-06-27 21:25:53 +00:00
|
|
|
}
|
2005-12-10 11:16:45 +00:00
|
|
|
|
2006-06-27 21:25:53 +00:00
|
|
|
if (AudioUnitInitialize(_outputAudioUnit) != noErr) {
|
2005-12-10 11:16:45 +00:00
|
|
|
return "cocoa_s: Failed to start CoreAudio: AudioUnitInitialize";
|
2006-06-27 21:25:53 +00:00
|
|
|
}
|
2005-12-10 11:16:45 +00:00
|
|
|
|
|
|
|
/* Set the input format of the audio unit. */
|
2006-06-27 21:25:53 +00:00
|
|
|
if (AudioUnitSetProperty(_outputAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &requestedDesc, sizeof(requestedDesc)) != noErr) {
|
2006-02-01 09:08:25 +00:00
|
|
|
return "cocoa_s: Failed to start CoreAudio: AudioUnitSetProperty (kAudioUnitProperty_StreamFormat)";
|
2006-06-27 21:25:53 +00:00
|
|
|
}
|
2005-12-10 11:16:45 +00:00
|
|
|
|
|
|
|
/* Set the audio callback */
|
|
|
|
callback.inputProc = audioCallback;
|
|
|
|
callback.inputProcRefCon = NULL;
|
2007-11-07 21:35:33 +00:00
|
|
|
if (AudioUnitSetProperty(_outputAudioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)) != noErr) {
|
|
|
|
return "cocoa_s: Failed to start CoreAudio: AudioUnitSetProperty (kAudioUnitProperty_SetRenderCallback)";
|
2006-06-27 21:25:53 +00:00
|
|
|
}
|
2005-12-10 11:16:45 +00:00
|
|
|
|
|
|
|
/* Finally, start processing of the audio unit */
|
2006-06-27 21:25:53 +00:00
|
|
|
if (AudioOutputUnitStart(_outputAudioUnit) != noErr) {
|
2005-12-10 11:16:45 +00:00
|
|
|
return "cocoa_s: Failed to start CoreAudio: AudioOutputUnitStart";
|
2006-06-27 21:25:53 +00:00
|
|
|
}
|
2005-12-10 11:16:45 +00:00
|
|
|
|
|
|
|
/* We're running! */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-07-05 12:23:54 +00:00
|
|
|
void SoundDriver_Cocoa::Stop()
|
2005-12-10 11:16:45 +00:00
|
|
|
{
|
2007-11-07 21:35:33 +00:00
|
|
|
struct AURenderCallbackStruct callback;
|
2005-12-10 11:16:45 +00:00
|
|
|
|
|
|
|
/* stop processing the audio unit */
|
2006-06-27 21:25:53 +00:00
|
|
|
if (AudioOutputUnitStop(_outputAudioUnit) != noErr) {
|
2006-12-26 22:04:53 +00:00
|
|
|
DEBUG(driver, 0, "cocoa_s: Core_CloseAudio: AudioOutputUnitStop failed");
|
2005-12-10 11:16:45 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Remove the input callback */
|
|
|
|
callback.inputProc = 0;
|
|
|
|
callback.inputProcRefCon = 0;
|
2007-11-07 21:35:33 +00:00
|
|
|
if (AudioUnitSetProperty(_outputAudioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callback, sizeof(callback)) != noErr) {
|
|
|
|
DEBUG(driver, 0, "cocoa_s: Core_CloseAudio: AudioUnitSetProperty (kAudioUnitProperty_SetRenderCallback) failed");
|
2005-12-10 11:16:45 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CloseComponent(_outputAudioUnit) != noErr) {
|
2006-12-26 22:04:53 +00:00
|
|
|
DEBUG(driver, 0, "cocoa_s: Core_CloseAudio: CloseComponent failed");
|
2005-12-10 11:16:45 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* WITH_COCOA */
|