bugfix(audio): Apply configured volume to Bink movie audio - #3083
Conversation
Fixes TheSuperHackers#2850. Movie audio ignored the Options volume sliders because BinkSetVolume was called once in createStream(), before Bink's audio output had started, so it never took effect. Extract the volume calc into calculateMovieAudioVolume() and reapply it on every decoded frame in frameDecompress() so it takes effect and tracks live slider changes.
Fix the floor comment (formula is unchanged from retail, floor is 327 not 1) and drop the live-slider-change claim from the per-frame comment; the Options menu isn't reachable during movie playback. The reason to reapply every frame is that the one-shot createStream() call ran before Bink's audio output started, so it never took effect.
Per review: don't reapply the volume every frame. The original defect was that BinkSetVolume ran in createStream(), before Bink's audio output existed, so it was discarded. Apply it once on the first BinkDoFrame(), the earliest point it can actually take effect. Drops the createStream() call and the per-frame poll in favor of a one-shot latch.
|
I don't think the title is correct, as the volume is not applied every frame, but only once. |
- Return the 327 floor instead of 0 on the null-audio path so it does not trip Bink's 'play at full volume' quirk. - Trim the redundant formula comment. - Restore retail tab alignment on m_handle/m_memFile and align m_volumeSet.
fixed |
Per xezon's review. Replace the per-frame latch with a push model: - VideoPlayerInterface gains a setVolume(Real) virtual (no-op default in VideoPlayer); BinkVideoPlayer overrides it to push the volume to every open stream's Bink audio output. - MilesAudioManager::processPlayingList() pushes the speech volume to TheVideoPlayer whenever the volume changes, so movies that bypass the Miles mixer follow the sliders. - BinkVideoPlayer::update() applies the volume once on the first frame a stream exists, fixing the original too-early set in createStream() (Bink's audio output is not running yet at creation, so it was lost). - calculateMovieAudioVolume() now takes the speech volume as a parameter.
|
You are clearly using AI. While there is in principle nothing against it, I would strongly recommend you review the changes it makes - per our contribution guide. |
|
|
||
| virtual void notifyVideoPlayerOfNewProvider( Bool nowHasValid ) override { } | ||
|
|
||
| virtual void setVolume( Real volume ) override { } |
There was a problem hiding this comment.
FFmpegVideoPlayer derives from VideoPlayer, so it picks up this no-op and the volume plumbing is Bink-only. Override it there too?
There was a problem hiding this comment.
FFmpegVideoPlayer now overrides setVolume and pushes the speech volume to the OpenAL movie stream. Initial volume is also applied when the stream starts, since that backend is already live by then.
There was a problem hiding this comment.
Wait do we have OpenAL in upstream yet? This might not work until we get that landed :(
There was a problem hiding this comment.
Yeah, OpenAL is not in this repo yet. The FFmpeg override is behind RTS_USE_OPENAL so Miles/Bink builds keep a no-op, and the OpenAL gain path is just plumbing until that backend lands.
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
|
This is looking good :) Can you do some testing and add the results to the PR description? eg
|
|
Done |
|
| Filename | Overview |
|---|---|
| Core/GameEngineDevice/Source/VideoDevice/Bink/BinkVideoPlayer.cpp | Applies initial volume after polling the Bink stream and propagates later volume changes across open streams. |
| Core/GameEngineDevice/Source/MilesAudioDevice/MilesAudioManager.cpp | Forwards changed speech volume to the active video-player provider during audio-list processing. |
| Core/GameEngine/Include/GameClient/VideoPlayer.h | Expands the shared video-player contract with volume control and supplies a no-op null implementation. |
| Core/GameEngineDevice/Include/VideoDevice/FFmpeg/FFmpegVideoPlayer.h | Keeps the optional FFmpeg provider compatible with the expanded interface through a no-op override. |
Sequence Diagram
sequenceDiagram
participant Audio as MilesAudioManager
participant Player as BinkVideoPlayer
participant Stream as BinkVideoStream
participant Bink as Bink API
Player->>Stream: createStream(handle)
Stream->>Bink: BinkWait(handle)
Player->>Bink: BinkSetVolume(initial volume)
Audio->>Player: setVolume(speech volume)
loop Every open stream
Player->>Bink: BinkSetVolume(updated volume)
end
Reviews (3): Last reviewed commit: "refactor(video): make null players expli..." | Re-trigger Greptile
xezon
left a comment
There was a problem hiding this comment.
Good to see this got rid of the update loop hack.
|
Codex Review: Didn't find any major issues. 🎉 Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
The change title and description are outdated. |
updated |
Fixes #2850.
Problem
Bink movie audio bypasses the Miles mixer. The initial
BinkSetVolume()call ran before Bink's audio output was ready, so movies ignored the configured Speech volume and could play at full volume.Changes
BinkWait()before applying the initial volume inBinkVideoPlayer::createStream().VideoPlayerInterface::setVolume()and implement it inBinkVideoPlayerso Speech-volume changes update every open Bink stream.Testing
EALogoMoviesynchronously withSizzlein a test harness. The replacement rendered normally and received the configured volume. The same 35-second interval measured -83.3 dB mean / -66.2 dB peak at Speech 0 and -19.7 dB mean / -2.5 dB peak at Speech 100.