YM2413 producing buggy output - is that even possible?

Page 1/2
| 2

By Bengalack

Paladin (747)

Bengalack's picture

13-01-2022, 22:40

I hope some of you can help me with a workaround or just tell me what I missed...

I get cymbals and hihat playing when it should not (the first percussion sound only, after first sound, we are good). This really puzzled me for a long time, but I have narrowed it down to a VERY simple test case.

My case shows that you get wrong output if you do this:

1. Just play a tune in *non-drum* mode ("9ch") just a short while (This is the important step)
2. Here you are likely to mute chip or reset or whatever, as you are going to start a new tune (it does not matter what you do --this is the crazy part)
3. Play a new tune which plays a percussion instrument, say ... bass drum ("6ch")
4. Hear that hihat and cymbal plays too (possibly all percussion instruments are played) during the first percussion playback/sound

I can reproduce this 100% of the times. Well, based on data from MoonBlaster.

I first noticed this in my game using my own vgm-replayer. As the source of the vgm-recording is MoonBlaster, I moved into MoonBlaster and reproduced the buggy audio there as well.

I have set up a super simple sample for this. I have been using default values in MoonBlaster (1.4), so all you need to do, is to make a tune that is 6 channels, and that plays drum. ONE command only, is needed. That is your full tune for this:

The default drum setup is like this, ie. block 1 is only bass drum:

When you record this in openmsx using vgm_rec, you get super simple output, a small file with a few register writes. Here is the output of a script I made:

