From e8d718383e1fe4e98a938f152c3e285357e98215 Mon Sep 17 00:00:00 2001 From: Steve Checkoway Date: Wed, 9 Jul 2003 05:26:33 +0000 Subject: [PATCH] Seperate the QuickTime sound drivers into two classes. One (working atm) class for a single Sound Manager channel. One (not working atm) class for multiple Sound Manager channels. --- .../src/arch/Sound/RageSoundDriver_QT.cpp | 473 +++++------------- stepmania/src/arch/Sound/RageSoundDriver_QT.h | 49 +- .../src/arch/Sound/RageSoundDriver_QT1.cpp | 213 ++++++++ .../src/arch/Sound/RageSoundDriver_QT1.h | 55 ++ stepmania/src/arch/arch.cpp | 17 +- stepmania/src/arch/arch_darwin.h | 2 +- 6 files changed, 436 insertions(+), 373 deletions(-) create mode 100644 stepmania/src/arch/Sound/RageSoundDriver_QT1.cpp create mode 100644 stepmania/src/arch/Sound/RageSoundDriver_QT1.h diff --git a/stepmania/src/arch/Sound/RageSoundDriver_QT.cpp b/stepmania/src/arch/Sound/RageSoundDriver_QT.cpp index cdaad9c392..8db113395f 100644 --- a/stepmania/src/arch/Sound/RageSoundDriver_QT.cpp +++ b/stepmania/src/arch/Sound/RageSoundDriver_QT.cpp @@ -19,148 +19,86 @@ using namespace QT; const unsigned channels = 2; const unsigned samplesize = channels*16; -const unsigned samples = 4096; +const unsigned samples = 512; const unsigned freq = 44100; const unsigned buffersize = samples*samplesize/8; -const unsigned initialQTSoundChannels = 8; -const unsigned SndCommand_qLength = 2; - -static ComponentInstance soundClock; -static bool useMultipleChannels; +/* Oh boy! dealing with memory at inturupt time. What fun! */ #pragma options align=power -struct channelInfo { - RageSound *snd; - volatile bool stopping; - volatile int last_pos; - volatile int flush_pos; - volatile Uint64 start_time; - volatile Uint32 fill_me; - SndChannelPtr channel; - CmpSoundHeader header; - Uint8 *buffer[2]; /* Double Buffer */ - channelInfo() { snd=NULL; channel=NULL; } - void reset() { stopping=false; flush_pos=0; last_pos=0; start_time=0; fill_me=0; } -}; - -static dequefree_channels; -static vectorplaying_channels; +static volatile Uint32 fill_me = 0; +static UInt8 *buffer[2]; +static CmpSoundHeader header; RageSound_QT::RageSound_QT() { - useMultipleChannels = canPlayMultiChannels(); - LOG->Trace("Can we use multiple channels? %s", (useMultipleChannels ? "yes" : "no")); + RageException::ThrowNonfatal("Class not finished!"); + + /*SndCallBackUPP callback; + callback = NewSndCallBackUPP(GetData); + memset(&header, 0, sizeof(header)); + header.numChannels = channels; + header.sampleSize = samplesize / channels; + header.sampleRate = rate44khz; /* really 44.1kHz * / + header.numFrames = samples; + header.encode = cmpSH; + + buffer[0] = new Uint8[buffersize]; + buffer[1] = new Uint8[buffersize]; + memset(buffer[0], 0, buffersize); + memset(buffer[1], 0, buffersize); + + channel = new SndChannel; + channel->userInfo = reinterpret_cast(this); + channel->qLength = 2; + soundOutput = OpenDefaultComponent(kSoundOutputDeviceType, NULL); ASSERT(soundOutput != NULL); - TimeRecord record; - ComponentInstance soundOutput; + + TimeRecord record; SoundComponentGetInfo(soundOutput, NULL, siOutputLatency, &record); latency = record.value.lo / record.scale; - if (!useMultipleChannels) - latency += samples / freq; /* double buffer */ + latency += samples / freq; /* double buffer * / - SndCallBackUPP callback = NewSndCallBackUPP(GetData); + OSErr err = SndNewChannel(&channel, sampledSynth, initStereo, callback); + + if (err != noErr) { + delete channel; + channel = NULL; + RageException::ThrowNonfatal("Unable to create audio channel"); + } - soundClock = NULL; - SndChannelPtr chan = NULL; SndCommand cmd; - OSErr err; - Uint8 *zero = NULL; - Uint8 *one = NULL; + cmd.cmd = clockComponentCmd; + cmd.param1 = true; + cmd.param2 = 0; + err |= SndDoImmediate(channel, &cmd); - for (unsigned i=0; i(&clock); + err |= SndDoImmediate(channel, &cmd); + last_pos = 0; - memset(&info->header, 0, sizeof(&info->header)); - info->header.numChannels = channels; - info->header.sampleSize = samplesize / channels; - info->header.sampleRate = rate44khz; /* really 44.1kHz */ - info->header.numFrames = samples; - info->header.encode = cmpSH; + cmd.cmd = callBackCmd; + cmd.param2 = 0; + err |= SndDoCommand(channel, &cmd, false); - if (useMultipleChannels || zero == NULL) { - zero = new Uint8[buffersize]; - one = new Uint8[buffersize]; - memset(zero, 0, buffersize); - memset(one, 0, buffersize); - } - info->buffer[0] = zero; - info->buffer[1] = one; - - if (useMultipleChannels || chan == NULL) { - chan = new SndChannel; - chan->userInfo = reinterpret_cast(info); - chan->qLength = SndCommand_qLength; - err = SndNewChannel(&chan, sampledSynth, initStereo, callback); - if (err != noErr) { - SAFE_DELETE(info->channel); - RageException::ThrowNonfatal("Unable to create audio channel. THIS IS A BUG!"); - } - } - info->channel = chan; - - if (!soundClock) { - cmd.cmd = clockComponentCmd; - cmd.param1 = true; - cmd.param2 = 0; - err |= SndDoImmediate(info->channel, &cmd); - - cmd.cmd = getClockComponentCmd; - cmd.param1 = 0; - cmd.param2 = reinterpret_cast(&soundClock); - err |= SndDoImmediate(info->channel, &cmd); - } - - if (err != noErr) - RageException::ThrowNonfatal("Unable to create audio channel. THIS IS A BUG!"); - free_channels.push_back(info); - } - - ASSERT(free_channels.size() == initialQTSoundChannels); - playing_channels.reserve(initialQTSoundChannels); - if (!useMultipleChannels) { /* start the callbacks */ - cmd.cmd = callBackCmd; - cmd.param1 = 0; - cmd.param2 = 0; - err |= SndDoCommand(chan, &cmd, false); - } + if (err != noErr) + RageException::ThrowNonfatal("Unable to create audio channel");*/ } RageSound_QT::~RageSound_QT() { - LockMutex L(SOUNDMAN->lock); - int size = playing_channels.size(); - - for (int i=0; ichannel) - SndDisposeChannel(info->channel, true); - SAFE_DELETE_ARRAY(info->buffer[0]); - SAFE_DELETE_ARRAY(info->buffer[1]); - } - - size = free_channels.size(); - for (int i=0; ichannel) - SndDisposeChannel(info->channel, true); - SAFE_DELETE_ARRAY(info->buffer[0]); - SAFE_DELETE_ARRAY(info->buffer[1]); - if (!useMultipleChannels) - break; - } - + /*if (channel) + SndDisposeChannel(channel, true); + SAFE_DELETE_ARRAY(buffer[0]); + SAFE_DELETE_ARRAY(buffer[1]); if (soundOutput) - CloseComponent(soundOutput); - if (soundClock) - CloseComponent(soundClock); + CloseComponent(soundOutput);*/ } -void RageSound_QT::GetData(SndChannelPtr chan, SndCommand *cmd_passed) { +void RageSound_QT::GetData(SndChannel *chan, SndCommand *cmd_passed) { + /*while (!SOUNDMAN) + SDL_Delay(10); LockMutex L(SOUNDMAN->lock); - register OSErr err = noErr; static bool gettingData=false; static int recursiveCalls = 0; if (gettingData) { @@ -169,260 +107,109 @@ void RageSound_QT::GetData(SndChannelPtr chan, SndCommand *cmd_passed) { RageException::Throw("GetData() called recursively too many times."); } else recursiveCalls = 0; - gettingData=true; - channelInfo *info = reinterpret_cast(chan->userInfo); - ASSERT(info); - LOG->Trace("GetData() sound 0x%X", reinterpret_cast(info->snd)); + gettingData = true; + static SoundMixBuffer mix; + RageSound_QT *P = reinterpret_cast(chan->userInfo); + + fill_me = cmd_passed->param2; + UInt32 play_me = !fill_me; + + if (!P->last_pos){ + TimeRecord tr; + ClockGetTime(P->clock, &tr); + UInt64 temp = tr.value.hi; + temp <<= 32; + temp |= tr.value.lo; + double d = static_cast(temp)/tr.scale*freq; + temp = static_cast(d); + P->last_pos = static_cast(temp % 0x00000000FFFFFFFFLL); + } else + P->last_pos += samples; + + /* Swap buffers * / + header.samplePtr = reinterpret_cast(buffer[play_me]); SndCommand cmd; - register UInt32 play_me; + cmd.cmd = bufferCmd; + cmd.param1 = 0; + cmd.param2 = reinterpret_cast(&header); + SndDoCommand(chan, &cmd, 0); - if (cmd_passed != NULL) { - info->fill_me = cmd_passed->param2; - play_me = !info->fill_me; - info->header.samplePtr = reinterpret_cast(info->buffer[play_me]); - cmd.cmd = bufferCmd; - cmd.param1 = 0; - cmd.param2 = reinterpret_cast(&info->header); - LOG->Trace("Sending bufferCmd sound 0x%X", reinterpret_cast(info->snd)); - err = SndDoCommand(chan, &cmd, false); - if (err != noErr) - goto bail; - } + /* Clear the fill buffer * / + memset(buffer[fill_me], 0, buffersize); - if (info->stopping){ - LOG->Trace("Stopping"); - return; /* We're done */ - } + for (unsigned i=0; isounds.size(); ++i) { + if (P->sounds[i]->stopping) + continue; - /* Clear the fill buffer */ - memset(info->buffer[info->fill_me], 0, buffersize); - - if (useMultipleChannels) { - if (!info->last_pos){ - TimeRecord tr; - ClockGetTime(soundClock, &tr); - info->start_time = tr.value.hi; - info->start_time <<= 32; - info->start_time |= tr.value.lo; + unsigned got = P->sounds[i]->snd->GetPCM(reinterpret_cast(buffer[fill_me]), buffersize, P->last_pos); + mix.write(reinterpret_cast(buffer[fill_me]), got / 2); + if (got < buffersize) { + P->sounds[i]->stopping = true; + P->sounds[i]->flush_pos = P->last_pos + (got * 8 / samplesize); } - - LOG->Trace("About to GetPCM() sound 0x%X", reinterpret_cast(info->snd)); - register int got = info->snd->GetPCM(reinterpret_cast(info->buffer[info->fill_me]), buffersize, info->last_pos); - LOG->Trace("Got %D bytes", got); - if (static_cast(got) < buffersize) { - info->stopping = true; - info->flush_pos = info->last_pos + (got * 8 / samplesize); /* (got / (samplesize / 8)) */ - } - info->last_pos += samples; - } else { - static SoundMixBuffer mix; - register int size = playing_channels.size(); - for (int i=0; ilast_pos){ - TimeRecord tr; - ClockGetTime(soundClock, &tr); - info2->start_time = tr.value.hi; - info2->start_time <<= 32; - info2->start_time |= tr.value.lo; - } - - LOG->Trace("About to GetPCM() sound 0x%X", reinterpret_cast(info2->snd)); - register int got = info2->snd->GetPCM(reinterpret_cast(info->buffer[info->fill_me]), buffersize, info2->last_pos); - LOG->Trace("Got %D bytes", got); - if (static_cast(got) < buffersize) { - info2->stopping = true; - info2->flush_pos = info2->last_pos + (got * 8 / samplesize); - } - mix.write(reinterpret_cast(info->buffer[info->fill_me]), got / 2); - info2->last_pos += samples; - } - mix.read(reinterpret_cast(info->buffer[info->fill_me])); } - if (cmd_passed != NULL) { - cmd.cmd = callBackCmd; - cmd.param2 = play_me; - LOG->Trace("Sending callBackCmd sound 0x%X", reinterpret_cast(info->snd)); - err = SndDoCommand(chan, &cmd, false); - if (err != noErr) - goto bail; - } - gettingData=false; - return; + mix.read(reinterpret_cast(buffer[fill_me])); -bail: - RageException::Throw("SndDoCommand failed with error %d", err); + cmd.cmd = callBackCmd; + cmd.param2 = play_me; + SndDoCommand(chan, &cmd, 0); + gettingData=false;*/ } - void RageSound_QT::StartMixing(RageSound *snd) { + /*sound *s = new sound; + s->snd = snd; + LockMutex L(SOUNDMAN->lock); - LOG->Trace("StartMixing(). Mixing sound 0x%X", reinterpret_cast(snd)); - SndCommand cmd; - channelInfo *info; - - if (free_channels.size()) { - info = free_channels.front(); - free_channels.pop_front(); - } else { /* No free audio channels, create another */ - LOG->Warn("Out of audio channels, creating channel number %D", playing_channels.size()+1); - info = new channelInfo; - - memset(&info->header, 0, sizeof(&info->header)); - info->header.numChannels = channels; - info->header.sampleSize = samplesize / channels; - info->header.sampleRate = rate44khz; /* really 44.1kHz */ - info->header.numFrames = samples; - info->header.encode = cmpSH; - - info->buffer[0] = new Uint8[buffersize]; - info->buffer[1] = new Uint8[buffersize]; - memset(info->buffer[0], 0, buffersize); - memset(info->buffer[1], 0, buffersize); - - if (useMultipleChannels) { - info->channel = new SndChannel; - info->channel->userInfo = reinterpret_cast(info); - info->channel->qLength = SndCommand_qLength; - register OSErr err = SndNewChannel(&(info->channel), sampledSynth, initStereo, NewSndCallBackUPP(GetData)); - - if (err != noErr) { - SAFE_DELETE(info->channel); - RageException::Throw("Unable to create audio channel. THIS IS A BUG."); - } - } - } - info->reset(); - info->snd = snd; - /* Fill the first buffer with data */ - playing_channels.push_back(info); - if (useMultipleChannels) { - GetData(info->channel, NULL); - cmd.cmd = callBackCmd; - cmd.param1 = 0; - cmd.param2 = !info->fill_me; - SndDoCommand(info->channel, &cmd, 0); /* command queue is empty */ - } + sounds.push_back(s); + LOG->Trace("There are %D sounds playing", sounds.size());*/ } void RageSound_QT::StopMixing(RageSound *snd) { - LockMutex L(SOUNDMAN->lock); - LOG->Trace("StopMixing(). Stopping sound 0x%X", reinterpret_cast(snd)); - /* Find the sound. */ - int size = playing_channels.size(); - int i; - channelInfo *info; + /*LockMutex L(SOUNDMAN->lock); - for (i=0; i<=size; ++i) - if ((info=playing_channels[i])->snd == snd) - break; - if (i==size) { - LOG->Trace("Not stopping a sound because it's not playing."); + /* Find the sound. * / + unsigned i; + for(i = 0; i < sounds.size(); ++i) + if(sounds[i]->snd == snd) break; + if(i == sounds.size()) + { + LOG->Trace("not stopping a sound because it's not playing"); return; } - playing_channels.erase(playing_channels.begin()+i); - if (useMultipleChannels) { - SndCommand cmd; - cmd.cmd = flushCmd; - cmd.param1 = 0; - cmd.param2 = 0; - LOG->Trace("Flushing channel with song %X", reinterpret_cast(snd)); - SndDoImmediate(info->channel, &cmd); - cmd.cmd = quietCmd; - SndDoImmediate(info->channel, &cmd); - } - free_channels.push_back(info); + delete sounds[i]; + sounds.erase(sounds.begin()+i, sounds.begin()+i+1); + LOG->Trace("There are %D sounds playing", sounds.size());*/ } void RageSound_QT::Update(float delta) { #pragma unused (delta) - LockMutex L(SOUNDMAN->lock); + /*LockMutex L(SOUNDMAN->lock); - vector playing = playing_channels; - int size = playing.size(); - for (int i=0; istopping != 0) + vectorsnds = sounds; + for (unsigned i = 0; i < snds.size(); ++i) { + if (!sounds[i]->stopping) continue; - if (GetPosition(info->snd) < info->flush_pos) + if (GetPosition(snds[i]->snd) < sounds[i]->flush_pos) continue; - info->snd->StopPlaying(); - } + snds[i]->snd->StopPlaying(); + }*/ } int RageSound_QT::GetPosition(const RageSound *snd) const { - LockMutex L(SOUNDMAN->lock); - TimeRecord tr; - ClockGetTime(soundClock, &tr); - UInt64 time = tr.value.hi; - time <<= 32; - time |= tr.value.lo; - - /* Find the info */ - register int size = playing_channels.size(); - register int i; - channelInfo *info; - for (i=0; isnd == snd) - break; - if (i == size) - RageException::Throw("Can't get the position of a sound that isn't playing"); - - LOG->Trace("GetPosition() sound 0x%X", reinterpret_cast(snd)); - - time -= info->start_time; /* Now time contains the total time the sound was played. */ - time = time * freq / tr.scale; /* Now time contains the number of samples played. */ - return static_cast(time % 0x00000000FFFFFFFFLL); +#pragma unused (snd) + /*TimeRecord tr; + ClockGetTime(clock, &tr); + UInt64 temp = tr.value.hi; + temp <<= 32; + temp |= tr.value.lo; + double d = static_cast(temp)/tr.scale*freq; + temp = static_cast(d); + return static_cast(temp % 0x00000000FFFFFFFFLL);*/ } float RageSound_QT::GetPlayLatency() const { - return latency; + //return latency; } - -/* Pascal code from SoundManager docs. - -FUNCTION MyCanPlayMultiChannels: Boolean; - VAR - myResponse: LongInt; - myResult: Boolean; - myErr: OSErr; - myVersion: NumVersion; - BEGIN - myResult := FALSE; - myVersion := SndSoundManagerVersion; - myErr := Gestalt(gestaltSoundAttr, myResponse); - IF myVersion.majorRev >= 3 THEN - IF (myErr = noErr) AND (BTst(myResponse, gestaltMultiChannels)) THEN - myResult := TRUE - ELSE - BEGIN - myErr := Gestalt(gestaltHardwareAttr, myResponse); - IF (myErr = noErr) AND (BTst(myResponse, gestaltHasASC)) THEN - myResult := TRUE - END; - MyCanPlayMultiChannels := myResult; - END; -*/ - -bool canPlayMultiChannels(){ - register long response; - register OSErr err; - NumVersion version; - register bool result; - - result = false; - version = SndSoundManagerVersion(); - err = Gestalt(gestaltSoundAttr, &response); - if (version.majorRev >= 3){ - if((err == noErr) && (response & gestaltMultiChannels == gestaltMultiChannels)) - result = true; - } else { - err = Gestalt(gestaltHardwareAttr, &response); - if ((err == noErr) && (response & gestaltHasASC == gestaltHasASC)) - result = true; - } - return result; -} - diff --git a/stepmania/src/arch/Sound/RageSoundDriver_QT.h b/stepmania/src/arch/Sound/RageSoundDriver_QT.h index 8753946574..ec5dbfbd29 100644 --- a/stepmania/src/arch/Sound/RageSoundDriver_QT.h +++ b/stepmania/src/arch/Sound/RageSoundDriver_QT.h @@ -4,43 +4,52 @@ * RageSoundDriver_QT.h * stepmania * + * Use multiple Sound Manager channels to output sound. + * * Created by Steve Checkoway on Mon Jun 23 2003. * Copyright (c) 2003 Steve Checkoway. All rights reserved. * */ -#include "global.h" + /* ugh, what a hack! QT includes Carbon/Carbon.h which - * has defs for a few things defined in RageUtil.h which - * is included in arch.cpp along w/ (eventually) this. - * How do I do this without using phony namespaces? - * --Steve - */ +* has defs for a few things defined in RageUtil.h which +* is included in arch.cpp along w/ (eventually) this. +* How do I do this without using phony namespaces? +* --Steve +*/ namespace QT { #include } - #include "RageSound.h" #include "RageSoundDriver.h" class RageSound_QT: public RageSoundDriver { private: - QT::ComponentInstance soundOutput; - float latency; + struct sound { + RageSound *snd; + bool stopping; + int flush_pos; + sound() { snd=NULL; stopping=false; flush_pos=0; } + }; + + vector sounds; + QT::ComponentInstance clock; + QT::ComponentInstance soundOutput; + QT::SndChannelPtr channel; + int last_pos; + float latency; protected: - virtual void StartMixing(RageSound *snd); - virtual void StopMixing(RageSound *snd); - virtual int GetPosition(const RageSound *snd) const; - virtual void Update (float delta); - virtual float GetPlayLatency() const; + virtual void StartMixing(RageSound *snd); + virtual void StopMixing(RageSound *snd); + virtual int GetPosition(const RageSound *snd) const; + virtual void Update (float delta); + virtual float GetPlayLatency() const; public: - RageSound_QT(); - virtual ~RageSound_QT(); - static void GetData(QT::SndChannel *chan, QT::SndCommand *cmd_passed); + RageSound_QT(); + virtual ~RageSound_QT(); + static void GetData(QT::SndChannel *chan, QT::SndCommand *cmd_passed); }; -bool canPlayMultiChannels(); - #endif /* RAGE_SOUND_QT */ - \ No newline at end of file diff --git a/stepmania/src/arch/Sound/RageSoundDriver_QT1.cpp b/stepmania/src/arch/Sound/RageSoundDriver_QT1.cpp new file mode 100644 index 0000000000..1b5df8872b --- /dev/null +++ b/stepmania/src/arch/Sound/RageSoundDriver_QT1.cpp @@ -0,0 +1,213 @@ +/* + * RageSoundDriver_QT.cpp + * stepmania + * + * Created by Steve Checkoway on Mon Jun 23 2003. + * Copyright (c) 2003 Steve Checkoway. All rights reserved. + * + */ + +#include "global.h" +#include "RageSoundDriver_QT1.h" +#include "RageLog.h" +#include "RageUtil.h" +#include "RageLog.h" +#include +#include +/* Ugh */ +using namespace QT; + +const unsigned channels = 2; +const unsigned samplesize = channels*16; +const unsigned samples = 512; +const unsigned freq = 44100; +const unsigned buffersize = samples*samplesize/8; + +/* Oh boy! dealing with memory at inturupt time. What fun! */ +#pragma options align=power +static volatile Uint32 fill_me = 0; +static UInt8 *buffer[2]; +static CmpSoundHeader header; + +RageSound_QT1::RageSound_QT1() { + SndCallBackUPP callback; + callback = NewSndCallBackUPP(GetData); + memset(&header, 0, sizeof(header)); + header.numChannels = channels; + header.sampleSize = samplesize / channels; + header.sampleRate = rate44khz; /* really 44.1kHz */ + header.numFrames = samples; + header.encode = cmpSH; + + buffer[0] = new Uint8[buffersize]; + buffer[1] = new Uint8[buffersize]; + memset(buffer[0], 0, buffersize); + memset(buffer[1], 0, buffersize); + + channel = new SndChannel; + channel->userInfo = reinterpret_cast(this); + channel->qLength = 2; + + soundOutput = OpenDefaultComponent(kSoundOutputDeviceType, NULL); + ASSERT(soundOutput != NULL); + + TimeRecord record; + SoundComponentGetInfo(soundOutput, NULL, siOutputLatency, &record); + latency = record.value.lo / record.scale; + latency += samples / freq; /* double buffer */ + + OSErr err = SndNewChannel(&channel, sampledSynth, initStereo, callback); + + if (err != noErr) { + delete channel; + channel = NULL; + RageException::ThrowNonfatal("Unable to create audio channel"); + } + + SndCommand cmd; + cmd.cmd = clockComponentCmd; + cmd.param1 = true; + cmd.param2 = 0; + err |= SndDoImmediate(channel, &cmd); + + cmd.cmd = getClockComponentCmd; + cmd.param1 = 0; + cmd.param2 = reinterpret_cast(&clock); + err |= SndDoImmediate(channel, &cmd); + last_pos = 0; + + cmd.cmd = callBackCmd; + cmd.param2 = 0; + err |= SndDoCommand(channel, &cmd, false); + + if (err != noErr) + RageException::ThrowNonfatal("Unable to create audio channel"); +} + +RageSound_QT1::~RageSound_QT1() { + if (channel) + SndDisposeChannel(channel, true); + SAFE_DELETE_ARRAY(buffer[0]); + SAFE_DELETE_ARRAY(buffer[1]); + if (soundOutput) + CloseComponent(soundOutput); +} + +void RageSound_QT1::GetData(SndChannel *chan, SndCommand *cmd_passed) { + while (!SOUNDMAN) + SDL_Delay(10); + LockMutex L(SOUNDMAN->lock); + static bool gettingData=false; + static int recursiveCalls = 0; + if (gettingData) { + LOG->Warn( "GetData() called recursively %D times.", ++recursiveCalls); + if (recursiveCalls >=10) + RageException::Throw("GetData() called recursively too many times."); + } else + recursiveCalls = 0; + gettingData = true; + static SoundMixBuffer mix; + RageSound_QT1 *P = reinterpret_cast(chan->userInfo); + + fill_me = cmd_passed->param2; + UInt32 play_me = !fill_me; + + if (!P->last_pos){ + TimeRecord tr; + ClockGetTime(P->clock, &tr); + UInt64 temp = tr.value.hi; + temp <<= 32; + temp |= tr.value.lo; + double d = static_cast(temp)/tr.scale*freq; + temp = static_cast(d); + P->last_pos = static_cast(temp % 0x00000000FFFFFFFFLL); + } else + P->last_pos += samples; + + /* Swap buffers */ + header.samplePtr = reinterpret_cast(buffer[play_me]); + SndCommand cmd; + cmd.cmd = bufferCmd; + cmd.param1 = 0; + cmd.param2 = reinterpret_cast(&header); + SndDoCommand(chan, &cmd, 0); + + /* Clear the fill buffer */ + memset(buffer[fill_me], 0, buffersize); + + for (unsigned i=0; isounds.size(); ++i) { + if (P->sounds[i]->stopping) + continue; + + unsigned got = P->sounds[i]->snd->GetPCM(reinterpret_cast(buffer[fill_me]), buffersize, P->last_pos); + mix.write(reinterpret_cast(buffer[fill_me]), got / 2); + if (got < buffersize) { + P->sounds[i]->stopping = true; + P->sounds[i]->flush_pos = P->last_pos + (got * 8 / samplesize); + } + } + + mix.read(reinterpret_cast(buffer[fill_me])); + + cmd.cmd = callBackCmd; + cmd.param2 = play_me; + SndDoCommand(chan, &cmd, 0); + gettingData=false; +} + +void RageSound_QT1::StartMixing(RageSound *snd) { + sound *s = new sound; + s->snd = snd; + + LockMutex L(SOUNDMAN->lock); + sounds.push_back(s); + LOG->Trace("There are %D sounds playing", sounds.size()); +} + +void RageSound_QT1::StopMixing(RageSound *snd) { + LockMutex L(SOUNDMAN->lock); + + /* Find the sound. */ + unsigned i; + for(i = 0; i < sounds.size(); ++i) + if(sounds[i]->snd == snd) break; + if(i == sounds.size()) + { + LOG->Trace("not stopping a sound because it's not playing"); + return; + } + + delete sounds[i]; + sounds.erase(sounds.begin()+i, sounds.begin()+i+1); + LOG->Trace("There are %D sounds playing", sounds.size()); +} + +void RageSound_QT1::Update(float delta) { +#pragma unused (delta) + LockMutex L(SOUNDMAN->lock); + + vectorsnds = sounds; + for (unsigned i = 0; i < snds.size(); ++i) { + if (!sounds[i]->stopping) + continue; + if (GetPosition(snds[i]->snd) < sounds[i]->flush_pos) + continue; + snds[i]->snd->StopPlaying(); + } +} + +int RageSound_QT1::GetPosition(const RageSound *snd) const { +#pragma unused (snd) + TimeRecord tr; + ClockGetTime(clock, &tr); + UInt64 temp = tr.value.hi; + temp <<= 32; + temp |= tr.value.lo; + double d = static_cast(temp)/tr.scale*freq; + temp = static_cast(d); + return static_cast(temp % 0x00000000FFFFFFFFLL); +} + +float RageSound_QT1::GetPlayLatency() const { + return latency; +} diff --git a/stepmania/src/arch/Sound/RageSoundDriver_QT1.h b/stepmania/src/arch/Sound/RageSoundDriver_QT1.h new file mode 100644 index 0000000000..0a4f8253db --- /dev/null +++ b/stepmania/src/arch/Sound/RageSoundDriver_QT1.h @@ -0,0 +1,55 @@ +#ifndef RAGE_SOUND_QT1 +#define RAGE_SOUND_QT1 +/* + * RageSoundDriver_QT1.h + * stepmania + * + * Use only a single Sound Manager channel to output sound. + * + * Created by Steve Checkoway on Mon Jun 23 2003. + * Copyright (c) 2003 Steve Checkoway. All rights reserved. + * + */ + +/* ugh, what a hack! QT includes Carbon/Carbon.h which +* has defs for a few things defined in RageUtil.h which +* is included in arch.cpp along w/ (eventually) this. +* How do I do this without using phony namespaces? +* --Steve +*/ +namespace QT { +#include +} +#include "RageSound.h" +#include "RageSoundDriver.h" + +class RageSound_QT1: public RageSoundDriver { +private: + struct sound { + RageSound *snd; + bool stopping; + int flush_pos; + sound() { snd=NULL; stopping=false; flush_pos=0; } + }; + + vector sounds; + QT::ComponentInstance clock; + QT::ComponentInstance soundOutput; + QT::SndChannelPtr channel; + int last_pos; + float latency; + +protected: + virtual void StartMixing(RageSound *snd); + virtual void StopMixing(RageSound *snd); + virtual int GetPosition(const RageSound *snd) const; + virtual void Update (float delta); + virtual float GetPlayLatency() const; + +public: + RageSound_QT1(); + virtual ~RageSound_QT1(); + static void GetData(QT::SndChannel *chan, QT::SndCommand *cmd_passed); +}; + +#endif /* RAGE_SOUND_QT1 */ diff --git a/stepmania/src/arch/arch.cpp b/stepmania/src/arch/arch.cpp index 3d6c0e84e8..27b894ea3c 100644 --- a/stepmania/src/arch/arch.cpp +++ b/stepmania/src/arch/arch.cpp @@ -76,18 +76,17 @@ RageSoundDriver *MakeRageSoundDriver(CString drivers) #ifdef RAGE_SOUND_QT if(!DriversToTry[i].CompareNoCase("QT")) ret = new RageSound_QT; #endif -/*#ifdef RAGE_SOUND_SDL - if(!DriversToTry[i].CompareNoCase("SDL")) ret = new RageSound_SDL; -#endif*/ - if(!DriversToTry[i].CompareNoCase("Null")) ret = new RageSound_Null; - if( !ret ) - LOG->Warn("Unknown sound driver name: %s", DriversToTry[i].c_str()); - } - catch(const RageException &e) { +#ifdef RAGE_SOUND_QT1 + if(!DriversToTry[i].CompareNoCase("QT1")) ret = new RageSound_QT1; +#endif + if(!DriversToTry[i].CompareNoCase("Null")) ret = new RageSound_Null; + if( !ret ) + LOG->Warn("Unknown sound driver name: %s", DriversToTry[i].c_str()); + } catch(const RageException &e) { LOG->Info("Couldn't load driver %s: %s", DriversToTry[i].c_str(), e.what()); } } - + if(ret) LOG->Info("Sound driver: %s", Driver.c_str()); diff --git a/stepmania/src/arch/arch_darwin.h b/stepmania/src/arch/arch_darwin.h index dcbb9d0a16..847abe5d11 100644 --- a/stepmania/src/arch/arch_darwin.h +++ b/stepmania/src/arch/arch_darwin.h @@ -10,7 +10,7 @@ * */ -//#include "Sound/RageSoundDriver_QT_old.h" +#include "Sound/RageSoundDriver_QT1.h" #include "Sound/RageSoundDriver_QT.h" #include "LoadingWindow/LoadingWindow_Cocoa.h"