Skip to content

(YM2612 + SN76489) to YM2610B / YM2608 VGM converter

Technical discussion about the VGM format, and all the software you need to handle VGM files.

Moderator: Staff

  • drr Offline
  • Posts: 10
  • Joined: 2021-03-14, 10:15:59

(YM2612 + SN76489) to YM2610B / YM2608 VGM converter

Post by drr »

As part of a YM2610(B) hardware player project, I’ve made a standalone VGM converter that might be of use to others with OPN-based hardware players. It partially converts YM2612 / SN76489 VGMs to one playable on a YM2610B or YM2608 (plus integrated YM2149). FM/SSG pitches are adjusted based on configurable input / output clocks, so differences in clock should not cause off-key playback. Since it doesn’t account for PSG noise or PCM conversion, the Thunder Force IV soundtrack is a good example to try it with. Other tracks that don't rely on PCM could work as well but I've not tested it extensively.

Understandably there is a restriction on new accounts posting URLs so I can't link the repo or the demo video which shows it working on my hardware player + YM2610B, so I've zipped and attached the Python scripts here. If you search for "YM2610(B) hardware VGM player" on YouTube, you'll see a pair of videos with it.

The conversion sounds about right to me but I don’t have any actual Sega consoles to compare it with. The FM/SSG attenuation pot settings on my board are a guess based on YouTube videos, which could also be masking volume level mismatch, not sure. The chip is clocked at 8MHz in that video to support neo geo properly but the pitch conversion compensates for it.

Some ideas to improve on it would be using ADPCMB and some sort of automatic encoding to fake the PCM DAC channel, and possibly a best-effort noise channel mapping for the PSG->SSG converter but I doubt there's a one size fits all solution to that problem.
Attachments
Hardware player used to test script
Hardware player used to test script
opnb_converter.zip
(10.52 KiB) Downloaded 246 times
ym2612_to_ym2610b_converter.zip
Outdated, has issues discussed below
(9.78 KiB) Downloaded 258 times
Last edited by drr on 2021-04-09, 5:04:41, edited 3 times in total.
  • Yarm Offline
  • Posts: 20
  • Joined: 2016-05-09, 0:19:46
  • Location: England

Post by Yarm »

OMG Ive been doing the exact same thing this weekend!
Got it playing Titan Overdrive II pretty well on a YM2610!
I have used the Delta-T for PCM playback, it only works with the fast call command 0x95 though.
Ive been thinking about ways to translate 0x80 to 0x8F send dac and wait, I have an idea, will work on it this week.
Also to do - is translate the FM clock somehow as my player is 8MHz not the 7.whatever MHz of the Megadrive.
SN to SSG conversion works pretty well apart from when tone + noise is played together then noise has to take on tone volume.

I also made a hardware player using a XC95288XL CPLD and a 4MB RAM!

I'll share the code when Ive done the 2 points above if you're interested, Its in visual basic 2017 though.
Attachments
06 - Evil Destroyer (Stage 1 Boss)_YM2610.vgm
(308.28 KiB) Downloaded 196 times
Overdrive2_YM2610.vgm
(2.03 MiB) Downloaded 201 times
Last edited by Yarm on 2021-03-30, 11:09:56, edited 3 times in total.
  • Yarm Offline
  • Posts: 20
  • Joined: 2016-05-09, 0:19:46
  • Location: England

Post by Yarm »

Ive attached photos of my board, a bit dusty as its been sitting around for about a year.
The bypass caps are on the other side.
Not as nice as yours by the look of it.
Attachments
20210330_093629.jpg
20210330_093546.jpg
  • drr Offline
  • Posts: 10
  • Joined: 2021-03-14, 10:15:59

Post by drr »

Cool that someone else has done something similar thanks for sharing that. The converted file sounds about the same as what I've got here, just the FM clock difference as you mentioned. I attached one that works on my 8MHz setup where it just emits a pair of adjusted FM pitch writes when the whole pitch is known. I suppose you can encode DeltaT over time since the delays between writes are known, just can't do it all upfront in a single command. When I revisit this project I might try your DeltaT solution if you do come up with a clean way to do it

I've got a 1991 chip as well and it's the only one I've got that actually works 100%, fingers crossed it's still got some life left in it since these are a pain to find
Attachments
tf4boss.vgm
(307.4 KiB) Downloaded 188 times
  • Yarm Offline
  • Posts: 20
  • Joined: 2016-05-09, 0:19:46
  • Location: England

Post by Yarm »

Awesome!

I sorted the FM clock translation yesterday, wasn't too hard actually.
I'm just in the middle of writing another program that converts the write dac and wait type of music into one that uses block play.

