From bf2e7c210d863dd0f0b217b52c476c74571736ba Mon Sep 17 00:00:00 2001 From: Chris Robinson Date: Thu, 6 Oct 2022 11:19:10 -0700 Subject: [PATCH] Use a MovieAudioTrack for synchronized audio with MvePlayer --- src/common/cutscenes/movieplayer.cpp | 56 ++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 7 deletions(-) diff --git a/src/common/cutscenes/movieplayer.cpp b/src/common/cutscenes/movieplayer.cpp index b86df6a2f2..124a9b2bd5 100644 --- a/src/common/cutscenes/movieplayer.cpp +++ b/src/common/cutscenes/movieplayer.cpp @@ -260,11 +260,55 @@ public: class MvePlayer : public MoviePlayer { InterplayDecoder decoder; - SoundStream* stream = nullptr; + MovieAudioTrack audioTrack; bool failed = false; bool StreamCallback(SoundStream *stream, void *buff, int len) { + const double delay = audioTrack.GetClockDiff(stream); + const int samplerate = audioTrack.GetSampleRate(); + const int framesize = audioTrack.GetFrameSize(); + + if(delay > 0.0) + { + // If diff > 0, skip samples. Don't skip more than a full update at once. + int skip = std::min(int(delay*samplerate)*framesize, len); + if(!decoder.FillSamples(buff, len)) + return false; + + // Offset the measured audio position to account for the skipped samples. + audioTrack.AdjustOffset(skip/framesize); + + if(skip == len) + return decoder.FillSamples(buff, len); + memmove(buff, (char*)buff+skip, len-skip); + if(!decoder.FillSamples((char*)buff+len-skip, skip)) + memset((char*)buff+len-skip, 0, skip); + + return true; + } + + if(delay < 0.0) + { + // If diff < 0, duplicate samples. Don't duplicate a full update (we need at + // least one new sample frame to duplicate). + int dup = std::min(int(-delay*samplerate)*framesize, len-framesize); + if(!decoder.FillSamples((char*)buff+dup, len-dup)) + return false; + + if(framesize == 1) + memset(buff, ((char*)buff)[dup], dup); + else + { + for(int i=0;i < dup;++i) + ((char*)buff)[i] = ((char*)buff+dup)[i%framesize]; + } + + // Offset the measured audio position to account for the duplicated samples. + audioTrack.AdjustOffset(-dup/framesize); + return true; + } + return decoder.FillSamples(buff, len); } static bool StreamCallbackC(SoundStream *stream, void *buff, int len, void *userdata) @@ -288,15 +332,15 @@ public: { if (failed) return false; + audioTrack.SetClock(clock); bool playon = decoder.RunFrame(clock); if (playon) { - if (!stream && decoder.HasAudio()) + if (!audioTrack.GetAudioStream() && decoder.HasAudio()) { S_StopMusic(true); // start audio playback - stream = S_CreateCustomStream(6000, decoder.GetSampleRate(), decoder.NumChannels(), MusicSamples16bit, StreamCallbackC, this); - if (!stream) + if (!audioTrack.Start(decoder.GetSampleRate(), decoder.NumChannels(), MusicSamples16bit, StreamCallbackC, this)) decoder.DisableAudio(); } } @@ -306,9 +350,7 @@ public: ~MvePlayer() { - if (stream) - S_StopCustomStream(stream); - stream = nullptr; + audioTrack.Finish(); decoder.Close(); }