Skip to content

VGM structure by simple words (noob's investigation)

Technical discussion which is not directly related to VGM files. Talk about Hardware and Software.

Moderator: Staff

  • SeregaZ Offline
  • Posts: 98
  • Joined: 2015-08-08, 13:56:52

VGM structure by simple words (noob's investigation)

Post by SeregaZ »

becouse i am not understand documentation - only by own experiment and practice - i starting to study some kind of VGM file parse. (it will help in a future)

so... i get vgm2txt and parse few second of song (for this example it was first song from RnR SMD) and open this song in winhex.

as i understand at the begining lay some system info about chips. until to 0x00000040. from this starts song itself info. in this case (i am not sure) song if easy - no have PCM samples. and i think only 1 instrument per channel (Tony Williams - Bad to the Bone)

1. i think this part some kind of "turn off" function to make silence from previus song.

Code: Select all

0x00000040: 52 28 00    YM2612:		Channel 0 Key On/Off: Slot1 Off, Slot2 Off, Slot3 Off, Slot4 Off
0x00000043: 52 28 04    YM2612:		Channel 3 Key On/Off: Slot1 Off, Slot2 Off, Slot3 Off, Slot4 Off
0x00000046: 52 28 01    YM2612:		Channel 1 Key On/Off: Slot1 Off, Slot2 Off, Slot3 Off, Slot4 Off
0x00000049: 52 28 05    YM2612:		Channel 4 Key On/Off: Slot1 Off, Slot2 Off, Slot3 Off, Slot4 Off
0x0000004C: 52 28 02    YM2612:		Channel 2 Key On/Off: Slot1 Off, Slot2 Off, Slot3 Off, Slot4 Off
0x0000004F: 52 28 06    YM2612:		Channel 5 Key On/Off: Slot1 Off, Slot2 Off, Slot3 Off, Slot4 Off
28 - probably it is registry of chip - YM2612: $28 Individual Operator Key On/Off
01-05 - it is value of this $28 regitry
ValleyBell OPN dll equalent command: OPN_Write(0, $28, $01), OPN_Write(0, $28, $02), etc

2. and as i can see later - almost all info in this txt log have 3 bytes. will name it "tripplets". it 2 last value is i am uderstand - what it is first? 52 value? i thought it is some system marker again and used for instrument setting... but then i am see 53 - it is broke my theory. then i remember ValleyBell say for 1-2-3 channel one commands, 4-5-6 need + 255. that is why 53 :) 52 probably it means some kind of "0".

Code: Select all

0x00000067: 52 32 02    YM2612:		Ch 2 Slot 0 Detune: 0, Multiple: Freq * 2.0
0x0000006A: 53 32 00    YM2612:		Ch 5 Slot 0 Detune: 0, Multiple: Freq * 0.5
so that commands still ready to eat for that DLL using. it is nice...

3. and then come some strange part:

Code: Select all

0x000002AD: 52 27 2E    YM2612:		CSM Mode: Disable, 3 Slot Mode: Disable, Enable Timer: -B, Timer IRQ Enable: AB, Reset Timer Status: -B
0x000002B0: 52 40 7F    YM2612:		Ch 0 Slot 0 Total Level: 0x7F = 0%
0x000002B3: 52 44 7F    YM2612:		Ch 0 Slot 1 Total Level: 0x7F = 0%
0x000002B6: 52 48 7F    YM2612:		Ch 0 Slot 2 Total Level: 0x7F = 0%
0x000002B9: 52 4C 7F    YM2612:		Ch 0 Slot 3 Total Level: 0x7F = 0%
0x000002BC: 52 41 7F    YM2612:		Ch 1 Slot 0 Total Level: 0x7F = 0%
0x000002BF: 52 45 7F    YM2612:		Ch 1 Slot 1 Total Level: 0x7F = 0%
0x000002C2: 52 49 7F    YM2612:		Ch 1 Slot 2 Total Level: 0x7F = 0%
0x000002C5: 52 4D 7F    YM2612:		Ch 1 Slot 3 Total Level: 0x7F = 0%
0x000002C8: 52 42 7F    YM2612:		Ch 2 Slot 0 Total Level: 0x7F = 0%
0x000002CB: 52 46 7F    YM2612:		Ch 2 Slot 1 Total Level: 0x7F = 0%
0x000002CE: 52 4A 7F    YM2612:		Ch 2 Slot 2 Total Level: 0x7F = 0%
0x000002D1: 52 4E 7F    YM2612:		Ch 2 Slot 3 Total Level: 0x7F = 0%
0x000002D4: 53 40 7F    YM2612:		Ch 3 Slot 0 Total Level: 0x7F = 0%
0x000002D7: 53 44 7F    YM2612:		Ch 3 Slot 1 Total Level: 0x7F = 0%
0x000002DA: 53 48 7F    YM2612:		Ch 3 Slot 2 Total Level: 0x7F = 0%
0x000002DD: 53 4C 7F    YM2612:		Ch 3 Slot 3 Total Level: 0x7F = 0%
0x000002E0: 53 42 7F    YM2612:		Ch 5 Slot 0 Total Level: 0x7F = 0%
0x000002E3: 53 46 7F    YM2612:		Ch 5 Slot 1 Total Level: 0x7F = 0%
0x000002E6: 53 4A 7F    YM2612:		Ch 5 Slot 2 Total Level: 0x7F = 0%
0x000002E9: 53 4E 7F    YM2612:		Ch 5 Slot 3 Total Level: 0x7F = 0%
0x000002EC: 53 41 7F    YM2612:		Ch 4 Slot 0 Total Level: 0x7F = 0%
0x000002EF: 53 45 7F    YM2612:		Ch 4 Slot 1 Total Level: 0x7F = 0%
0x000002F2: 53 49 7F    YM2612:		Ch 4 Slot 2 Total Level: 0x7F = 0%
0x000002F5: 53 4D 7F    YM2612:		Ch 4 Slot 3 Total Level: 0x7F = 0%
i am understand if it is part of instrument setting for chip... but why this part repeat over and over? probably it is repeat 10-20 times...

4. and this is probably "volume" setting. and it is come to... 0? or 0 it is max volume?

5. and finaly shows notes (i think notes ):

Code: Select all

0x00000C64: 52 A0 68    YM2612:		Ch 0 F-Num (set) LSB = 68
0x00000C67: 52 A5 0B    YM2612:		Ch 1 F-Num (prepare) MSB = 3, Octave 1
0x00000C6A: 52 A1 D3    YM2612:		Ch 1 F-Num (set) LSB = D3
0x00000C6D: 52 A6 03    YM2612:		Ch 2 F-Num (prepare) MSB = 3, Octave 0
0x00000C70: 52 A2 37    YM2612:		Ch 2 F-Num (set) LSB = 37
0x00000C73: 53 A4 13    YM2612:		Ch 3 F-Num (prepare) MSB = 3, Octave 2
0x00000C76: 53 A0 D3    YM2612:		Ch 3 F-Num (set) LSB = D3
0x00000C79: 53 A5 23    YM2612:		Ch 4 F-Num (prepare) MSB = 3, Octave 4
0x00000C7C: 53 A1 D3    YM2612:		Ch 4 F-Num (set) LSB = D3
0x00000C7F: 52 40 7F    YM2612:		Ch 0 Slot 0 Total Level: 0x7F = 0%
0x00000C82: 52 44 7F    YM2612:		Ch 0 Slot 1 Total Level: 0x7F = 0%
0x00000C85: 52 48 7F    YM2612:		Ch 0 Slot 2 Total Level: 0x7F = 0%...
but where is length of notes? :) and then again volume? brain go into simmer...

