diff --git a/Core/GameEngine/Include/GameClient/VideoPlayer.h b/Core/GameEngine/Include/GameClient/VideoPlayer.h index 98a7d4c8d67..a7380a2114c 100644 --- a/Core/GameEngine/Include/GameClient/VideoPlayer.h +++ b/Core/GameEngine/Include/GameClient/VideoPlayer.h @@ -245,6 +245,8 @@ class VideoPlayerInterface : public SubsystemInterface virtual const FieldParse *getFieldParse() const = 0; ///< Return the field parse info virtual void notifyVideoPlayerOfNewProvider( Bool nowHasValid ) = 0; ///< Notify the video player that they can now ask for an audio handle, or they need to give theirs up. + + virtual void setVolume( Real volume ) = 0; ///< Push a new speech volume to the video player's audio output }; @@ -299,6 +301,13 @@ class VideoPlayer : public VideoPlayerInterface }; +class NullVideoPlayer : public VideoPlayer +{ + public: + + virtual void setVolume( Real ) override { } +}; + extern VideoPlayerInterface *TheVideoPlayer; //---------------------------------------------------------------------------- diff --git a/Core/GameEngineDevice/Include/VideoDevice/Bink/BinkVideoPlayer.h b/Core/GameEngineDevice/Include/VideoDevice/Bink/BinkVideoPlayer.h index 38047636245..5bfd99adf82 100644 --- a/Core/GameEngineDevice/Include/VideoDevice/Bink/BinkVideoPlayer.h +++ b/Core/GameEngineDevice/Include/VideoDevice/Bink/BinkVideoPlayer.h @@ -101,11 +101,6 @@ class BinkVideoStream : public VideoStream class BinkVideoPlayer : public VideoPlayer { - - protected: - - VideoStreamInterface* createStream( HBINK handle ); - public: // subsytem requirements @@ -127,7 +122,16 @@ class BinkVideoPlayer : public VideoPlayer virtual VideoStreamInterface* load( AsciiString movieTitle ) override; ///< Load video file in to memory for playback virtual void notifyVideoPlayerOfNewProvider( Bool nowHasValid ) override; + virtual void setVolume( Real volume ) override; virtual void initializeBinkWithMiles(); + + protected: + + VideoStreamInterface* createStream( HBINK handle ); + + private: + + static Int calculateMovieAudioVolume( Real volume ); }; diff --git a/Core/GameEngineDevice/Include/VideoDevice/FFmpeg/FFmpegVideoPlayer.h b/Core/GameEngineDevice/Include/VideoDevice/FFmpeg/FFmpegVideoPlayer.h index 2d6e55d7053..3635aa78e02 100644 --- a/Core/GameEngineDevice/Include/VideoDevice/FFmpeg/FFmpegVideoPlayer.h +++ b/Core/GameEngineDevice/Include/VideoDevice/FFmpeg/FFmpegVideoPlayer.h @@ -121,6 +121,7 @@ class FFmpegVideoPlayer : public VideoPlayer virtual VideoStreamInterface* load( AsciiString movieTitle ); ///< Load video file in to memory for playback virtual void notifyVideoPlayerOfNewProvider( Bool nowHasValid ); + virtual void setVolume( Real ) override { } virtual void initializeBinkWithMiles(); }; diff --git a/Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp b/Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp index 23a2cfef6ee..d8943281329 100644 --- a/Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp +++ b/Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp @@ -2269,6 +2269,11 @@ void MilesAudioManager::processPlayingList() if (m_volumeHasChanged) { m_volumeHasChanged = false; + + // TheSuperHackers @bugfix Push speech volume changes because Bink movie audio bypasses the Miles mixer. + if (TheVideoPlayer) { + TheVideoPlayer->setVolume(getVolume(AudioAffect_Speech)); + } } } diff --git a/Core/GameEngineDevice/Source/VideoDevice/Bink/BinkVideoPlayer.cpp b/Core/GameEngineDevice/Source/VideoDevice/Bink/BinkVideoPlayer.cpp index ebbc91179c1..5044f077710 100644 --- a/Core/GameEngineDevice/Source/VideoDevice/Bink/BinkVideoPlayer.cpp +++ b/Core/GameEngineDevice/Source/VideoDevice/Bink/BinkVideoPlayer.cpp @@ -202,18 +202,40 @@ VideoStreamInterface* BinkVideoPlayer::createStream( HBINK handle ) stream->m_player = this; m_firstStream = stream; - // never let volume go to 0, as Bink will interpret that as "play at full volume". - Int mod = (Int) ((TheAudio->getVolume(AudioAffect_Speech) * 0.8f) * 100) + 1; - Int volume = (32768*mod)/100; - DEBUG_LOG(("BinkVideoPlayer::createStream() - About to set volume (%g -> %d -> %d", - TheAudio->getVolume(AudioAffect_Speech), mod, volume)); - BinkSetVolume( stream->m_handle,0, volume); - DEBUG_LOG(("BinkVideoPlayer::createStream() - set volume")); + // TheSuperHackers @bugfix BinkWait must run first or Bink ignores the initial volume. + BinkWait( stream->m_handle ); + Int volume = calculateMovieAudioVolume( TheAudio->getVolume(AudioAffect_Speech) ); + BinkSetVolume( stream->m_handle, 0, volume ); } return stream; } +//============================================================================ +// BinkVideoPlayer::calculateMovieAudioVolume +//============================================================================ + +Int BinkVideoPlayer::calculateMovieAudioVolume( Real volume ) +{ + // Never let volume go to 0, as Bink will interpret that as "play at full volume". + Int mod = (Int) ((volume * 0.8f) * 100) + 1; + return (32768*mod)/100; +} + +//============================================================================ +// BinkVideoPlayer::setVolume +//============================================================================ + +void BinkVideoPlayer::setVolume( Real volume ) +{ + // Push the new volume to every open stream's audio output. + Int binkVolume = calculateMovieAudioVolume( volume ); + for ( VideoStreamInterface* stream = firstStream(); stream != nullptr; stream = stream->next() ) + { + BinkSetVolume( static_cast( stream )->m_handle, 0, binkVolume ); + } +} + //============================================================================ // BinkVideoPlayer::open //============================================================================ diff --git a/Core/Tools/MapCacheBuilder/Source/WinMain.cpp b/Core/Tools/MapCacheBuilder/Source/WinMain.cpp index 134f1465980..1ba344f7c01 100644 --- a/Core/Tools/MapCacheBuilder/Source/WinMain.cpp +++ b/Core/Tools/MapCacheBuilder/Source/WinMain.cpp @@ -259,7 +259,7 @@ Int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, initSubsystem(TheTerrainRoads, new TerrainRoadCollection(), "Data\\INI\\Default\\Roads", "Data\\INI\\Roads"); initSubsystem(TheScriptEngine, (ScriptEngine*)(new ScriptEngine())); initSubsystem(TheAudio, (AudioManager*)new MilesAudioManager()); - initSubsystem(TheVideoPlayer, (VideoPlayerInterface*)(new VideoPlayer())); + initSubsystem(TheVideoPlayer, (VideoPlayerInterface*)(new NullVideoPlayer())); initSubsystem(TheModuleFactory, (ModuleFactory*)(new W3DModuleFactory())); initSubsystem(TheSidesList, new SidesList()); initSubsystem(TheCaveSystem, new CaveSystem()); diff --git a/Generals/Code/Tools/WorldBuilder/src/WorldBuilder.cpp b/Generals/Code/Tools/WorldBuilder/src/WorldBuilder.cpp index c122151259d..b3287235361 100644 --- a/Generals/Code/Tools/WorldBuilder/src/WorldBuilder.cpp +++ b/Generals/Code/Tools/WorldBuilder/src/WorldBuilder.cpp @@ -367,7 +367,7 @@ BOOL CWorldBuilderApp::InitInstance() initSubsystem(TheScriptEngine, (ScriptEngine*)(new ScriptEngine())); initSubsystem(TheAudio, (AudioManager*)new MilesAudioManager()); - initSubsystem(TheVideoPlayer, (VideoPlayerInterface*)(new VideoPlayer())); + initSubsystem(TheVideoPlayer, (VideoPlayerInterface*)(new NullVideoPlayer())); initSubsystem(TheModuleFactory, (ModuleFactory*)(new W3DModuleFactory())); initSubsystem(TheSidesList, new SidesList()); initSubsystem(TheCaveSystem, new CaveSystem()); diff --git a/GeneralsMD/Code/Tools/WorldBuilder/src/WorldBuilder.cpp b/GeneralsMD/Code/Tools/WorldBuilder/src/WorldBuilder.cpp index 5f19126638a..d49589ee0c8 100644 --- a/GeneralsMD/Code/Tools/WorldBuilder/src/WorldBuilder.cpp +++ b/GeneralsMD/Code/Tools/WorldBuilder/src/WorldBuilder.cpp @@ -384,7 +384,7 @@ BOOL CWorldBuilderApp::InitInstance() ini.loadFileDirectory( "Data\\Scripts\\Scripts", INI_LOAD_OVERWRITE, nullptr ); initSubsystem(TheAudio, (AudioManager*)new MilesAudioManager()); - initSubsystem(TheVideoPlayer, (VideoPlayerInterface*)(new VideoPlayer())); + initSubsystem(TheVideoPlayer, (VideoPlayerInterface*)(new NullVideoPlayer())); initSubsystem(TheModuleFactory, (ModuleFactory*)(new W3DModuleFactory())); initSubsystem(TheSidesList, new SidesList()); initSubsystem(TheCaveSystem, new CaveSystem());