From c000b91536da54d6ab3b181c82760ea66382a45e Mon Sep 17 00:00:00 2001 From: Steve Checkoway Date: Sun, 10 Aug 2003 00:43:18 +0000 Subject: [PATCH] Sound driver now works. I don't know if it is perfect or not, but GetPosition seems to return valid positions. --- .../src/arch/Sound/RageSoundDriver_QT.cpp | 317 +++++++++++++----- stepmania/src/arch/Sound/RageSoundDriver_QT.h | 2 +- 2 files changed, 233 insertions(+), 86 deletions(-) diff --git a/stepmania/src/arch/Sound/RageSoundDriver_QT.cpp b/stepmania/src/arch/Sound/RageSoundDriver_QT.cpp index 33409daced..635706f548 100644 --- a/stepmania/src/arch/Sound/RageSoundDriver_QT.cpp +++ b/stepmania/src/arch/Sound/RageSoundDriver_QT.cpp @@ -21,7 +21,7 @@ const unsigned numchannels = 2; const unsigned samplesize = 2 * numchannels; -const unsigned samples = 40960; +const unsigned samples = 2048; const long halfsamples = long(samples / 2); const long twicesamples = long(samples * 2); const unsigned freq = 44100; @@ -32,7 +32,7 @@ const unsigned initialSounds = 10; #define TEST_ERR(err, func) \ CHECKPOINT; \ if (__builtin_expect(err, noErr)) \ - RageException::Throw(#func " failed with error: %d", err) +RageException::Throw(#func " failed with error: %d at %s:%d", err, __FILE__, __LINE__) #else #define TEST_ERR(err, func) CHECKPOINT #endif @@ -40,22 +40,24 @@ if (__builtin_expect(err, noErr)) \ typedef struct soundInfo { RageSound *snd; - Movie movie; - Track track; + //Movie movie; + //Track track; long stopPos; - long lastPos; - unsigned totalMediaSamples; - unsigned firstLiveMediaSample; - SoundDescriptionHandle sndDescHdl; - - static soundInfo **MakeSoundInfoHdl(); - static void DisposeSoundInfoHdl(soundInfo **sHdl); - void Reset(); - void DisposeSampleReferences(Media media, unsigned endIndex = 0xFFFFFFFF); - void GetData(); + //long lastPos; + bool stopping; + //long totalMediaSamples; + //SoundDescriptionHandle sndDescHdl; + //short dataRefIndices[4]; + + soundInfo() { snd=NULL; stopPos=0; stopping=false; } + //static soundInfo **MakeSoundInfoHdl(); + //static void DisposeSoundInfoHdl(soundInfo **sHdl); + //void Reset(); + void DisposeSampleReferences(Media media, short index); + //void GetData(); } *soundInfoPtr, **soundInfoHdl; -soundInfoHdl soundInfo::MakeSoundInfoHdl() +/*soundInfoHdl soundInfo::MakeSoundInfoHdl() { soundInfoHdl sHdl = (soundInfoHdl)NewHandle(sizeof(soundInfo)); OSStatus err = MemError(); @@ -92,8 +94,7 @@ soundInfoHdl soundInfo::MakeSoundInfoHdl() err = MemError(); TEST_ERR(err, HUnlock); - s->totalMediaSamples = 0; - s->firstLiveMediaSample = 0; + bzero(s->dataRefIndices, 8); s->Reset(); HUnlock(Handle(sHdl)); err = MemError(); @@ -112,61 +113,57 @@ void soundInfo::DisposeSoundInfoHdl(soundInfoHdl sHdl) DisposeMovie(s->movie); HUnlock(Handle(sHdl)); DisposeHandle(Handle(sHdl)); -} +}*/ /* Make sure that the Handle to this data is locked before calling this method. */ -void soundInfo::Reset() +/*void soundInfo::Reset() { Media media = GetTrackMedia(track); if (media) { - this->DisposeSampleReferences(media); // All of them + this->DisposeSampleReferences(media, 0); + this->DisposeSampleReferences(media, 1); + this->DisposeSampleReferences(media, 2); DisposeTrackMedia(media); } - totalMediaSamples = 0; - firstLiveMediaSample = 0; + //dataRefIndices[3] = 0; stopPos = 0; lastPos = 0; - snd = NULL; + //snd = NULL; GoToBeginningOfMovie(movie); -} +}*/ -void soundInfo::DisposeSampleReferences(Media media, unsigned endIndex) +static short dataRefIndices[4]; +static SoundDescriptionHandle sndDescHdl; + +//void soundInfo::DisposeSampleReferences(Media media, short index) +void DisposeSampleReferences(Media media, short index) { LockMutex L(SOUNDMAN->lock); - if (!firstLiveMediaSample) - return; - if (endIndex < firstLiveMediaSample) - { - LOG->Warn("Couldn't dispose of data to %d because it has already been " - "disposed.", endIndex); - return; - } - ASSERT(totalMediaSamples); - endIndex = min(endIndex, totalMediaSamples); + ASSERT(index <= 2 && index >= 0); - for (; firstLiveMediaSample <= endIndex; ++firstLiveMediaSample) - { - Handle dataRef; - OSType dataRefType; - long dataRefAttributes; - OSErr err = GetMediaDataRef(media, firstLiveMediaSample, &dataRef, - &dataRefType, &dataRefAttributes); - TEST_ERR(err, GetMediaDataRef); - ASSERT(dataRefType == HandleDataHandlerSubType); - ASSERT(!(dataRefAttributes & dataRefWasNotResolved)); - HLock(dataRef); - Handle sndHdl; - memcpy(&sndHdl, *dataRef, sizeof(Handle)); - DisposeHandle(sndHdl); - HUnlock(dataRef); - DisposeHandle(dataRef); - } + if (!dataRefIndices[index]) + return; + + Handle dataRef; + OSType dataRefType; + long dataRefAttributes; + OSErr err = GetMediaDataRef(media, dataRefIndices[index], &dataRef, &dataRefType, &dataRefAttributes); + TEST_ERR(err, GetMediaDataRef); + ASSERT(dataRefType == HandleDataHandlerSubType); + ASSERT(!(dataRefAttributes & dataRefWasNotResolved)); + HLock(dataRef); + Handle sndHdl; + memcpy(&sndHdl, *dataRef, sizeof(Handle)); + DisposeHandle(sndHdl); + HUnlock(dataRef); + DisposeHandle(dataRef); + dataRefIndices[index] = 0; } /* Make sure that the Handle to this data is locked before calling this method. */ -inline void soundInfo::GetData() +/*inline void soundInfo::GetData() { CHECKPOINT; char buffer[buffersize]; @@ -182,45 +179,52 @@ inline void soundInfo::GetData() Handle sndHdl; PtrToHand(buffer, &sndHdl, got); + OSErr err = MemError(); + TEST_ERR(err, PtrToHand); Handle dataRef; PtrToHand(&sndHdl, &dataRef, sizeof(Handle)); + err = MemError(); + TEST_ERR(err, PtrToHand); Media media = GetTrackMedia(track); - OSErr err; + bool insert; if (media) { short index; err = AddMediaDataRef(media, &index, dataRef, HandleDataHandlerSubType); TEST_ERR(err, AddMediaDataRef); - totalMediaSamples++; - ASSERT(totalMediaSamples == unsigned(index)); + ASSERT(index); + dataRefIndices[dataRefIndices[3] % 3] = index; + insert = false; } else { media = NewTrackMedia(track, SoundMediaType, freq, dataRef, HandleDataHandlerSubType); - err = GetMoviesError(); + OSErr err = GetMoviesError(); TEST_ERR(err, NewTrackMedia); - firstLiveMediaSample = 1; - totalMediaSamples = 1; + dataRefIndices[0] = 1; + insert = true; } CHECKPOINT; BeginMediaEdits(media); AddMediaSample(media, sndHdl, 0, got, 1, SampleDescriptionHandle(sndDescHdl), samples, 0, NULL); EndMediaEdits(media); CHECKPOINT; - InsertMediaIntoTrack(track, -1, lastPos - samples, samples, 0x00010000); + if (insert) + InsertMediaIntoTrack(track, -1, lastPos - samples, got / samplesize, 0x00010000); CHECKPOINT; - if (totalMediaSamples > 3) + if (++dataRefIndices[3] > 3) { - SetMovieActiveSegment(movie, (totalMediaSamples - 2) * samples, twicesamples); - DisposeSampleReferences(media, totalMediaSamples - 3); //Remove one sample + SetMovieActiveSegment(movie, (dataRefIndices[3] - 2) * samples, twicesamples); + DisposeSampleReferences(media, dataRefIndices[3] % 3); } CHECKPOINT; } -static void CallBack(QTCallBack cb, long refCon) { +static void CallBack(QTCallBack cb, long refCon) +{ LockMutex L(SOUNDMAN->lock); CHECKPOINT; soundInfoHdl sHdl = soundInfoHdl(refCon); @@ -241,29 +245,142 @@ static void CallBack(QTCallBack cb, long refCon) { CallMeWhen(cb, CallBack, long(sHdl), triggerTimeFwd, timeToCall, freq); HUnlock(Handle(sHdl)); -} +}*/ -static vector playingSounds; -static queue freeSounds; +//static vector playingSounds; +//static queue freeSounds; +static vector sounds; +static long lastPos; +static Movie movie; +static Track track; + +static void CallBack(QTCallBack cb, long refCon) +{ +#pragma unused(refCon) + while (!SOUNDMAN) + SDL_Delay(10); + LockMutex L(SOUNDMAN->lock); + static SoundMixBuffer mix; + char buffer[buffersize]; + + bzero(buffer, buffersize); + for (unsigned i=0; istopping) + continue; + + unsigned got = sounds[i]->snd->GetPCM(buffer, buffersize, lastPos); + + mix.write((SInt16 *)buffer, got / 2); + if (got < buffersize) + { + sounds[i]->stopping = true; + sounds[i]->stopPos = lastPos + got / samplesize; + } + } + lastPos += samples; + + mix.read((SInt16 *)buffer); + Handle sndHdl; + PtrToHand(buffer, &sndHdl, buffersize); + OSErr err = MemError(); + TEST_ERR(err, PtrToHand); + Handle dataRef; + PtrToHand(&sndHdl, &dataRef, sizeof(Handle)); + err = MemError(); + TEST_ERR(err, PtrToHand); + Media media = GetTrackMedia(track); + bool insert; + + if (media) + { + short index; + err = AddMediaDataRef(media, &index, dataRef, HandleDataHandlerSubType); + TEST_ERR(err, AddMediaDataRef); + ASSERT(index); + dataRefIndices[dataRefIndices[3] % 3] = index; + insert = false; + } + else + { + media = NewTrackMedia(track, SoundMediaType, freq, dataRef, HandleDataHandlerSubType); + OSErr err = GetMoviesError(); + TEST_ERR(err, NewTrackMedia); + dataRefIndices[0] = 1; + insert = true; + } + CHECKPOINT; + BeginMediaEdits(media); + AddMediaSample(media, sndHdl, 0, samples, 1, SampleDescriptionHandle(sndDescHdl), samples, 0, NULL); + EndMediaEdits(media); + CHECKPOINT; + if (insert) + InsertMediaIntoTrack(track, -1, lastPos - samples, samples, 0x00010000); + CHECKPOINT; + + if (++dataRefIndices[3] > 3) + { + SetMovieActiveSegment(movie, (dataRefIndices[3] - 2) * samples, twicesamples); + DisposeSampleReferences(media, dataRefIndices[3] % 3); + } + CHECKPOINT; + + long timeToCall; + if (!cb) + { + StartMovie(movie); + cb = NewCallBack(GetMovieTimeBase(movie), callBackAtTime); + timeToCall = halfsamples; + } + else + timeToCall = lastPos - halfsamples; + CallMeWhen(cb, CallBack, 0, triggerTimeFwd, timeToCall, freq); +} RageSound_QT::RageSound_QT() { -#if 1 - RageException::ThrowNonfatal("Class not finished!"); -#endif - - playingSounds.reserve(initialSounds); + /*playingSounds.reserve(initialSounds); for (unsigned i=0; idescSize = sizeof(SoundDescription); + sndDescPtr->dataFormat = k16BitBigEndianFormat; + sndDescPtr->numChannels = numchannels; + sndDescPtr->sampleSize = samplesize * 8 / numchannels; + sndDescPtr->sampleRate = freq << 16; + HUnlock(Handle(sndDescHdl)); + err = MemError(); + TEST_ERR(err, HUnlock); + + /* Start the Movie */ + CallBack(NULL, 0); } RageSound_QT::~RageSound_QT() { LockMutex L(SOUNDMAN->lock); - while (!playingSounds.empty()) + /*while (!playingSounds.empty()) { soundInfoHdl &sHdl = playingSounds.back(); soundInfo::DisposeSoundInfoHdl(sHdl); @@ -274,6 +391,12 @@ RageSound_QT::~RageSound_QT() soundInfoHdl &sHdl = freeSounds.front(); soundInfo::DisposeSoundInfoHdl(sHdl); freeSounds.pop(); + }*/ + while (!sounds.empty()) + { + soundInfoPtr s = sounds.back(); + s->snd->StopPlaying(); + sounds.pop_back(); } } @@ -282,7 +405,7 @@ void RageSound_QT::StartMixing(RageSound *snd) LockMutex L(SOUNDMAN->lock); CHECKPOINT; LOG->Trace("StartMixing()"); - soundInfoHdl sHdl; + /*soundInfoHdl sHdl; if (freeSounds.empty()) sHdl = soundInfo::MakeSoundInfoHdl(); else @@ -292,7 +415,10 @@ void RageSound_QT::StartMixing(RageSound *snd) } (*sHdl)->snd = snd; playingSounds.push_back(sHdl); - CallBack(NULL, long(sHdl)); + CallBack(NULL, long(sHdl));*/ + soundInfoPtr s = new soundInfo; + s->snd = snd; + sounds.push_back(s); } void RageSound_QT::StopMixing(RageSound *snd) @@ -301,7 +427,7 @@ void RageSound_QT::StopMixing(RageSound *snd) CHECKPOINT; LOG->Trace("StopMixing"); - for (vector::iterator iter=playingSounds.begin(); iter<=playingSounds.end(); ++iter) + /*for (vector::iterator iter=playingSounds.begin(); itersnd != snd) + continue; + sounds.erase(sounds.begin()+i); + return; } LOG->Warn("A sound could not be stopped because it was not being played."); @@ -327,21 +460,28 @@ void RageSound_QT::Update(float delta) #pragma unused (delta) LockMutex L(SOUNDMAN->lock); - vector snds = playingSounds; - for (vector::iterator iter=snds.begin(); iter<=snds.end(); ++iter) + /*vector snds = playingSounds; + for (vector::iterator iter=snds.begin(); itermovie)) (*sHdl)->snd->StopPlaying(); else HUnlock(Handle(sHdl)); CHECKPOINT; + }*/ + vector snds = sounds; + for (unsigned i=0; istopping) + continue; + if (GetPosition(snds[i]->snd) < snds[i]->stopPos) + continue; + snds[i]->snd->StopPlaying(); } } @@ -349,12 +489,19 @@ int RageSound_QT::GetPosition(const RageSound *snd) const { LockMutex L(SOUNDMAN->lock); - for (vector::iterator iter=playingSounds.begin(); iter<=playingSounds.end(); ++iter) + /*for (vector::iterator iter=playingSounds.begin(); itersnd == snd) return GetMovieTime((*sHdl)->movie, NULL); } - RageException::Throw("Can't get the position of a sound that isn't playing"); + RageException::Throw("Can't get the position of a sound that isn't playing");*/ + return GetMovieTime(movie, NULL); +} + +float RageSound_QT::GetPlayLatency() const +{ + return float(halfsamples / 2) / freq; + //return 0; } diff --git a/stepmania/src/arch/Sound/RageSoundDriver_QT.h b/stepmania/src/arch/Sound/RageSoundDriver_QT.h index da502e473d..9dda801468 100644 --- a/stepmania/src/arch/Sound/RageSoundDriver_QT.h +++ b/stepmania/src/arch/Sound/RageSoundDriver_QT.h @@ -19,7 +19,7 @@ protected: virtual void StopMixing(RageSound *snd); virtual int GetPosition(const RageSound *snd) const; virtual void Update (float delta); - virtual float GetPlayLatency() const { return 0; } + virtual float GetPlayLatency() const; public: RageSound_QT();