Edit: I just tried your file and it crashes WinAmp :(
  • drr Offline
  • Posts: 10
  • Joined: 2021-03-14, 10:15:59

Post by drr »

Maybe the converter put something in the header that the Winamp player doesn't like, not sure. Only tried VGM files on my OPM/OPN hardware players lately. I've had to move command data around a bit as some of these tracks start the command stream within the reserved header section which didn't look right. I'd have to double check

edit: I see the issue, YM2610 support was added in a version newer than the original VGM file (after v1.50?). Didn't add backwards compatibility in my own players so explains why I didn't get errors, I'll patch that up when I have a sec
  • User avatar
  • ValleyBell Offline
  • Posts: 4768
  • Joined: 2011-12-01, 20:20:07
  • Location: Germany

Post by ValleyBell »

For reference - the issue is that:
The VGM header specifies "data offset = 0xCC", which means that the actual data begins at offset 0x100 and everything up until that is the VGM header.
And that header area is filled with garbage data. (leftover stuff from the original VGM)

It ends up crashing when trying to read the "VGM extra header", whose offset is placed at 0xBC. And due to it treating VGM commands as header data, the offset is 0x45531945, which is outside of the file. (I forgot a boundary check there - I will fix this soon.)

And even if it wouldn't crash there, it would try to instantiate all chips from RF5C68 to GA20, with clock rates of up to 1 GHz and it would probably take like 1 minute to render 1 second of the VGM.
  • Yarm Offline
  • Posts: 20
  • Joined: 2016-05-09, 0:19:46
  • Location: England

Post by Yarm »

Thanks ValleyBell :)
With my utility if it has to expand the header (if less than 128 bytes) then it zero fills it, and it also re-creates the offset, length, loop and gd3 position.
I dont know what drr's utility is doing because I cant read python.

I got the Megadrive PCM converter actually doing something but its a disaster. My approach was to do 2 passes of the original VGM, on the first pass collect data about when samples were played, then build a table of sample plays and unique samples, and then on a second pass create a new VGM with new individual sample blocks and fast block play commands (and stops).

The approach was the whenever there is a set address 0xE0 then the next write 0x80-0x8F would mark the start of a sample play and the time, file position and address is recorded in a table and for each sample write after an end sample marker is kept until the next 0xE0 and then its taken as the end position and stored in the table along with the start. The number of samples played and the times are used to get the frequency.

I remove all the 0xE0 and 0x80-0x8F commands and change them to 0x70-0x7F (minus 1). The play commands are inserted at the same point as the determined start play from the first pass, and the block play setup is done straight after the data block definition.

This results in samples playing out of time at the wrong pitch with lots of added extra sample being played and its a disaster.
Although it was a very long shot!
  • drr Offline
  • Posts: 10
  • Joined: 2021-03-14, 10:15:59

Post by drr »

Right, the output VGM had the data offset adjusted to allow YM2610B header to be specified but didn’t zero out the leftover junk which caused issues that ValleyBell points out above. It’s more obvious now that I’ve built and run VGMPlay here. Corrected this and a few other problems and updated the zip in OP and my repo.

Attached is a new pair of files which sound OK on both VGMPlay + hardware player. One is Thunder Force IV on 2610B with 8MHz adjustment, another is a Metal Slug 2 track remapped to use less PCM address space. Forgot to call this out in the OP, it’s potentially useful for hardware player with less than 16MB of RAM and the FPGA board I’ve got here has only an 8MB PSRAM chip for samples. Some “MMU” needs to translate the 16MB virtual address space to the smaller physical address space of the RAM. May as well do that in a converter.

Thanks for documenting that PCM converter strategy too. I have a few ideas on how to approach it, will post how it goes when I get to it.

Related news: the spares I thought were lost actually showed up. Question is: do they actually work? I’ll find out after the pins get a good clean and alignment.
Attachments
finally-some-spares.jpg
slug2remapped.zip
(1.1 MiB) Downloaded 184 times
tf4boss.zip
(75.55 KiB) Downloaded 181 times
  • Yarm Offline
  • Posts: 20
  • Joined: 2016-05-09, 0:19:46
  • Location: England

Post by Yarm »

Awesome!
My original FPGA controlled player did the mapping in the FPGA but the CPLD (5V tolerant) on my new version didnt have space for that, so I wrote a remapper last year.
It wasnt as easy as I expected. Also watch out for crossing 1MB boundaries with your samples.

The files sound great, and play in winamp ok.
Don't know whats going on with my hardware player but when I played the Overdrive 2 music the FM part was very very quiet.
I also bought several chips, I know one of them was bad, I'll have to go and find them, not sure if they're all B type though.
  • drr Offline
  • Posts: 10
  • Joined: 2021-03-14, 10:15:59

Post by drr »

The Overdrive demo track posted before is very cool. I should be looking at more demoscene tracks too. Had to deal with the 1MB cross since I’m doing remapping by 64K chunks, wanted to change only the top 8bits of the address and nothing else so had to shuffle some samples around. The B type chips are a headache since it's the risk of them being broken plus the risk of it being rebadged as a "B"!

