VOGONS


First post, by Mok

User metadata
Rank Newbie
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;
+ }
+ }
Show last 37 lines
+ 
+
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++) {

Reply 1 of 4, by Mok

User metadata
Rank Newbie
Rank
Newbie

While playing several midi tunes (each one replaces patches) I noticed that soft-reset of emulated MT-32 doesn't work at all - Sysex F0 41 10 16 12 7F x x ("all parameters reset") is not supported (and possibly can produce bugs as it's accepted as normal write to synth memory). Edit: *the rest is deleted*

Edit: I was wrong. After checking the code more carefully I see that Reset is actually supported. The only problem is that it fails on the too-short sysex msg included with a dos midi player which I tried. Seems it works on the original synth. Change in code will be trivial.

Edit2: Confirmed in the control rom disassembly that real MT-32 does the reset straight after getting 7Fh byte.

Last edited by Mok on 2009-02-16, 18:46. Edited 1 time in total.

Reply 2 of 4, by Mok

User metadata
Rank Newbie
Rank
Newbie

And yet another simple(?) problem. I noticed dos-box sometimes crashes when starting some specific game or playing .mid grabbed from the same game. After some tracing I found out that some sysex messages send incorrect(?) parameters which can make the emulator write outside mt-32 memory buffers. Example below, taken from Shadowlands title tune. The parameter in question is Timbre Group which should be in 0-3 range.

F0 41 10 16 12 05 01 00 02 10 0C 32 0C 00 01 00 1D F7
F0 41 10 16 12 05 01 08 02 11 0C 32 0C 00 01 00 14 F7
F0 41 10 16 12 05 01 10 47 12 00 00 00 00 00 00 11 F7 <- 47h value is wrong
F0 41 10 16 12 05 01 18 47 13 00 00 00 00 00 00 08 F7 <- again
F0 41 10 16 12 05 01 20 47 14 00 00 00 00 00 00 7F F7 <- again
F0 41 10 16 12 08 28 0A 00 00 00 20 26 F7... and so on

Reply 3 of 4, by wd

User metadata
Rank DOSBox Author
Rank
DOSBox Author

Already got some framework set up for testing? Invalid values for a 2-bit
value might either be ignored or masked (&3) which might not be hard to test.

Reply 4 of 4, by Mok

User metadata
Rank Newbie
Rank
Newbie
wd wrote:

Already got some framework set up for testing? Invalid values for a 2-bit
value might either be ignored or masked (&3) which might not be hard to test.

Yep, for now I'm masking the bits for this and the other parameters (as shown in lapc manual) and the crash is gone, but the question is what is the correct way to fix it... Is real synth masking it too? Or maybe it's refusing to accept incorrect patch? Restoring patch to default in case of wrong parameters in another possibility... heh. Shame I don't have a real synth here 🙁

Edit: Ok, I have checked control rom and they have a list of max values for each copied parameter and in case it's too big, they use max value instead.