I've finished my first try at making a patch for exchanging the left and right digital stereo channels in DOSBox 0.72. I implemented all the features I mentioned in my previous post, and I think it's a complete little package. Perhaps a moderator will feel this is worth splitting off into the patches section of the forum.
Features:
- Added a swapstereo= value to the [mixer] section in the conf file which defaults to false. If the value isn't in the conf file at all, it's considered as false.
- Added a switch to the MIXER command in DOSBox to toggle the swapping of the stereo channels. MIXER /SWAPSTEREO will invert the current setting. Also added a display of the current setting after the list of volume controls that MIXER displays.
Notes:
- The modifications are mostly contained in mixer.cpp, but dosbox.cpp also has a small change to support writing out the new conf setting when doing a "CONFIG -writeconf" in DOSBox.
- I chose the semantic of "swapped", but it could just as easily be "inverted", "reversed", "flipped", etc.
- Offset values are used to modify the AddSamples method in mixer.cpp, but I am unsure if this has less overhead or is more efficient than creating even more nested conditions in the code than there already are... perhaps someone knows without using a profiler?
The diff file for use in MSys/MinGW is attached. To apply the patch, copy the diff into your dosbox source folder, then in MSys: change directory to the dosbox source folder, run a "patch -p0<swapstereo.diff", and then "make" the application as usual.
I hope you will enjoy the patch and find it useful; and please let me know any thoughts or criticisms you have about it.
After working on my mixer patch, I realized that anything causing the samples to be shifted in the DMA buffer could cause the stereo channels to get crossed. Looking at the code in sblaster.cpp, something caught my eye in GenerateDMASound:
1case DSP_DMA_8: 2 if (sb.dma.stereo) { 3 read=sb.dma.chan->Read(size,&sb.dma.buf.b8[sb.dma.remain_size]); 4 Bitu total=read+sb.dma.remain_size; 5 if (!sb.dma.sign) sb.chan->AddSamples_s8(total>>1,sb.dma.buf.b8); 6 else sb.chan->AddSamples_s8s(total>>1,(Bit8s*)sb.dma.buf.b8); 7 if (total&1) { 8 sb.dma.remain_size=1; 9 sb.dma.buf.b8[0]=sb.dma.buf.b8[total-1]; 10 } else sb.dma.remain_size=0;
The code snippet is for 8-bit stereo, but the 16-bit stereo code is structured basically the same. The remain_size property interested me, because it is acting as an offset into the DMA buffer. I'm not sure, but I think it has to do with an odd number of samples being transfered in a given DMA cycle, and stereo samples are processed in (even) pairs. Anyway, the code towards the bottom toggles the property between 0 and 1, so I thought I might be on to something. I decided to do some logging of SB stuff, first stopping the "Raising IRQ" messages that flooded the log, and then adding some more info to existing messages. The following log is from the CD version of System Shock configured to use the AIL3 (Miles) SB16 driver:
The unexpected thing is the first 16-bit stereo (DMA mode 5) transfer being done for a single sample, which happens when the game starts up, before any sound is heard. This initial transfer is causing the remain_size property to get "stuck" at 1 for all subsequent DMA unmask events. The remainder isn't eventually resolved during the transfer cycles because the number of samples is even thereafter. It might be just this single-cycle stereo transfer of one sample that causes the shifting; but looking at the code, it seems like any stereo transfer with an odd number of total samples (a bad idea to begin with) could result in the same thing.
I made a log for Dungeon Keeper, which also uses Miles drivers and has swapped stereo channels in DOSBox, using both SBPro and SB16 configurations, and saw the same initial single-sample stereo transfer that throws off remain_size. Another Miles driver game, Settlers 2, follows the same pattern; but its stereo separation isn't easy to hear. Looking at the Miles driver files SBPRO.DIG and SB16.DIG in these games shows that they went through a number of revisions; but the single-sample stereo transfer at initialization remained a consistent "feature".
I tried resetting sb.dma.remain_size to 0 on each DMA unmask event, and it seems effective in preventing the swapping; but there are probably a number of ways to harden the code against what the Miles drivers (and possibly others) are doing, and my approach might not be ideal in all circumstances.
FYI, two DSP commands are issued between that first single-sample transfer, and the normal sound-producing tranfers: 0x41 (set output sample rate) and 0xC6, which generates a call to DSP_PrepareDMA_New. The "PrepareDMA" functions in DOSBox end up calling DSP_DoDMATransfer, which seems like it might be a good place to reset.
could you see what the games do you use the sbpro1 setting in dosbox ?
as the size=1 and such was added because that is how the sbpro1 handled it. (might be sbpro2)
Hmm, although System Shock does have a setup option for "Old SoundBlaster Pro" and "SoundBlaster Pro", the game's config file doesn't change with either setting, and there is only one SBPRO.DIG driver file... so perhaps the distinction is only important for auto-detection?
It seems remain_size doesn't have an effect here, the initialization transfer is mono for 4 samples with the SBPro driver; but the channels are still swapped. 😒 Can't see another explanation... at least I still have my mixer patch to fall back on.
BTW, with the SB16 in Dungeon Keeper, I noticed there is a "pop" in the left channel when you hear the first sound in the game; but it's gone when you set remain_size to 0, effectively dropping that hanging initialization sample in the buffer and preventing it from being output. I could not say how real SB16 hardware handled it, but it works out more aesthetically to reset the remainder when initializing a new DMA transfer. 😉
Please can you post patched exe(s)? I'm not a developer and don't have the MiniGW env etc. etc. but I really hate those games with inverted audio channels! 🙁
BTW, also Albion/DosBox has inverted stereo problems.
Albion uses the Miles sound drivers, so its situation is no different.
The attached file is a Win32 MinGW build of DOSBox 0.72 with the swapstereo patch. It also resets remain_size to zero when initializing a new DMA transfer, as discussed above, so the stereo channels with the Miles SB16 driver should be correct without swapping. The build includes most of the "optional" components: DDraw output, SDL_net, libpng/zlib. I gave up trying to get SDL_sound compiled under MinGW, but I don't notice the absence of whatever capability it provides. The executable has no debug or symbol info, making it more compact, and doesn't need any support files beyond those required by the official build.
There's also a bonus patch for the "zero split-line glitch" that affects the Event Horizon games, as discussed in Graphic glitch in Event Horizon games The approach used is not the post-decrement covered in the thread; instead it checks for the split before rendering lines, which is functionally similar to what is in the current CVS.
WOW!
This is very kind of you... thank you a lot!
I can now live happier 'till next DOSBox official versions (hope will be soon and will include also this sound prob. bug fixed)! 😁
I will just add that there is no stereo in wolf3d with sbtype=sbpro1,sbpro2 since dosbox 0.66beta2 (only sb16 with mixer=true has stereo sfx in wolf3D)
It was ok in dosbox 0.65. It is also ok on my real sbpro1 and real sbpro2 cards.
This is my first try to compile the DosBox Source.
I finally managed it to setup mingw + minsys on my pc.
I used this german Dosbox Build tutorial to compile dosbox.
Then I modified this SwapStereo-Patch for the v0.73 source.
I add my compiled version. It has SDLnet, SDLsound, LibPng and additionally Glide Support and SwapStereo-Patch(I hope that I did everything right 😉 ).
Throwing another game on the pile: The VGA remake of Space Quest 1 plays Sarien footstep sounds from the opposite speaker in relation to the side of the screen on which they appear. This is with sbtype=sb16 and Sound Blaster selected (I think) as the sound card in the game's install utility.
Hello HunterZ: Just look 3 posts back. I compiled the Dosbox 0.73 with the SwapStereo-Patch. It should load all miles-based-games with Left/Right correctly. For Archimedean Dynasty and GTA it works fine. 😀
Additionally you can swap channels by command promt and in the *.conf too.