mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-05-07 16:01:28 +02:00

quantum, as the callback wants us to provide exactly the amount of samples needed. This is incomplete because core audio may ask for less than the full buffer size (for me, typically 1484 or 1488 bytes of a 2048 byte buffer). As a quick hack until I read the rather impenetrable core audio documentation, assume that each callback request will want about the same number of samples as the preceeding one. This makes sound bearable. Also various cleanup. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5543 8ced0084-cf51-0410-be5f-012b33b47a6e
180 lines
4.6 KiB
C++
180 lines
4.6 KiB
C++
// Copyright (C) 2003 Dolphin Project.
|
|
|
|
// This program 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.0.
|
|
|
|
// This program 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 2.0 for more details.
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
// Official SVN repository and contact information can be found at
|
|
// http://code.google.com/p/dolphin-emu/
|
|
|
|
#include "CoreAudioSoundStream.h"
|
|
|
|
volatile unsigned int numBytesToRender; /* XXX */
|
|
|
|
typedef struct internal
|
|
{
|
|
AudioUnit audioUnit;
|
|
short realtimeBuffer[1024]; /* XXX */
|
|
};
|
|
|
|
OSStatus callback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags,
|
|
const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber,
|
|
UInt32 inNumberFrames, AudioBufferList *ioData)
|
|
{
|
|
internal *soundStruct = (internal *)inRefCon;
|
|
|
|
for (int i=0; i < (int)ioData->mNumberBuffers; i++)
|
|
{
|
|
memcpy(ioData->mBuffers[i].mData, &soundStruct->realtimeBuffer,
|
|
ioData->mBuffers[i].mDataByteSize);
|
|
}
|
|
|
|
numBytesToRender = ioData->mBuffers[0].mDataByteSize; /* XXX */
|
|
return 0;
|
|
}
|
|
|
|
void CoreAudioSound::SoundLoop()
|
|
{
|
|
CoreAudioInit();
|
|
}
|
|
|
|
CoreAudioSound::CoreAudioSound(CMixer *mixer) : SoundStream(mixer)
|
|
{
|
|
}
|
|
|
|
CoreAudioSound::~CoreAudioSound()
|
|
{
|
|
}
|
|
|
|
bool CoreAudioSound::CoreAudioInit()
|
|
{
|
|
ComponentDescription desc;
|
|
OSStatus err;
|
|
UInt32 enableIO;
|
|
AURenderCallbackStruct callback_struct;
|
|
AudioStreamBasicDescription format;
|
|
UInt32 numSamplesPerSlice;
|
|
UInt32 numSamplesPerSliceSize = sizeof numSamplesPerSlice;
|
|
|
|
internal *soundStruct = (internal *)malloc(sizeof(internal));
|
|
memset(soundStruct->realtimeBuffer, 0,
|
|
sizeof soundStruct->realtimeBuffer);
|
|
|
|
desc.componentType = kAudioUnitType_Output;
|
|
desc.componentSubType = kAudioUnitSubType_HALOutput;
|
|
desc.componentFlags = 0;
|
|
desc.componentFlagsMask = 0;
|
|
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
|
|
|
Component component = FindNextComponent(NULL, &desc);
|
|
if (component == NULL)
|
|
printf("error finding audio component\n");
|
|
|
|
err = OpenAComponent(component, &soundStruct->audioUnit);
|
|
if (err)
|
|
printf("error opening audio component\n");
|
|
|
|
//enable output device
|
|
enableIO = 1;
|
|
AudioUnitSetProperty(soundStruct->audioUnit,
|
|
kAudioOutputUnitProperty_EnableIO,
|
|
kAudioUnitScope_Output, 0, &enableIO,
|
|
sizeof enableIO);
|
|
|
|
//set audio format
|
|
FillOutASBDForLPCM(format, m_mixer->GetSampleRate(),
|
|
2, 16, 16, false, false, false);
|
|
err = AudioUnitSetProperty(soundStruct->audioUnit,
|
|
kAudioUnitProperty_StreamFormat,
|
|
kAudioUnitScope_Input, 0, &format,
|
|
sizeof(AudioStreamBasicDescription));
|
|
if (err)
|
|
printf("error setting audio format\n");
|
|
|
|
callback_struct.inputProc = callback;
|
|
callback_struct.inputProcRefCon = soundStruct;
|
|
err = AudioUnitSetProperty(soundStruct->audioUnit,
|
|
kAudioUnitProperty_SetRenderCallback,
|
|
kAudioUnitScope_Input, 0, &callback_struct,
|
|
sizeof callback_struct);
|
|
if (err)
|
|
printf("error setting audio callback\n");
|
|
|
|
err = AudioUnitGetProperty(soundStruct->audioUnit,
|
|
kAudioUnitProperty_MaximumFramesPerSlice,
|
|
kAudioUnitScope_Global, 0,
|
|
&numSamplesPerSlice, &numSamplesPerSliceSize);
|
|
if (err)
|
|
printf("error getting audio buffer size\n");
|
|
|
|
numBytesToRender = numSamplesPerSlice * 4;
|
|
|
|
err = AudioUnitInitialize(soundStruct->audioUnit);
|
|
if (err)
|
|
printf("error initializing audiounit\n");
|
|
|
|
err = AudioOutputUnitStart(soundStruct->audioUnit);
|
|
if (err)
|
|
printf("error starting audiounit\n");
|
|
|
|
do
|
|
{
|
|
soundCriticalSection.Enter();
|
|
m_mixer->Mix(soundStruct->realtimeBuffer, numBytesToRender);
|
|
soundCriticalSection.Leave();
|
|
soundSyncEvent.Wait();
|
|
} while(!threadData);
|
|
|
|
err = AudioOutputUnitStop(soundStruct->audioUnit);
|
|
if (err)
|
|
printf("error stopping audiounit\n");
|
|
|
|
err = AudioUnitUninitialize(soundStruct->audioUnit);
|
|
if (err)
|
|
printf("error uninitializing audiounit\n");
|
|
|
|
err = CloseComponent(soundStruct->audioUnit);
|
|
if (err)
|
|
printf("error while closing audio component\n");
|
|
|
|
free(soundStruct);
|
|
return true;
|
|
}
|
|
|
|
void *coreAudioThread(void *args)
|
|
{
|
|
|
|
((CoreAudioSound *)args)->SoundLoop();
|
|
return NULL;
|
|
}
|
|
|
|
bool CoreAudioSound::Start()
|
|
{
|
|
soundSyncEvent.Init();
|
|
thread = new Common::Thread(coreAudioThread, (void *)this);
|
|
return true;
|
|
}
|
|
|
|
void CoreAudioSound::Stop()
|
|
{
|
|
threadData = 1;
|
|
soundSyncEvent.Set();
|
|
delete thread;
|
|
thread = NULL;
|
|
|
|
return;
|
|
}
|
|
|
|
void CoreAudioSound::Update()
|
|
{
|
|
soundSyncEvent.Set();
|
|
}
|