diff --git a/stepmania/src/RageSound.cpp b/stepmania/src/RageSound.cpp index 36b585df4a..b95eb9914c 100644 --- a/stepmania/src/RageSound.cpp +++ b/stepmania/src/RageSound.cpp @@ -66,6 +66,7 @@ RageSound::RageSound(): Sample = NULL; decode_position = 0; stopped_position = 0; + max_driver_frame = 0; playing = false; playing_thread = 0; databuf.reserve(internal_buffer_size); @@ -109,6 +110,7 @@ RageSound &RageSound::operator=( const RageSound &cpy ) m_Param = cpy.m_Param; decode_position = cpy.decode_position; stopped_position = cpy.stopped_position; + max_driver_frame = 0; playing = false; playing_thread = 0; @@ -600,7 +602,8 @@ void RageSound::StopPlaying() // LOG->Trace("set playing false for %p (StopPlaying) (%s)", this, this->GetLoadedFilePath().c_str()); playing = false; playing_thread = 0; - + + max_driver_frame = 0; pos_map.Clear(); // LOG->Trace("StopPlaying %p finished (%s)", this, this->GetLoadedFilePath().c_str()); @@ -684,6 +687,15 @@ int64_t RageSound::GetPositionSecondsInternal( bool *approximate ) const /* Get our current hardware position. */ int64_t cur_frame = SOUNDMAN->GetPosition(this); + /* It's sometimes possible for the hardware position to move backwards, usually + * on underrun. We can try to prevent this in each driver, but it's an obscure + * error, so let's clamp the result here instead. Be sure to reset this on stop, + * since the position may reset. */ + if( cur_frame < max_driver_frame ) + LOG->Trace( "Sound %s: driver returned a lesser position (%i < %i)", + this->GetLoadedFilePath().c_str(), (int) cur_frame, (int) max_driver_frame ); + max_driver_frame = cur_frame = max( cur_frame, max_driver_frame ); + return pos_map.Search( cur_frame, approximate ); } diff --git a/stepmania/src/RageSound.h b/stepmania/src/RageSound.h index 7206bb066d..f568e97a51 100644 --- a/stepmania/src/RageSound.h +++ b/stepmania/src/RageSound.h @@ -151,6 +151,9 @@ private: int stopped_position; bool playing; + /* Keep track of the max SOUNDMAN->GetPosition result (see GetPositionSecondsInternal). */ + mutable int64_t max_driver_frame; + /* If playing, record the thread that called Play(). */ unsigned playing_thread;