Made some progress on a crude but hopefully effective PCM converter, attached a VGM with a Mega turrican track. The file is a mess but you get the idea. There’s enough memory I figure so it just encodes a single 44.1KHz sample for the whole track. 1 delay step = 1 sample output for simplicity but can resample. Then the sample generator is easy and only limitation is track length but should fit most VGMs. It drifts towards end of track because it starts playing and doesn’t bother to keep it in sync, doesn’t loop either. Looping section would need a separate sample for itself with this setup. Still on the TODO list.
Attachments
megat.zip
(1.13 MiB) Downloaded 188 times
  • Yarm Offline
  • Posts: 20
  • Joined: 2016-05-09, 0:19:46
  • Location: England

Post by Yarm »

It sounds pretty good.
I suspect because you cant get an integer value for the Delta N from 44100 that's why it drifts.

I have been trying to create a hybrid of our ideas today.
I am converting the DAC channel to a 44100 straight sample but chopping it up based on my determined start and end positions and creating a sample block for every play of a sample which still results in a large file but should be a little smaller.

It worked great on Sonic but on Turrican im getting a horrible buzzing and its creating thousands of blocks.
The buzz is there even in the pure straight DAC recording (without all the block stuff) (im dumping it to another file so i can hear it).

I'm using 0xE0 to get the address and on each 0x80 to 0x8F I'm writing the previous sample value to the recording buffer while the buffer pointer is less than the total play time and then write 1 of the current value. pretty simple.

I added the YM2612 0x2B dac enable flag to stop it processing when it dosen't need to but the buzz is still there.

It has lots of 23 sample writes which creates most of the noise (but not all of it), but I don't hear it when the original file playing in winamp.
What was your approach?
  • drr Offline
  • Posts: 10
  • Joined: 2021-03-14, 10:15:59

Post by drr »

What Turrican track causes the buzzing sounds? Is it the same title track I posted there? I think I am doing the same thing for the DAC writing, for 0x8n, write the sample N times, then any other delay will just output the most recent sample N more times. Haven't done anything for the automatic DAC stream commands yet.

Noticed that having these long running 44.1KHz streams makes it easy to sneak in the PSG noise equivalent. It's not great compared to having a dedicated noise generator but it is noise after all. Not as bad as trying to run a square wave through the ADPCM codec.
  • User avatar
  • ValleyBell Offline
  • Posts: 4768
  • Joined: 2011-12-01, 20:20:07
  • Location: Germany

Post by ValleyBell »

At least for MegaDrive music, most Japanese games use the PSG noise channel in "take frequency from PSG 3" mode.
Thus, they effectively play 2 square waves + 1 noise, thus allowing you to just reduce it to 3 SSG channels.

Anything based on the GEMS driver can use all 4 PSG channels are once. But on the other hand, GEMS-based soundtracks rarely use the PSG.

When you try to dump all DAC data into a separate file, keep in mind that the DAC sample frequency is affected not only by 8x commands, but by 7x commands as well.
EDIT: and command 61/62/63
  • Yarm Offline
  • Posts: 20
  • Joined: 2016-05-09, 0:19:46
  • Location: England

Post by Yarm »

Its the Mega Turrican "02 - Opening Theme" I was testing on.
The uncompressed VGM is 2,013,060 bytes and has a modified date of 10 ‎December ‎2005, ‏‎05:37:50

I wrote a small utility to tell me what commands are in use:

Command 0x4F used 1 times
Command 0x50 used 16204 times
Command 0x52 used 44720 times
Command 0x53 used 4964 times
Command 0x61 used 112 times
Command 0x66 used 1 times
Command 0x67 used 1 times
Command 0x70 used 2112 times
Command 0x71 used 7333 times
Command 0x72 used 16640 times
Command 0x73 used 7273 times
Command 0x74 used 131 times
Command 0x75 used 210 times
Command 0x76 used 189 times
Command 0x77 used 1189 times
Command 0x78 used 1865 times
Command 0x79 used 682 times
Command 0x7A used 336 times
Command 0x7B used 7 times
Command 0x7C used 7 times
Command 0x7D used 9 times
Command 0x7F used 60 times
Command 0x80 used 25434 times
Command 0x81 used 2855 times
Command 0x82 used 167571 times
Command 0x83 used 635784 times
Command 0x84 used 633745 times
Command 0x85 used 2434 times
Command 0x86 used 1927 times
Command 0x87 used 1974 times
Command 0x88 used 875 times
Command 0x89 used 382 times
Command 0x8A used 931 times
Command 0x8B used 79 times
Command 0x8C used 123 times
Command 0x8D used 1118 times
Command 0x8E used 103 times
Command 0x8F used 66 times
Command 0xE0 used 26092 times

Please can you tell me how many times 0xE0 is supposed to be used? 26092 is crazy!
Post Reply