Sound driver now works. I don't know if it is perfect or not, but GetPosition seems to return valid positions.

This commit is contained in:
Steve Checkoway
2003-08-10 00:43:18 +00:00
parent b5d0545f42
commit c000b91536
2 changed files with 233 additions and 86 deletions
+231 -84
View File
@@ -21,7 +21,7 @@
const unsigned numchannels = 2; const unsigned numchannels = 2;
const unsigned samplesize = 2 * numchannels; const unsigned samplesize = 2 * numchannels;
const unsigned samples = 40960; const unsigned samples = 2048;
const long halfsamples = long(samples / 2); const long halfsamples = long(samples / 2);
const long twicesamples = long(samples * 2); const long twicesamples = long(samples * 2);
const unsigned freq = 44100; const unsigned freq = 44100;
@@ -32,7 +32,7 @@ const unsigned initialSounds = 10;
#define TEST_ERR(err, func) \ #define TEST_ERR(err, func) \
CHECKPOINT; \ CHECKPOINT; \
if (__builtin_expect(err, noErr)) \ 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 #else
#define TEST_ERR(err, func) CHECKPOINT #define TEST_ERR(err, func) CHECKPOINT
#endif #endif
@@ -40,22 +40,24 @@ if (__builtin_expect(err, noErr)) \
typedef struct soundInfo typedef struct soundInfo
{ {
RageSound *snd; RageSound *snd;
Movie movie; //Movie movie;
Track track; //Track track;
long stopPos; long stopPos;
long lastPos; //long lastPos;
unsigned totalMediaSamples; bool stopping;
unsigned firstLiveMediaSample; //long totalMediaSamples;
SoundDescriptionHandle sndDescHdl; //SoundDescriptionHandle sndDescHdl;
//short dataRefIndices[4];
static soundInfo **MakeSoundInfoHdl(); soundInfo() { snd=NULL; stopPos=0; stopping=false; }
static void DisposeSoundInfoHdl(soundInfo **sHdl); //static soundInfo **MakeSoundInfoHdl();
void Reset(); //static void DisposeSoundInfoHdl(soundInfo **sHdl);
void DisposeSampleReferences(Media media, unsigned endIndex = 0xFFFFFFFF); //void Reset();
void GetData(); void DisposeSampleReferences(Media media, short index);
//void GetData();
} *soundInfoPtr, **soundInfoHdl; } *soundInfoPtr, **soundInfoHdl;
soundInfoHdl soundInfo::MakeSoundInfoHdl() /*soundInfoHdl soundInfo::MakeSoundInfoHdl()
{ {
soundInfoHdl sHdl = (soundInfoHdl)NewHandle(sizeof(soundInfo)); soundInfoHdl sHdl = (soundInfoHdl)NewHandle(sizeof(soundInfo));
OSStatus err = MemError(); OSStatus err = MemError();
@@ -92,8 +94,7 @@ soundInfoHdl soundInfo::MakeSoundInfoHdl()
err = MemError(); err = MemError();
TEST_ERR(err, HUnlock); TEST_ERR(err, HUnlock);
s->totalMediaSamples = 0; bzero(s->dataRefIndices, 8);
s->firstLiveMediaSample = 0;
s->Reset(); s->Reset();
HUnlock(Handle(sHdl)); HUnlock(Handle(sHdl));
err = MemError(); err = MemError();
@@ -112,61 +113,57 @@ void soundInfo::DisposeSoundInfoHdl(soundInfoHdl sHdl)
DisposeMovie(s->movie); DisposeMovie(s->movie);
HUnlock(Handle(sHdl)); HUnlock(Handle(sHdl));
DisposeHandle(Handle(sHdl)); DisposeHandle(Handle(sHdl));
} }*/
/* Make sure that the Handle to this data is locked before calling this method. */ /* Make sure that the Handle to this data is locked before calling this method. */
void soundInfo::Reset() /*void soundInfo::Reset()
{ {
Media media = GetTrackMedia(track); Media media = GetTrackMedia(track);
if (media) if (media)
{ {
this->DisposeSampleReferences(media); // All of them this->DisposeSampleReferences(media, 0);
this->DisposeSampleReferences(media, 1);
this->DisposeSampleReferences(media, 2);
DisposeTrackMedia(media); DisposeTrackMedia(media);
} }
totalMediaSamples = 0; //dataRefIndices[3] = 0;
firstLiveMediaSample = 0;
stopPos = 0; stopPos = 0;
lastPos = 0; lastPos = 0;
snd = NULL; //snd = NULL;
GoToBeginningOfMovie(movie); 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); LockMutex L(SOUNDMAN->lock);
if (!firstLiveMediaSample) ASSERT(index <= 2 && index >= 0);
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);
for (; firstLiveMediaSample <= endIndex; ++firstLiveMediaSample) if (!dataRefIndices[index])
{ return;
Handle dataRef;
OSType dataRefType; Handle dataRef;
long dataRefAttributes; OSType dataRefType;
OSErr err = GetMediaDataRef(media, firstLiveMediaSample, &dataRef, long dataRefAttributes;
&dataRefType, &dataRefAttributes); OSErr err = GetMediaDataRef(media, dataRefIndices[index], &dataRef, &dataRefType, &dataRefAttributes);
TEST_ERR(err, GetMediaDataRef); TEST_ERR(err, GetMediaDataRef);
ASSERT(dataRefType == HandleDataHandlerSubType); ASSERT(dataRefType == HandleDataHandlerSubType);
ASSERT(!(dataRefAttributes & dataRefWasNotResolved)); ASSERT(!(dataRefAttributes & dataRefWasNotResolved));
HLock(dataRef); HLock(dataRef);
Handle sndHdl; Handle sndHdl;
memcpy(&sndHdl, *dataRef, sizeof(Handle)); memcpy(&sndHdl, *dataRef, sizeof(Handle));
DisposeHandle(sndHdl); DisposeHandle(sndHdl);
HUnlock(dataRef); HUnlock(dataRef);
DisposeHandle(dataRef); DisposeHandle(dataRef);
} dataRefIndices[index] = 0;
} }
/* Make sure that the Handle to this data is locked before calling this method. */ /* Make sure that the Handle to this data is locked before calling this method. */
inline void soundInfo::GetData() /*inline void soundInfo::GetData()
{ {
CHECKPOINT; CHECKPOINT;
char buffer[buffersize]; char buffer[buffersize];
@@ -182,45 +179,52 @@ inline void soundInfo::GetData()
Handle sndHdl; Handle sndHdl;
PtrToHand(buffer, &sndHdl, got); PtrToHand(buffer, &sndHdl, got);
OSErr err = MemError();
TEST_ERR(err, PtrToHand);
Handle dataRef; Handle dataRef;
PtrToHand(&sndHdl, &dataRef, sizeof(Handle)); PtrToHand(&sndHdl, &dataRef, sizeof(Handle));
err = MemError();
TEST_ERR(err, PtrToHand);
Media media = GetTrackMedia(track); Media media = GetTrackMedia(track);
OSErr err; bool insert;
if (media) if (media)
{ {
short index; short index;
err = AddMediaDataRef(media, &index, dataRef, HandleDataHandlerSubType); err = AddMediaDataRef(media, &index, dataRef, HandleDataHandlerSubType);
TEST_ERR(err, AddMediaDataRef); TEST_ERR(err, AddMediaDataRef);
totalMediaSamples++; ASSERT(index);
ASSERT(totalMediaSamples == unsigned(index)); dataRefIndices[dataRefIndices[3] % 3] = index;
insert = false;
} }
else else
{ {
media = NewTrackMedia(track, SoundMediaType, freq, dataRef, HandleDataHandlerSubType); media = NewTrackMedia(track, SoundMediaType, freq, dataRef, HandleDataHandlerSubType);
err = GetMoviesError(); OSErr err = GetMoviesError();
TEST_ERR(err, NewTrackMedia); TEST_ERR(err, NewTrackMedia);
firstLiveMediaSample = 1; dataRefIndices[0] = 1;
totalMediaSamples = 1; insert = true;
} }
CHECKPOINT; CHECKPOINT;
BeginMediaEdits(media); BeginMediaEdits(media);
AddMediaSample(media, sndHdl, 0, got, 1, SampleDescriptionHandle(sndDescHdl), samples, 0, NULL); AddMediaSample(media, sndHdl, 0, got, 1, SampleDescriptionHandle(sndDescHdl), samples, 0, NULL);
EndMediaEdits(media); EndMediaEdits(media);
CHECKPOINT; CHECKPOINT;
InsertMediaIntoTrack(track, -1, lastPos - samples, samples, 0x00010000); if (insert)
InsertMediaIntoTrack(track, -1, lastPos - samples, got / samplesize, 0x00010000);
CHECKPOINT; CHECKPOINT;
if (totalMediaSamples > 3) if (++dataRefIndices[3] > 3)
{ {
SetMovieActiveSegment(movie, (totalMediaSamples - 2) * samples, twicesamples); SetMovieActiveSegment(movie, (dataRefIndices[3] - 2) * samples, twicesamples);
DisposeSampleReferences(media, totalMediaSamples - 3); //Remove one sample DisposeSampleReferences(media, dataRefIndices[3] % 3);
} }
CHECKPOINT; CHECKPOINT;
} }
static void CallBack(QTCallBack cb, long refCon) { static void CallBack(QTCallBack cb, long refCon)
{
LockMutex L(SOUNDMAN->lock); LockMutex L(SOUNDMAN->lock);
CHECKPOINT; CHECKPOINT;
soundInfoHdl sHdl = soundInfoHdl(refCon); soundInfoHdl sHdl = soundInfoHdl(refCon);
@@ -241,29 +245,142 @@ static void CallBack(QTCallBack cb, long refCon) {
CallMeWhen(cb, CallBack, long(sHdl), triggerTimeFwd, timeToCall, freq); CallMeWhen(cb, CallBack, long(sHdl), triggerTimeFwd, timeToCall, freq);
HUnlock(Handle(sHdl)); HUnlock(Handle(sHdl));
} }*/
static vector<soundInfoHdl> playingSounds; //static vector<soundInfoHdl> playingSounds;
static queue<soundInfoHdl> freeSounds; //static queue<soundInfoHdl> freeSounds;
static vector<soundInfoPtr> 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; i<sounds.size(); ++i)
{
if (sounds[i]->stopping)
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() RageSound_QT::RageSound_QT()
{ {
#if 1 /*playingSounds.reserve(initialSounds);
RageException::ThrowNonfatal("Class not finished!");
#endif
playingSounds.reserve(initialSounds);
for (unsigned i=0; i<initialSounds; ++i) for (unsigned i=0; i<initialSounds; ++i)
{ {
soundInfoHdl sHdl = soundInfo::MakeSoundInfoHdl(); soundInfoHdl sHdl = soundInfo::MakeSoundInfoHdl();
freeSounds.push(sHdl); freeSounds.push(sHdl);
} }*/
lastPos = 0;
bzero(dataRefIndices, 8);
movie = NewMovie(newMovieActive);
OSErr err = GetMoviesError();
TEST_ERR(err, NewMovie);
SetMovieTimeScale(movie, freq);
err = GetMoviesError();
TEST_ERR(err, SetMovieTimeScale);
track = NewMovieTrack(movie, 0, 0, kFullVolume);
err = GetMoviesError();
TEST_ERR(err, NewMovieTrack);
HLock(Handle(sndDescHdl));
err = MemError();
TEST_ERR(err, HLock);
SoundDescriptionPtr sndDescPtr = *sndDescHdl;
sndDescPtr->descSize = 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() RageSound_QT::~RageSound_QT()
{ {
LockMutex L(SOUNDMAN->lock); LockMutex L(SOUNDMAN->lock);
while (!playingSounds.empty()) /*while (!playingSounds.empty())
{ {
soundInfoHdl &sHdl = playingSounds.back(); soundInfoHdl &sHdl = playingSounds.back();
soundInfo::DisposeSoundInfoHdl(sHdl); soundInfo::DisposeSoundInfoHdl(sHdl);
@@ -274,6 +391,12 @@ RageSound_QT::~RageSound_QT()
soundInfoHdl &sHdl = freeSounds.front(); soundInfoHdl &sHdl = freeSounds.front();
soundInfo::DisposeSoundInfoHdl(sHdl); soundInfo::DisposeSoundInfoHdl(sHdl);
freeSounds.pop(); 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); LockMutex L(SOUNDMAN->lock);
CHECKPOINT; CHECKPOINT;
LOG->Trace("StartMixing()"); LOG->Trace("StartMixing()");
soundInfoHdl sHdl; /*soundInfoHdl sHdl;
if (freeSounds.empty()) if (freeSounds.empty())
sHdl = soundInfo::MakeSoundInfoHdl(); sHdl = soundInfo::MakeSoundInfoHdl();
else else
@@ -292,7 +415,10 @@ void RageSound_QT::StartMixing(RageSound *snd)
} }
(*sHdl)->snd = snd; (*sHdl)->snd = snd;
playingSounds.push_back(sHdl); 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) void RageSound_QT::StopMixing(RageSound *snd)
@@ -301,7 +427,7 @@ void RageSound_QT::StopMixing(RageSound *snd)
CHECKPOINT; CHECKPOINT;
LOG->Trace("StopMixing"); LOG->Trace("StopMixing");
for (vector<soundInfoHdl>::iterator iter=playingSounds.begin(); iter<=playingSounds.end(); ++iter) /*for (vector<soundInfoHdl>::iterator iter=playingSounds.begin(); iter<playingSounds.end(); ++iter)
{ {
soundInfoHdl sHdl = *iter; soundInfoHdl sHdl = *iter;
@@ -317,6 +443,13 @@ void RageSound_QT::StopMixing(RageSound *snd)
freeSounds.push(sHdl); freeSounds.push(sHdl);
HUnlock(Handle(sHdl)); HUnlock(Handle(sHdl));
return; return;
}*/
for (unsigned i=0; i<sounds.size(); ++i)
{
if (sounds[i]->snd != snd)
continue;
sounds.erase(sounds.begin()+i);
return;
} }
LOG->Warn("A sound could not be stopped because it was not being played."); 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) #pragma unused (delta)
LockMutex L(SOUNDMAN->lock); LockMutex L(SOUNDMAN->lock);
vector<soundInfoHdl> snds = playingSounds; /*vector<soundInfoHdl> snds = playingSounds;
for (vector<soundInfoHdl>::iterator iter=snds.begin(); iter<=snds.end(); ++iter) for (vector<soundInfoHdl>::iterator iter=snds.begin(); iter<snds.end(); ++iter)
{ {
soundInfoHdl sHdl = *iter; soundInfoHdl sHdl = *iter;
OSErr err = GetMoviesError();
TEST_ERR(err, GetMoviesError);
HLock(Handle(sHdl)); HLock(Handle(sHdl));
err = MemError(); OSErr err = MemError();
TEST_ERR(err, MemError); TEST_ERR(err, HLock);
if (IsMovieDone((*sHdl)->movie)) if (IsMovieDone((*sHdl)->movie))
(*sHdl)->snd->StopPlaying(); (*sHdl)->snd->StopPlaying();
else else
HUnlock(Handle(sHdl)); HUnlock(Handle(sHdl));
CHECKPOINT; CHECKPOINT;
}*/
vector<soundInfoPtr> snds = sounds;
for (unsigned i=0; i<snds.size(); ++i)
{
if (!snds[i]->stopping)
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); LockMutex L(SOUNDMAN->lock);
for (vector<soundInfoHdl>::iterator iter=playingSounds.begin(); iter<=playingSounds.end(); ++iter) /*for (vector<soundInfoHdl>::iterator iter=playingSounds.begin(); iter<playingSounds.end(); ++iter)
{ {
soundInfoHdl sHdl = *iter; soundInfoHdl sHdl = *iter;
if ((*sHdl)->snd == snd) if ((*sHdl)->snd == snd)
return GetMovieTime((*sHdl)->movie, NULL); 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;
} }
@@ -19,7 +19,7 @@ protected:
virtual void StopMixing(RageSound *snd); virtual void StopMixing(RageSound *snd);
virtual int GetPosition(const RageSound *snd) const; virtual int GetPosition(const RageSound *snd) const;
virtual void Update (float delta); virtual void Update (float delta);
virtual float GetPlayLatency() const { return 0; } virtual float GetPlayLatency() const;
public: public:
RageSound_QT(); RageSound_QT();