First post, by Mok
- Rank
- Newbie
I wanted to play an old game with mt-32 music, so I downloaded newest cvs source of dosbox and mt-32 branch of scummvm source (as it seems it's the only one which is still modified). Unfortunately after compiling it, it was exactly the same as before, lots of crackling and some missing voices. After playing with a source for a couple of hours I added some hacks that actually allow me to play the game without switching the music off. Don't take me wrong - I didn't fix the bugs. I'm not a C/C++ programmer plus I know absolutely nothing about sound. The problems I fixed or worked around are mostly related to overflows in code. TBH I think the way the emulator is designed is a bit flawed. There's a lot of converting between floating point, 32-bit and 16-bit data. I understand that it was made that way so the emu is working even on slower machines but it's a bit silly... 16-bit data, converted to floats, then back to 16-bit or 32-bit, then again converted to floats for reverb and so on... Probably most of the problems would disappear if someone changed everything (cached samples, all math) to floats with only 1 conversion to 16-bit data at the very end. Yes, probably it would be slower. But most of overflows would disappear and having working version then you could think about carefully doing an optimized integer version for archs with slow fpus.
Changes:
1) I changed MT32EMU_MAX_PARTIALS from 32 to 64. I know that MT-32 can only play 32 partials, but this workaround actually fixes the missing instruments problem for me. Can be tested for example in Laser Squad intro. I guess the emu isn't freeing partials exactly the same way as original hardware but I have no idea how to fix it properly.
2) Mode 3 reverb is set in source to some gigantic room type which sounds horrible and overflows a lot. In reality it should be "tap delay" reverb and while I have no idea how to set the values to mimic the original device (I don't have a real mt-32), I lowered it for now. Many tunes in games use it - good example is Daemon's Gate title tune - sounds really bad with the previous value.
3) I added simple int16 clipping code for clamping samples into (-32768,32767) range.
4) ProduceOutput1 overflows a lot. Adding clip_int16 here didn't fix the problem so I also increased shift value from 15 to 16. This hack fixed most of the crackling in the playback without reverb.
5) And last change - added clipping of the data returned by reverb code. I think this one is actually correct bugfix as reverb code result was simply cast to 16-bit without any checking for overflows. Well, using lrintf is probably not portable enough, but this is only test patch anyway.
If you want to test it - I recommend using some less popular multi-sound card games, where MT-32 is used for more than just emulating GM device. Good examples are games with sound by Imagitec Design, Krisalis etc. They usually sound really bad with unpatched emulator or at least have crackling problems. My test round was done with the following titles - most had some problems before patch (but not all of them): Daemon's Gate, Bloodwych, Space Crusade, Heimdall, Hero's Quest, The Humans, Ragnarok (King's Table), Laser Squad, Legend, Obitus, Shadowlands, Shadowworlds, Speedball 2, Protostar & Space Wrecked. After patch I can actually enjoy the music - even if it's not exactly the same as on the original hardware 😉
Compiled win32 dosbox version (mingw) - plain today's cvs + mt-32 (without SDL_sound support as I failed to compile it) can be downloaded here (no ROMs included): http://strony.aster.pl/mokmtg/dosbox_mt32.rar
Here is the diff for MT-32 sources (current from scummvm cvs tree):
*** mt32emu.h Sat May 24 16:44:22 2008
--- c:\msys\1.0\home\Maciek\dosbox\src\gui\mt32emu.h Fri Feb 13 21:46:38 2009
***************
*** 36,40 ****
// Configuration
// The maximum number of partials playing simultaneously
! #define MT32EMU_MAX_PARTIALS 32
// The maximum number of notes playing simultaneously per part.
// No point making it more than MT32EMU_MAX_PARTIALS, since each note needs at least one partial.
--- 36,40 ----
// Configuration
// The maximum number of partials playing simultaneously
! #define MT32EMU_MAX_PARTIALS 64
// The maximum number of notes playing simultaneously per part.
// No point making it more than MT32EMU_MAX_PARTIALS, since each note needs at least one partial.
*** synth.cpp Sun Aug 31 00:26:16 2008
--- c:\msys\1.0\home\Maciek\dosbox\src\gui\synth.cpp Fri Feb 13 22:49:42 2009
***************
*** 114,117 ****
--- 114,118 ----
void Synth::printDebug(const char *fmt, ...) {
+ /*
va_list ap;
va_start(ap, fmt);
***************
*** 123,126 ****
--- 124,128 ----
}
va_end(ap);
+ */
}
***************
*** 145,149 ****
break;
case 3:
! reverbModel->setroomsize(1.0f);
reverbModel->setdamp(.75f);
break;
--- 147,151 ----
break;
case 3:
! reverbModel->setroomsize(.5f);
reverbModel->setdamp(.75f);
break;
***************
*** 1111,1114 ****
--- 1113,1126 ----
}
+ static inline Bit16s clip_int16(Bit32s a)
+ {
+ if ((a+32768) & ~65535) {
+ return (a>>31) ^ 32767;
+ } else {
+ return a;
+ }
+ }
+
+
void ProduceOutput1(Bit16s *useBuf, Bit16s *stream, Bit32u len, Bit16s volume) {
#if MT32EMU_USE_MMX > 2
***************
*** 1121,1125 ****
int end = len * 2;
while (end--) {
! *stream = *stream + (Bit16s)(((Bit32s)*useBuf++ * (Bit32s)volume)>>15);
stream++;
}
--- 1133,1137 ----
int end = len * 2;
while (end--) {
! *stream = clip_int16((Bit32s)*stream + (((Bit32s)*useBuf++ * (Bit32s)volume)>>16));
stream++;
}
***************
*** 1159,1166 ****
m=0;
for (unsigned int i = 0; i < len; i++) {
! stream[m] = (Bit16s)(outbufl[i] * 32767.0f);
! m++;
! stream[m] = (Bit16s)(outbufr[i] * 32767.0f);
! m++;
}
for (unsigned int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {
--- 1171,1178 ----
m=0;
for (unsigned int i = 0; i < len; i++) {
! stream[m] = clip_int16(lrintf(outbufl[i] * 32767.0f));
! m++;
! stream[m] = clip_int16(lrintf(outbufr[i] * 32767.0f));
! m++;
}
for (unsigned int i = 0; i < MT32EMU_MAX_PARTIALS; i++) {