Skip to content

Cross platform audio, single audio thread, full audio emulation accuracy, full implementation of the entire SB PCM, SB DSP, SB Hardware mixer, SB reset delay, OPL port read/write delays, SB variants, OPL3, OPL2, dual OPL2, Adlib Gold Music and surround effects, and rewired PC Speaker. Full software mixer UI on top.#1635

Merged
maximilien-noal merged 279 commits intomasterfrom
fix/pcm
Mar 6, 2026

Conversation

@maximilien-noal
Copy link
Copy Markdown
Member

@maximilien-noal maximilien-noal commented Dec 13, 2025

Description of Changes

Fixes all PCM and music rendering issues by using the latest dosbox staging architecture for the software mixer, which runs on its own thread, and update every related class along with it (PC Speaker, Sound Blaster, OPL, ...)

image

It uses less threads. The audio logic is inverted: the software mixer pulls audio data from devices.

For comparison here is the old audio thread logic from the master branch:

image

It uses more threads, and is less efficient. It is also crash prone. EIther the emulated program crashes, or the emulator itself crashes.

Rationale behind Changes

Vastly improved audio quality, performance, architecture, hardware emulation, and hardware compatibility.

Fixes crash issues related to sound threads.

Re-architectures the entire audio logic, for better performance and emulation accuracy.

Makes Dune, Lost Eden, Krondor, and so many other games sound as they should, for the PC Speaker, SB PCM, OPL3, OPL2, Dual OPL2, and Adlib Gold OPL.

Fixes #1513 #1514 #1464

Also fixes Where in Space is Carmen Sandiego from locking up, and so many game compatibility issues.

Status

The code is now 100% ported and 100% correct.

Audio is performant and fully cross platform. Works on Windows, Linux, MacOS, x86_64, and ARM64.
No native dependencies anymore. Pure C#. The audio backend code is ported from SDL 2 source code into C#.

See: https://github.com/OpenRakis/Spice86.Audio/tree/main/src/Spice86.Audio for details

All games I could test work fine.
The code is ready for review

Suggested Testing Steps

Test General MIDI, MT-32, PC Speaker, Sound Blaster PCM, Sound Blaster OPL, Sound Blaster variants (Sb16, Sb1, Sb2, SbPro1, SbPro2), sbmixer on/off and, Adlib Gold music (with surround module!) on whatever platform you want (Linux, Mac, Windows, x86_64, ARM64)

Except for MT-32 on MacOS ARM64 (which still lacks a native dependency), all devices on all platforms should be accurate, sound at it should sound, be fast, and overall just work.

(in Release build, that is! -- A 'problem' inherited from master branch is that sometimes Debug build can slow down on large video updates - this won't affect the Nuget package since it's compiled in Release mode with all compiler optimizations)

@maximilien-noal maximilien-noal self-assigned this Dec 13, 2025
@maximilien-noal maximilien-noal added Dune Related to Dune PCM related to sound effects playback or performance Music Music emulation related. Can be any form of Music (FM Synth, MT-32, or General MIDI, ...) labels Dec 13, 2025
Comment thread src/Spice86.Core/Emulator/Devices/Sound/Blaster/LookupTables.cs Fixed
Comment thread src/Spice86.Core/Emulator/Devices/Sound/Blaster/LookupTables.cs Fixed
Comment thread src/Spice86.Core/Emulator/Devices/Sound/SoundChannel.cs Fixed
Comment thread src/Spice86.Core/Emulator/Devices/Sound/SoundChannel.cs Fixed
Comment thread src/Spice86.Core/Emulator/Devices/Sound/Blaster/SoundBlaster.cs Fixed
Comment thread src/Spice86.Core/Emulator/Devices/Sound/Blaster/SoundBlaster.cs Fixed
Comment thread src/Spice86.Core/Emulator/Devices/Sound/Blaster/SoundBlaster.cs Fixed
Comment thread src/Spice86.Core/Emulator/Devices/Sound/Mixer.cs Fixed
Comment thread src/Spice86.Core/Emulator/Devices/Sound/Mixer.cs Fixed
Comment thread src/Spice86.Core/Emulator/Devices/Sound/Mixer.cs Fixed
Comment thread src/Spice86/ViewModels/MixerChannelViewModel.cs Fixed
Comment thread src/Spice86/ViewModels/MixerChannelViewModel.cs Fixed
Comment thread src/Spice86.Core/Emulator/Devices/Sound/Blaster/SoundBlaster.cs Fixed
Comment thread src/Spice86.Core/Emulator/Devices/Sound/Mixer.cs Fixed
Comment thread src/Spice86.Core/Emulator/Devices/Sound/Mixer.cs Fixed
Comment thread src/Spice86.Core/Emulator/Devices/Sound/Blaster/SoundBlaster.cs Fixed
Comment thread src/Spice86/ViewModels/MainWindowViewModel.cs Fixed
Comment thread src/Spice86/ViewModels/MixerChannelViewModel.cs Fixed
Comment thread src/Spice86/ViewModels/MixerChannelViewModel.cs Fixed
Comment thread src/Spice86/ViewModels/MixerChannelViewModel.cs Fixed
Comment thread src/Spice86.Core/Emulator/Devices/Sound/Mixer.cs Fixed
Comment thread src/Spice86.Core/Emulator/Devices/Sound/MixerChannel.cs Fixed
Comment thread src/Spice86.Core/Emulator/Devices/Sound/MixerChannel.cs Fixed
Comment thread src/Spice86.Core/Emulator/Devices/Sound/MixerChannel.cs Fixed
Comment thread src/Spice86.Core/Emulator/Devices/Sound/MixerChannel.cs Fixed
Comment thread src/Spice86.Core/Emulator/Devices/Sound/Mixer.cs Fixed
Comment thread src/Spice86.Core/Emulator/Devices/Sound/Mixer.cs Fixed
Comment thread src/Spice86.Core/Emulator/Devices/Sound/Lfo.cs Fixed
Comment thread tests/Spice86.Tests/Emulator/Devices/Sound/SoundBlasterDmaTests.cs Fixed
Comment thread tests/Spice86.Tests/Emulator/Devices/Sound/SoundBlasterDmaTests.cs Fixed
Comment thread src/Spice86.Core/Emulator/Devices/Sound/Mixer.cs Fixed
Copy link
Copy Markdown
Contributor