6. then i see:

Code: Select all

0x00000D78: 61 BF 00    Wait:	191 samples (   4.33 ms)	(total	191 (00:00.00))
61 it is marker? and it means 0?

7. and then catastrophe happen:

Code: Select all

0x00000D87: 77          Wait:	 8 sample(s) (   0.18 ms)	(total	222 (00:00.00))
one byte? it is kill triplet system :) so it must be some rule when reading:
if byte >= 6F read it as 1 byte, else read three bytes. correct? and probably if byte = 66 it is end of music?

8. and how to understand this "wait"? what channel and it is pause, or it is length of note?
  • SeregaZ Offline
  • Posts: 98
  • Joined: 2015-08-08, 13:56:52

Post by SeregaZ »

now i see 61 long pause, 0x7n short pause. but anyway how this pauses work? this pauses must have channel-flag.

it is line of time :) i though every channel must have his own pauses.
  • User avatar
  • MaliceX Offline
  • Posts: 226
  • Joined: 2012-09-29, 11:45:48
  • Location: Australia
  • Contact:

Post by MaliceX »

Nope. It's probably similar to VHDL testbench, where you can assign signals with values simultaneously at a single point in time, and the only way to move forward is to wait.
-dj.tuBIG/MaliceX
  • SeregaZ Offline
  • Posts: 98
  • Joined: 2015-08-08, 13:56:52

Post by SeregaZ »

so on this base of knowledge and DLL of ValleyBell i made some kind of player. and it is play fine if song is unpacked from vgz to vgm, without pcm samples and without PSG. BUT! it some kind of slooooow :(

cpu eat - it is ok. my programm have no microsecunds params. so i need to eat cpu - but problem not in this eating. i set delay(1) - it is minimum without cpu eating - and play same wrong :( maybe it is some wrong command for registers?

***

and later i found it :) it was wrong type of variable :) so time to study PCM...
  • SeregaZ Offline
  • Posts: 98
  • Joined: 2015-08-08, 13:56:52

Post by SeregaZ »

