-
-
Notifications
You must be signed in to change notification settings - Fork 154
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Selectively suppress initial Sound Blaster DMA transfer #411
Conversation
5dc605d
to
d6165c3
Compare
|
b7b873d
to
b2a471b
Compare
b2a471b
to
1e7b22f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On first sight, looks good code-wise :) I left few comments (naming and such), will follow up with some testing for the next round of review.
BTW, thank you for detailed commit messages - they really help :) |
a89af72
to
2f5e50b
Compare
CheckDMAEnd actually finishes the DMA transfer and actually doesn't return a boolean (or success/fail) as its name describes. This commit makes it fall in line with the other DMA_* functions.
The function doesn't generate DMA sounds. It processes audio samples as provided by the emulated software. The suggested name also falls in line with the existing DMA_* functions.
The name implies it does something to terminate the DMA event. We see it's actually a no-op wrapper that just processes DMA samples. We eliminate this redundant wrapping so the calling code more accurately describes what's actually happening.
We rename this slightly to reflect the fact that this function is actually processing samples. We also prefer the name "Suppress" over "Silent", as the former is an verb where as the latter in an adjective describing a state-of-being.
This opens up the ability to differentiate how samples are processed: if they're actually Played or Suppressed.
This function will suppress the given DMA transfer if its size is less than or equal to a DOS DWORD or of any size if the SB's onboard speaker-output is set to disabled (in which case, the game doesn't want it to be heard). Once the initial suppression takes place, this function flips the DMA_Process_Samples function pointer over to DMA_Play_Samples, so subsequent DMA transfers are no suppressed. Note: this commit simply adds this function without making use of it.
This intialization function is added to DSP_Reset(), which is called both during the object's construction as well as requested on-the-fly by the emulated software, typically during the detection phase; sometimes many times as the driver performs various tests to detemine if the card exists and is useable. This intialization function also makes use of the new DMA initialization suppression function to ensure "try-and-see transfers" are not heard.
Previous when an SB16 was being emulated, the mixer's channel was always left enabled (per its initial state), even when the game requested that it be disabled. This commit allows the (dosbox) mixer's audio channel state to reflect the requested speaker-output state, which saves cycles and simplifies the logic. This also respects the game's actual behavior: if the game developer asked the SB's onboard speaker-output to be disabled (or enabled), then we trust that's infact what they wanted.
Some of these would have conflicted in the commit history, so these have come at the end. - Improve naming of DMA transfer functions and avoid conflict with general dma.h functions. - Improve order of speaker setup routine to flush old content before turning on the audio channel. - Fix tab'ing in initialization function.
2f5e50b
to
ba69d97
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I modified last commit to replace Neither_Snake_Case_Nor_Camel_Case naming with CamelCase (to be consistent with naming of other functions in this file) and noticed some other whitespace errors.
That would've been my last comment, otherwise it's good - I will merge it in momentarily :)
Excellent, thanks for the last fixup @dreamer! |
Many games use a small DMA transfer as part of their Sound Blaster detection and initialization routine. Because the content in this initial DMA transfer is often garbage and/or discontinuous, this leads to a "pop" while the game is starting up (this information is courtesy ripsaw8080, thank you!).
This PR suppresses this initial DMA transfer after a
DSP_Reset
cycle if:This PR is a quality of life improvement because these initial pops can be jarring and lead to hearing damage at high volumes, especially for those using high-SnR earbud headphone. It's also a bug-fix because this "audio" is not game content, and instead is the result of poor documentation and hardware design by Creative Labs. See the before-and-after comparison images in the follow-up comment for just a small sampling of games affected by this.
Notes: the suppressed transfer is processed but without being played, so all aspects of the card state appear normal. If the suppression criteria isn't met then the behavior matches that prior to the PR. At no point is the audio content itself or channel volume altered.
After testing hundreds of titles, this corrects a significant number of games without adversely affecting those where the criteria is not met. I should warn that even with this, not all games games are fixed: some apply a constant DC-offset as part of their audio track (which pops on playback), others can pop even without using the Sound Blaster, and others pop without using DMA transfers.
PR review: Suggest reviewing commit-by-commit; I tried hard to layer these in a nice sequence that builds up to the functional change.