(hex-numbers in left margin are: Register-number Value

The vgm-file is here: https://drive.google.com/open?id=1A4zhY9tAa4mGBqyNiF8jhbRhL1...

To show how this sounds, I have made a video using vgmplay by Grauw:
https://youtu.be/-CgK1WDGdpE

What I do here:
1. Kick off a tune that is no-drum, and abort this one.
2. Start our test case. Hear the hithat/cymbal. = NOT OK
3. Re-Start our test case. Heat that bass drum only is played = OK
4. Re-Start our test case. Heat that bass drum only is played = OK
5. Re-Start our test case. Heat that bass drum only is played = OK

BTW: I assume this player resets the chip when it is starting.

BTW, I have also checked this:
* I've added 75-240 extra wait cycles between register writes. Didn't help.
* I tried to avoid percussion as the first commands sent. wait a bit. Didn't help.
* Full reset, or just mute (like MoonBlaster does) produces same result.
* Have used non-default drum frequencies too. Didn't help.
* It happens on real hardware too (a1-wsx)

The only thing that worked, was to set the volume of hithat/cymbal to 1 or 0 (silent)... but that is not ideal (as in MoonBlaster you can only set volume once / up front, so setting them as muted means that you cannot use them later).

Ok, so now I hope someone just tells me, hey, it 2022 - this is old news, the workaround is x,y,z.

How to avoid this?

Login or register to post comments

By jepmsx

Master (253)

jepmsx's picture

14-01-2022, 07:24

I've started to tinker with the OPLL, but I'm still struggling with the FM part.

In the manual it is stated in page 16 that "... Key-ON bits $26, $27,$28 must always be cleared to 0. Slots 13~18 are related with percussion sounds as shown in Table III-9, and data of F Num must input values that match percussion sounds. " . I don't know if it rings a bell.

I also printed the vgm2txt of the opening of the Psycho World and it does something strange regarding the 0x0E register. I copy here a piece:

Quote:

0x00000226: 51 21 00 YM2413: Reg 0x21 Data 0x00
0x00000229: 79 Wait: 10 sample(s) ( 0.23 ms) (total 79536 (00:01.80))
0x0000022A: 51 21 1C YM2413: Reg 0x21 Data 0x1C
0x0000022D: 61 5A 22 Wait: 8794 samples ( 199.41 ms) (total 88330 (00:02.00))
0x00000230: 51 0E 20 YM2413: Reg 0x0E Data 0x20
0x00000233: 7F Wait: 16 sample(s) ( 0.36 ms) (total 88346 (00:02.00))
0x00000234: 74 Wait: 5 sample(s) ( 0.11 ms) (total 88351 (00:02.00))
0x00000235: 51 38 44 YM2413: Reg 0x38 Data 0x44
0x00000238: 71 Wait: 2 sample(s) ( 0.05 ms) (total 88353 (00:02.00))
0x00000239: 51 0E 31 YM2413: Reg 0x0E Data 0x31
0x0000023C: 61 21 00 Wait: 33 samples ( 0.75 ms) (total 88386 (00:02.00))
0x0000023F: 51 21 00 YM2413: Reg 0x21 Data 0x00
0x00000242: 72 Wait: 3 sample(s) ( 0.07 ms) (total 88389 (00:02.00))
0x00000243: 51 11 C0 YM2413: Reg 0x11 Data 0xC0
0x00000246: 76 Wait: 7 sample(s) ( 0.16 ms) (total 88396 (00:02.00))
0x00000247: 51 21 1C YM2413: Reg 0x21 Data 0x1C
0x0000024A: 61 5A 22 Wait: 8794 samples ( 199.41 ms) (total 97190 (00:02.20))
0x0000024D: 51 21 00 YM2413: Reg 0x21 Data 0x00
0x00000250: 71 Wait: 2 sample(s) ( 0.05 ms) (total 97192 (00:02.20))
0x00000251: 51 11 AB YM2413: Reg 0x11 Data 0xAB
0x00000254: 77 Wait: 8 sample(s) ( 0.18 ms) (total 97200 (00:02.20))
0x00000255: 51 21 1C YM2413: Reg 0x21 Data 0x1C
0x00000258: 7B Wait: 12 sample(s) ( 0.27 ms) (total 97212 (00:02.20))
0x00000259: 51 20 00 YM2413: Reg 0x20 Data 0x00
0x0000025C: 71 Wait: 2 sample(s) ( 0.05 ms) (total 97214 (00:02.20))
0x0000025D: 51 10 01 YM2413: Reg 0x10 Data 0x01
0x00000260: 77 Wait: 8 sample(s) ( 0.18 ms) (total 97222 (00:02.20))
0x00000261: 51 20 1D YM2413: Reg 0x20 Data 0x1D
0x00000264: 61 44 22 Wait: 8772 samples ( 198.91 ms) (total 105994 (00:02.40))
0x00000267: 51 0E 20 YM2413: Reg 0x0E Data 0x20
0x0000026A: 7D Wait: 14 sample(s) ( 0.32 ms) (total 106008 (00:02.40))
0x0000026B: 51 37 41 YM2413: Reg 0x37 Data 0x41
0x0000026E: 78 Wait: 9 sample(s) ( 0.20 ms) (total 106017 (00:02.40))
0x0000026F: 51 0E 39 YM2413: Reg 0x0E Data 0x39
0x00000272: 61 21 00 Wait: 33 samples ( 0.75 ms) (total 106050 (00:02.40))
0x00000275: 51 21 00 YM2413: Reg 0x21 Data 0x00
0x00000278: 79 Wait: 10 sample(s) ( 0.23 ms) (total 106060 (00:02.40))
0x00000279: 51 21 1E YM2413: Reg 0x21 Data 0x1E
0x0000027C: 61 5A 22 Wait: 8794 samples ( 199.41 ms) (total 114854 (00:02.60))
0x0000027F: 51 21 00 YM2413: Reg 0x21 Data 0x00
0x00000282: 79 Wait: 10 sample(s) ( 0.23 ms) (total 114864 (00:02.60))
0x00000283: 51 21 1C YM2413: Reg 0x21 Data 0x1C
0x00000286: 7B Wait: 12 sample(s) ( 0.27 ms) (total 114876 (00:02.60))
0x00000287: 51 20 00 YM2413: Reg 0x20 Data 0x00
0x0000028A: 71 Wait: 2 sample(s) ( 0.05 ms) (total 114878 (00:02.60))
0x0000028B: 51 10 E5 YM2413: Reg 0x10 Data 0xE5
0x0000028E: 77 Wait: 8 sample(s) ( 0.18 ms) (total 114886 (00:02.60))
0x0000028F: 51 20 1C YM2413: Reg 0x20 Data 0x1C
0x00000292: 61 44 0B Wait: 2884 samples ( 65.40 ms) (total 117770 (00:02.67))
0x00000295: 51 0E 20 YM2413: Reg 0x0E Data 0x20
0x00000298: 7F Wait: 16 sample(s) ( 0.36 ms) (total 117786 (00:02.67))
0x00000299: 76 Wait: 7 sample(s) ( 0.16 ms) (total 117793 (00:02.67))
0x0000029A: 51 0E 39 YM2413: Reg 0x0E Data 0x39
0x0000029D: 61 05 17 Wait: 5893 samples ( 133.63 ms) (total 123686 (00:02.80))

It looks like before changing any value it writes 0x20 to register 0x0E

By Bengalack

Paladin (747)

Bengalack's picture

14-01-2022, 08:57

jepmsx wrote:

I've started to tinker with the OPLL, but I'm still struggling with the FM part.

Thanks for replying jepmsx! Great to hear that there are more of us Smile This way we can figure this one out. I'm sure.

jepmsx wrote:

In the manual it is stated in page 16 that "... Key-ON bits $26, $27,$28 must always be cleared to 0. Slots 13~18 are related with percussion sounds as shown in Table III-9, and data of F Num must input values that match percussion sounds. " . I don't know if it rings a bell.

Grauw pointed this out in another thread too. From what I can see, this is in place from the Moonblaster reg-write generation.

jepmsx wrote:

I also printed the vgm2txt of the opening of the Psycho World and it does something strange regarding the 0x0E register. I copy here a piece:
...
It looks like before changing any value it writes 0x20 to register 0x0E

Very good point - look to what other players have done!

I grabbed your vgm-file from vgmrips and started to do some analysing. They do things differently than MoonBlaster. Moonblaster sets the volume of rhythm instruments once, and never touches it again. Psycho sets rhythm instrument volume in, like, 30% of the cases where an r-instr is played. Just before the command for playing an r-instr. Also, Psycho consequently enables drum-mode (but all 5 r-instr are disabled) before setting volume on them, this is "0e 20". That said, psycho always do a plain

0e 20

before playing the r-instr in cases where there are no volume-changes, like:

0e 20
0e 31
(enable drums. and then: play Bass drum + hihat)

Moonblaster does this differently, in the latter example, Moonblaster would have set:

0e 11
0e 31
(disable drums: set Bass drum + hihat, and then: play Bass drum + hihat)

Maybe developers of Psycho World had some other documentation at hand, which stated other things than our documentation?

After a good nights sleep, my idea for a workaround, is to put more stuff into my conversion script. I parse the vgm to be able to play it in my game anyway, so, *maybe* an idea like this can work (this is injecting new register writes into the vgm-stream):

1. At the beginning, set volume for all r-instruments to lowest/muted
2. As soon as I detect playing of an r-instrument, I set the correct volume for this r-instrument only
3. Do point 2 until all r-instruments have their volume set. Or potentially always set volume before playing. (Or even set to low/mute again - need to test around)

I will to look more into this later this evening, need to get to work now Smile

By Bengalack

Paladin (747)

Bengalack's picture

15-01-2022, 08:04

Seems like this is an edge-case people know nothing about?

Anyways, I have a workaround that works for me.

My need is to use vgm-data in a game, and as I parse these data and convert them anyway, I can modify the data during this process.

The fix is to cling to the fact that the artifact did not occur if you make sure the volume for the rhythm-instruments that you are not using, is set to 0xF (=lowest, silent). We can call it "JIT" - Just In Time Smile

Parse the stream:
1. When the MoonBlaster stream sets the volume info at the start of the stream, note those values, but replace with 0xF/silent
2. For the rest of the stream: When a rhythm instrument is in use for the first time: inject/set its correct volume.

@jepmsx: I played around with the "0e 20" variant that Psycho uses. It came me undesired results, when I played around with the example vgm in this test case. The MB-variant came out as correct.

Last words: If someone could modify the code in MoonBlaster to output register writes, to avoid this artifact in the first place -- that would be the real fix.

By sdsnatcher73

Prophet (3951)

sdsnatcher73's picture

15-01-2022, 08:49

I think it would make sense to fix this in all replayers of MoonBlaster files, so at least MBMPLAY and ROBOPLAY come to mind.

By Bengalack

Paladin (747)

Bengalack's picture

15-01-2022, 16:01

I found that the vgm-file wasn't immedediately accessible to everyone - this is fixed now.

sdsnatcher73 wrote:

I think it would make sense to fix this in all replayers of MoonBlaster files, so at least MBMPLAY and ROBOPLAY come to mind.

Totally agree.

I have reproduced this inside MoonBlaster (like, press 'F1'). I do not know if someone has been aware of this and fixed it in MBMPLAY (but I assume not), I have not tested. I haven't tested Roboplay either.

My current approach/remedy is a workaround. Would be great to figure out what the core of the problem is, this way a more elegant solution could be used.

I find this thing so odd, I'm considering posting something on the SMS-forums as well oO

By Bengalack

Paladin (747)

Bengalack's picture

15-01-2022, 20:18

Bengalack wrote:

1. Just play a tune in *non-drum* mode ("9ch") just a short while (This is the important step)

Not sure if this is an important piece of information, but every 9-channel tune I have been using for this purpose, has been vgms generated from MoonBlaster.

By Grauw

Ascended (10768)

Grauw's picture

15-01-2022, 21:00

Bengalack wrote:

The vgm-file is here: https://drive.google.com/open?id=1A4zhY9tAa4mGBqyNiF8jhbRhL1...

To show how this sounds, I have made a video using vgmplay by Grauw:
https://youtu.be/-CgK1WDGdpE

Dump of the VGM data (short waits removed for readability):

0x00000100: 51 30 10    YM2413:		Reg 0x30 Data 0x10
0x00000106: 51 31 10    YM2413:		Reg 0x31 Data 0x10
0x0000010C: 51 32 10    YM2413:		Reg 0x32 Data 0x10
0x00000112: 51 33 10    YM2413:		Reg 0x33 Data 0x10
0x00000118: 51 34 10    YM2413:		Reg 0x34 Data 0x10
0x0000011E: 51 35 10    YM2413:		Reg 0x35 Data 0x10
0x00000124: 51 0E 00    YM2413:		Reg 0x0E Data 0x00
0x0000012A: 51 36 00    YM2413:		Reg 0x36 Data 0x00
0x00000130: 51 37 42    YM2413:		Reg 0x37 Data 0x42
0x00000136: 51 38 24    YM2413:		Reg 0x38 Data 0x24
0x0000013C: 51 16 20    YM2413:		Reg 0x16 Data 0x20
0x00000142: 51 26 05    YM2413:		Reg 0x26 Data 0x05
0x00000148: 51 17 50    YM2413:		Reg 0x17 Data 0x50
0x0000014E: 51 27 05    YM2413:		Reg 0x27 Data 0x05
0x00000154: 51 18 C0    YM2413:		Reg 0x18 Data 0xC0
0x0000015A: 51 28 01    YM2413:		Reg 0x28 Data 0x01
0x00000160: 51 0E 10    YM2413:		Reg 0x0E Data 0x10
0x00000166: 51 0E 30    YM2413:		Reg 0x0E Data 0x30
0x00000169: 61 FF FF    Wait:	65535 samples (   1486.05 ms)	(total	67574 (00:01.53))
0x0000016C: 61 D1 10    Wait:	4305 samples (   97.62 ms)	(total	71879 (00:01.63))
0x0000016F: 51 10 00    YM2413:		Reg 0x10 Data 0x00
0x00000175: 51 20 00    YM2413:		Reg 0x20 Data 0x00
0x0000017B: 51 11 00    YM2413:		Reg 0x11 Data 0x00
0x00000181: 51 21 00    YM2413:		Reg 0x21 Data 0x00
0x00000187: 51 12 00    YM2413:		Reg 0x12 Data 0x00
0x0000018D: 51 22 00    YM2413:		Reg 0x22 Data 0x00
0x00000193: 51 13 00    YM2413:		Reg 0x13 Data 0x00
0x00000199: 51 23 00    YM2413:		Reg 0x23 Data 0x00
0x0000019F: 51 14 00    YM2413:		Reg 0x14 Data 0x00
0x000001A5: 51 24 00    YM2413:		Reg 0x24 Data 0x00
0x000001AB: 51 15 00    YM2413:		Reg 0x15 Data 0x00
0x000001B1: 51 25 00    YM2413:		Reg 0x25 Data 0x00
0x000001B7: 51 16 00    YM2413:		Reg 0x16 Data 0x00
0x000001BD: 51 26 00    YM2413:		Reg 0x26 Data 0x00
0x000001C3: 51 17 00    YM2413:		Reg 0x17 Data 0x00
0x000001C9: 51 27 00    YM2413:		Reg 0x27 Data 0x00
0x000001CF: 51 18 00    YM2413:		Reg 0x18 Data 0x00
0x000001D5: 51 28 00    YM2413:		Reg 0x28 Data 0x00

The thing here that seems strange to me is that register 0EH is set to 10H before it is set to 30H. Bit 5 is the Rhythm Enable (RE) bit, bit 4 the BD bit. It doesn’t make sense to me to do key-on for the base drum before the rhythm mode is enabled.

From my understanding you should enable Rhythm mode first by writing 20H to register 0EH, and then keep that bit 5 set for as long as you intend to the rhythm configuration.

After that you should flip the key-on bits for each of the drums from 0 to 1 every time you want to play a drum sound. This is why Psycho World writes 20H to register 0EH regularly. In order to trigger a drum sound its key-on bit needs to go from 0 to 1, so you need to write a 0 in-between.

I don’t know what the rest of the MoonBlaster output looks like if you would play another BD hit, but it almost looks to me like they think the Rhythm register works such that bit 5 specifies key-on or key-off, and bits 0-4 specify which drums are affected by it. That would explain why they write 10H (“key-off BD”) and then 30H (“key-on BD”), except that’s not at all how it works.

By Grauw

Ascended (10768)

Grauw's picture

15-01-2022, 21:16

Grauw wrote:

I don’t know what the rest of the MoonBlaster output looks like if you would play another BD hit, but it almost looks to me like they think the Rhythm register works such that bit 5 specifies key-on or key-off, and bits 0-4 specify which drums are affected by it. That would explain why they write 10H (“key-off BD”) and then 30H (“key-on BD”), except that’s not at all how it works.

Yep, that seems to be how the Moonsoft thought the OPL rhythm register works:

	ld	a,c
	and	011111b
	ld	c,0eh
	call	fpcout
	set	5,a
	jp	fpcout

For every drum step, they first output the drum key-on bits with bit 5 (Rhythm Enable) set to 0, then output them again with bit 5 set to 1. I guess the intention is to trigger key-on, however the mechanism is interpreted completely wrong. Instead they should output 20H first to key-off all drums. That it still works seems only by chance, as they are rapidly disabling and then re-enabling the drums section every time a drum is played.

Though I can’t explain yet how this would trigger other drum sounds as a by-product.

By Bengalack

Paladin (747)

Bengalack's picture

15-01-2022, 21:20

Thanks for follow-up on this Grauw!

Grauw wrote:

The thing here that seems strange to me is that register 0EH is set to 10H before it is set to 30H. Bit 5 is the Rhythm Enable (RE) bit, bit 4 the BD bit. It doesn’t make sense to me to do key-on for the base drum before the rhythm mode is enabled.

Agree.

Grauw wrote:

From my understanding you should enable Rhythm mode first by writing 20H to register 0EH, and then keep that bit 5 set for as long as you intend to the rhythm configuration.

After that you should flip the key-on bits for each of the drums from 0 to 1 every time you want to play a drum sound. This is why Psycho World writes 20H to register 0EH regularly. In order to trigger a drum sound its key-on bit needs to go from 0 to 1, so you need to write a 0 in-between.

If understand you correctly, I can just use a hex editor, and swap that 0x10 with a 0x20, and test? If so, I thought of that and tested that, but the cymbal is still there.

Grauw wrote:

I don’t know what the rest of the MoonBlaster output looks like if you would play another BD hit, but it almost looks to me like they think the Rhythm register works such that bit 5 specifies key-on or key-off, and bits 0-4 specify which drums are affected by it. That would explain why they write 10H (“key-off BD”) and then 30H (“key-on BD”), except that’s not at all how it works.

MoonBlaster does this consequently throughout the full tune, I just isolated it for a simple testcase.

So... before we get someone to fix MoonBlaster I think I need to get this super simple testcase to work first Smile

By Grauw

Ascended (10768)

Grauw's picture

15-01-2022, 21:25

Maybe the way MoonBlaster uses the rhythm register is unrelated to the cymbal thing. I’ll think about that some more. But either way it’s definitely wrong, and surprising that nobody has noticed this after so many years of use.

You can also check the FM-BIOS OPLDRV code;

Initialise rhythm mode:
https://sourceforge.net/p/msxsyssrc/git/ci/master/tree/music...

Trigger a drum sound:
https://sourceforge.net/p/msxsyssrc/git/ci/master/tree/music...

Page 1/2
| 2