From 13fee58c651182d7d4a441c64646658613e88fd9 Mon Sep 17 00:00:00 2001 From: Glenn Maynard Date: Fri, 20 Dec 2002 01:45:41 +0000 Subject: [PATCH] better length handling --- stepmania/src/RageSound.cpp | 52 +++++++++++++++++++++++++------------ stepmania/src/RageSound.h | 32 +++++++++++++---------- 2 files changed, 55 insertions(+), 29 deletions(-) diff --git a/stepmania/src/RageSound.cpp b/stepmania/src/RageSound.cpp index e9f3f4ea73..d76bb7a222 100644 --- a/stepmania/src/RageSound.cpp +++ b/stepmania/src/RageSound.cpp @@ -222,8 +222,8 @@ void RageSound::SetLengthSeconds(float secs) m_LengthSeconds = secs; } -/* Start playing from m_StartSeconds. TODO: a way to start playing - * from the current pos (unpause) */ +/* Start playing from the current position. If the sound is already + * playing, Stop is called. */ void RageSound::Play() { LockMutex L(SOUNDMAN->lock); @@ -231,8 +231,6 @@ void RageSound::Play() if(playing) Stop(); playing = true; - SetPositionSeconds(m_StartSeconds); - // Tell the sound manager to start mixing us SOUNDMAN->StartMixing(this); } @@ -316,21 +314,40 @@ int RageSound::GetPCM(char *buffer, int size, int sampleno) while(size) { int got; + int MaxBytes; + if(m_LengthSeconds != -1) + { + /* We have a length; only read up to the end. MaxPosition is the + * sample position of the end. */ + int MaxPosition = int((m_StartSeconds + m_LengthSeconds) * samplerate); + + /* Number of bytes until MaxPosition. */ + MaxBytes = (MaxPosition - position) * samplesize; + + /* If it's negative, we're past the end, so cap it at 0. */ + MaxBytes = max(0, MaxBytes); + + /* Don't read more than size. */ + MaxBytes = min(MaxBytes, size); + } + else + MaxBytes = size; + if(position < 0) { /* We havn't *really* started playing yet, so just feed silence. How - * many more bytes of silence do we need? */ + * many more bytes of silence do we need? */ got = -position * samplesize; - got = min(got, size); + got = min(got, MaxBytes); memset(buffer, 0, got); } else if(big) { /* Feed data out of our streaming buffer. */ ASSERT(stream.Sample); - got = min(int(stream.buf.size()), size); + got = min(int(stream.buf.size()), MaxBytes); stream.buf.read(buffer, got); } else { /* Feed data out of our full buffer. */ int byte_pos = position * samplesize; - got = min(int(full_buf.size())-byte_pos, size); + got = min(int(full_buf.size())-byte_pos, MaxBytes); got = max(got, 0); if(got) memcpy(buffer, full_buf.data()+byte_pos, got); @@ -354,14 +371,22 @@ int RageSound::GetPCM(char *buffer, int size, int sampleno) /* If we've passed the stop point (m_StartSeconds+m_LengthSeconds), pretend * we've hit EOF. */ if(m_LengthSeconds != -1 && - float(position)/samplerate > m_StartSeconds+m_LengthSeconds) + float(position)/samplerate >= m_StartSeconds+m_LengthSeconds) HitEOF = true; if(!HitEOF) continue; + if(Loop && m_LengthSeconds == 0) + { + /* Oops. Looping with seconds == 0 doesn't make much sense. + * It might happen if we're given an empty sound file as input, + * though. Let's just stop. */ + break; + } + /* We're at EOF. If we're not looping, just stop. */ - if(Loop) + if(Loop && m_LengthSeconds != 0) { /* Rewind and start over. */ SetPositionSeconds(m_StartSeconds); @@ -443,14 +468,9 @@ void RageSound::Stop() /* Tell the sound manager to stop mixing this sound. */ SOUNDMAN->StopMixing(this); - if(big) { - ASSERT(stream.Sample); - Sound_Rewind(stream.Sample); - stream.buf.clear(); - } + SetPositionSeconds(m_StartSeconds); playing = false; - position = 0; for(int i = 0; i < 4; ++i) pos_map[i].clear(); } diff --git a/stepmania/src/RageSound.h b/stepmania/src/RageSound.h index c3cac8be24..51a8e17091 100644 --- a/stepmania/src/RageSound.h +++ b/stepmania/src/RageSound.h @@ -82,6 +82,22 @@ public: ~RageSound(); RageSound(const RageSound &cpy); + + /* Called only by the sound drivers: */ + /* This function should return the number of bytes actually put into buffer. + * If less than size is returned, it signals the stream to stop; once it's + * flushed, SoundStopped will be called. Until then, SOUNDMAN->GetPosition + * can still be called (the sound is still playing). */ + int GetPCM(char *buffer, int size, int sampleno); + + /* Called by the sound driver when a sound has actually finished stopping + * normally. Not called when Stop() is called to stop the sound prematurely. */ + void SoundStopped(); + + void Update(float delta); + + /* User API from here on: */ + /* If cache is true, we'll preload the entire file into memory if it's * small enough. False is only generally used when we're going to do * operations on a file but not actually play it (eg. to find out @@ -91,8 +107,11 @@ public: void LoadAndPlayIfNotAlready( CString sSoundFilePath ); void Unload(); + /* If enabled, then the sound will automatically stop when it reaches + * the end; otherwise it'll feed silence until Stop() is called. */ void SetAutoStop(bool yes=true) { AutoStop=yes; } bool GetAutoStop() const { return AutoStop; } + void SetStartSeconds(float secs = 0); /* default = beginning */ void SetLengthSeconds(float secs = -1); /* default = no length limit */ void Play(); @@ -111,19 +130,6 @@ public: /* Query only: */ bool IsStreaming() const { return big; } - - /* Called only by the sound drivers: */ - /* This function should return the number of bytes actually put into buffer. - * If less than size is returned, it signals the stream to stop; once it's - * flushed, SoundStopped will be called. Until then, SOUNDMAN->GetPosition - * can still be called (the sound is still playing). */ - int GetPCM(char *buffer, int size, int sampleno); - - /* Called by the sound driver when a sound has actually finished stopping - * normally. Not called when Stop() is called to stop the sound prematurely. */ - void SoundStopped(); - - void Update(float delta); }; #endif