as i can read from doc http://vgmrips.net/wiki/VGM_Specification#Data_blocks
samples starts from 67 command. and probably is it lay as one big pack in size, what is sets as param of this 67 command. 0x67 0x66 tt ss ss ss ss (data)

aaaand how to separate it? and probably in must have some marker for future usind in note-list when starts play this song.
  • ctr Offline
  • Posts: 492
  • Joined: 2013-07-17, 23:32:39

Post by ctr »

The sample position in the datablock is set by the 'a' parameter in 0x93 commands. There's not really a good way to separate samples, due to the way the optimization works (some samples are split up in several parts). But you can try saving all 'a' parameters used in every 0x93 command in the file, then using them as trimming points.
  • SeregaZ Offline
  • Posts: 98
  • Joined: 2015-08-08, 13:56:52

Post by SeregaZ »

you mean (in sega mega drive vgm case) when this data block comes - it have no any separate marker? just lay one by one as one big mixed piece? so i need to get size of this pack, and jump to the end of it, then start parse file, as always... but when i get 93 command - i will get size and adress of individual sample inside this big mixed block?
  • ctr Offline
  • Posts: 492
  • Joined: 2013-07-17, 23:32:39

Post by ctr »

You'll get the address of it. For Project2612 packs, you can get the size by counting 8n commands in the vgm file. For Deflemask/dacopt, the l parameter in the 0x93 commands
  • SeregaZ Offline
  • Posts: 98
  • Joined: 2015-08-08, 13:56:52

Post by SeregaZ »

not understand :)

lets go back to begining:

when i get 0x67 - it mean starts wav samples block. i need to get size of it and jump to end of it.

then after jump and parse far - i can get 0xE0 and 0x8n

0xE0 dddddddd seek to offset dddddddd (Intel byte order) in PCM data bank

0x8n YM2612 port 0 address 2A write from the Data bank, then wait n samples; n can range from 0 to 15. Note that the wait is n, NOT n+1.


it no have 0x93.

temporaly i set to ignore this two commands and file parse is fine. music is play, but some kind of broken drunk tempo.
  • SeregaZ Offline
  • Posts: 98
  • Joined: 2015-08-08, 13:56:52

Post by SeregaZ »

i am think a little... you mean: when i get 0xE0, i need to set marker for read in this dddddddd position inside wav data block, and when i get 0x8n i need to read 1 byte from that adres? and i need to stop read, when get new 0xE0? and this is will be one sample?

but where is frequence for this sample? this song no have frequence command. for example game dune have a few variants of freq of samples. or when ripper make rip from game he make record with one frequence for all samples? (10k+ as max)
  • ctr Offline
  • Posts: 492
  • Joined: 2013-07-17, 23:32:39

Post by ctr »

Yeah, basically. You can get the frequency by counting the amount of DAC commands and VGM samples between the two 0xE0 commands (or EOF)

Code: Select all

double freq = 44100 * (dac_count/delay_sum);
where dac_count is the amount of DAC commands since the beginning of the sample, and delay_sum is the sum of all delays since the beginning of the sample
  • SeregaZ Offline
  • Posts: 98
  • Joined: 2015-08-08, 13:56:52

Post by SeregaZ »

again not understand... ok, freequence it is smallest problem. why now this song have drunk tempo? and where exactly starts play sample? at 0xE0, or at first 0x8n? (i mean when i am play not in chip one byte by one, but by windows full sample at once)

and as i understand this 0x8n have two actions - second is a pause, as 0x7n do? but without +1, correct? probably it can fixed my drunk tempo...

add this pause. not helped... still drunk.

and this commands
OPN_Write(0, $28, $00)
OPN_Write(0, $28, $04)
OPN_Write(0, $28, $01)
OPN_Write(0, $28, $05)
OPN_Write(0, $28, $02)
OPN_Write(0, $28, $06)
is didnt stop sound. as he play last note - this note is playing, until i am not close programm.
  • SeregaZ Offline
  • Posts: 98
  • Joined: 2015-08-08, 13:56:52

Post by SeregaZ »

maybe 0x50 dd PSG (SN76489/SN76496) write value dd ; have pause effect too?

i am make attach. both song without samples. but one have 0x50, another no have. one plays fine, another with drunk tempo, when FM drums start.
Attachments
TESTPLAYVGMMEM.zip
(158.96 KiB) Downloaded 284 times
  • SeregaZ Offline
  • Posts: 98
  • Joined: 2015-08-08, 13:56:52

Post by SeregaZ »

noob's investigation is going to... stuck! no one knows how to set registers of yamaha to sing samples...
  • ctr Offline
  • Posts: 492
  • Joined: 2013-07-17, 23:32:39

Post by ctr »

It might be easier to write a VGM file and use VGMPlay to play it rather than using that DLL, as I don't think that DLL does everything vgmplay does.
Post Reply