@github-advanced-security github-advanced-security AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CodeQL found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

Copilot AI and others added 15 commits December 18, 2025 08:11
… tests (#1675)

* Initial plan

* add dsp port parity tests

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* expand dsp command tests

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* add dsp timeconstant samplerate and test register tests

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* cache sb state in dsp tests

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* add asm dsp integration tests

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* remove reflection and use nasm dsp binary

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>
…and stabilize test execution across platforms (#1676)

* Initial plan

* add sound blaster mixer tests and asm status output

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Update mixer asm stereo expectation

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Disable xunit parallelization to avoid Windows OOM

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Guard headless render timer against disposed renderer

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Remove swallowed exceptions in headless render timer

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>
…1677)

* Initial plan

* Add DacChannel property and PCM test infrastructure

- Add public DacChannel property to SoundBlaster class for test access
- Add audio capture infrastructure to SbPcmAsmIntegrationTests
- Add 5 new basic functional tests that don't require golden WAV files
- Tests validate test infrastructure, file writing, and basic execution
- Note: Audio capture limited when using DummyAudio engine

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Address code review: remove unused System.Linq import

- Remove unused System.Linq using directive
- Keep DacChannel public property (follows existing pattern from Opl3Fm)
- All tests still passing (5 new tests, 1026 total passing)

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Fix resource disposal in PCM tests to prevent leaks

- Wrap Spice86DependencyInjection in using statements for proper disposal
- Add disposal delay to allow timer cleanup before test completion
- Prevents resource leaks from undisposed emulator instances
- Note: Renderer NullReferenceException is pre-existing issue in test framework

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Add NullReferenceException guards in Renderer.Render

- Wrap state access in try-catch to handle disposal race conditions
- Prevents crash when HeadlessGui timer fires during cleanup
- Remove Task.Delay calls that increased race condition window
- All tests pass without crashes

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* refactor: remove poor error handling

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>
Co-authored-by: Maximilien Noal <noal.maximilien@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
…ing hot path mirror) (#1683)

* Initial plan

* Phase 2: Replace ConcurrentDictionary with Dictionary + lock in Mixer

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Add audio performance tests and validation

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Add comprehensive audio performance optimization documentation

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Address code review feedback: improve comments and buffer capacity checks

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Revert to ConcurrentDictionary to fix critical performance regression

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Update documentation to reflect Dictionary + lock revert and lessons learned

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Remove markdown documentation per user request

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Optimize OPL AudioCallback to use AddSamples_sfloat for bulk frame addition

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>
* Initial plan

* Optimize OPL audio hot paths following DOSBox Staging architecture

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Address code review feedback: remove extra blank lines and reduce lock contention

* Remove custom generator support and apply DOSBox Staging hot path optimizations

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Remove dead RenderTo method for cleaner DOSBox Staging parity

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>
…nd embedded test data (#1687)

* Initial plan

* Add SB PCM 11025Hz test: WAV file and ASM program

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Add C# tests for 11025Hz PCM and fix 8-bit WAV reading support

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Add completion documentation for SB PCM test implementation

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Complete sb_dma_8bit_single.asm with 11025 Hz PCM playback, remove docs and Python scripts

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Fix 8-bit PCM to float conversion to use correct scaling factor (127.5f)

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Update documentation to reflect actual 8-bit PCM conversion values

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Remove redundant IRQ ack, add 5-second WAV as embedded C# byte array

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Clarify ASM comments and improve WavFileFormat documentation

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>
…h optimized performance (#1689)

* Initial plan

* WIP: Start exact C# port of Speex resampler - TDD approach with initial test infrastructure

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Complete faithful C# port of Speex resampler - all 18 tests passing

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Integrate pure C# Speex into MixerChannel, remove P/Invoke bindings, update docs

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Refactor Speex integration: make non-nullable, remove try/catch, use const quality, initialize in constructor

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Complete Speex API port: Add all missing methods with TDD - 32/32 tests passing

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Fix code review issues: ArrayPool for hot paths, bounds checking, readonly fields, IDisposable, precision fixes

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Replace all ternary operators with if/else statements for better readability

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Fix code review feedback: clarify GCD comment, remove unnecessary null-conditional, use ternary operators

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>
Initialize _sampleRateHz to 22050 to prevent input sample rate exceptions with the Speex resampler. Note: this constructor initialization may not be the ideal solution for Speex resampler integration. No other logic was modified.
…1737)

* Initial plan

* Fix Speex resampler initialization to mirror DOSBox Staging exactly

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Add ClearResampler method, fix default resample method, update documentation

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Document architectural difference - recommend testing current fixes first

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>
…1741)

* Initial plan

* fix: keep framesRemaining in scope for handler call

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>
* Initial plan

* Phase 1: Move resampling to AddSamples methods - mirrors DOSBox architecture

- Added Envelope class for click prevention (mirrors DOSBox Envelope)
- Completely refactored all AddSamples methods (m8, m16, s16, mfloat, sfloat, AudioFrames)
- Created type-specific ConvertSamplesAndMaybeZohUpsample methods for each sample format
- Resampling now happens IN AddSamples methods (not in Mix)
- Added Lerp helper function for linear interpolation
- Added ApplySpeexResampling for Speex resampling in AddSamples
- Added ApplyInPlaceProcessing for filters and crossfeed in AddSamples
- Removed orphaned ApplyLerpUpsampling and SpeexResampleBuffer methods
- Architecture now matches DOSBox exactly: Convert→Resample→Process pattern

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

* Document critical architectural finding in AUDIO_PORT_PLAN.md

- Documented that resampling architecture is now fixed in MixerChannel
- Identified CRITICAL issue: SoundBlaster.cs bypasses AddSamples entirely
- SoundBlaster PCM audio is NOT resampled (bypasses the resampling we just fixed)
- Need to implement output_queue pattern from DOSBox for SoundBlaster
- OPL is fixed (calls AddSamples_sfloat), SoundBlaster PCM still broken

Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: maximilien-noal <1087524+maximilien-noal@users.noreply.github.com>
@maximilien-noal maximilien-noal changed the title Fixes for PCM and OPL sound quality, emulation accuracy, SB/OPL compatibility, mixer thread logic, audio events, audio hardware delays, and audio re-architecture Cross platform audio, single audio thread, full audio emulation accuracy, full implementation of the entire SB DSP, SB variants, OPL3, OPL2, dual OPL2, Adlib Gold Music and surround effects, and rewired PC Speaker. Full software mixer UI on top. Mar 1, 2026
@maximilien-noal maximilien-noal changed the title Cross platform audio, single audio thread, full audio emulation accuracy, full implementation of the entire SB DSP, SB variants, OPL3, OPL2, dual OPL2, Adlib Gold Music and surround effects, and rewired PC Speaker. Full software mixer UI on top. Cross platform audio, single audio thread, full audio emulation accuracy, full implementation of the entire SB DSP, SB Hardware mixer, SB reset delay, OPL port read/write delays, SB variants, OPL3, OPL2, dual OPL2, Adlib Gold Music and surround effects, and rewired PC Speaker. Full software mixer UI on top. Mar 1, 2026
@maximilien-noal maximilien-noal changed the title Cross platform audio, single audio thread, full audio emulation accuracy, full implementation of the entire SB DSP, SB Hardware mixer, SB reset delay, OPL port read/write delays, SB variants, OPL3, OPL2, dual OPL2, Adlib Gold Music and surround effects, and rewired PC Speaker. Full software mixer UI on top. Cross platform audio, single audio thread, full audio emulation accuracy, full implementation of the entire SB PCM, SB DSP, SB Hardware mixer, SB reset delay, OPL port read/write delays, SB variants, OPL3, OPL2, dual OPL2, Adlib Gold Music and surround effects, and rewired PC Speaker. Full software mixer UI on top. Mar 1, 2026
@maximilien-noal maximilien-noal marked this pull request as draft March 1, 2026 17:35
@maximilien-noal maximilien-noal marked this pull request as ready for review March 2, 2026 07:16
Refactored audio frame enqueueing logic to use generic methods for mono/stereo and sample type handling, eliminating redundant code. Added helper functions and delegates for sample conversion, improved silence handling, and optimized silent frame generation with an empty frame cache. Updated DAC mode to enqueue frames directly. Improved code clarity and maintainability.
@maximilien-noal maximilien-noal merged commit 6a635d8 into master Mar 6, 2026
5 checks passed
@maximilien-noal maximilien-noal deleted the fix/pcm branch March 6, 2026 20:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Dune Related to Dune Music Music emulation related. Can be any form of Music (FM Synth, MT-32, or General MIDI, ...) PCM related to sound effects playback or performance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Regression: (Dune) Some PCM sound effect don't always play (orni wings opening, for example)

6 participants