Difference between revisions of "UserWiki:SynaMax"

From Video Game Music Preservation Foundation Wiki
Jump to: navigation, search
(Fairlight CMI *.RS File Structure)
(Snatcher (Sega CD) Music Driver)
 
(32 intermediate revisions by the same user not shown)
Line 1: Line 1:
 +
==Fairlight CMI - Important Memory Maps==
 +
 +
===Page T===
 +
 +
Page T's table is split up into three sections: Register, Stroke and Channel.  Register starts at 0x7A80, Stroke starts at 0x7B00, and Channel starts at 0x7B80.
 +
 +
{| class="wikitable"
 +
! Offset
 +
! Size
 +
! Description
 +
! Notes
 +
|-
 +
| 0x7A80 || 0x10 || <center>'''Register File'''</center> || Unknown; shows up in the Page T debug menu.
 +
|-
 +
| 0x7B00 || 0x10 || <center>'''Stroke Key'''</center> || Unknown; shows up in the Page T debug menu.
 +
|-
 +
| 0x7B80 || 0x10 || <center>'''Channel G. IN'''</center> || Unknown; shows up in the Page T debug menu.
 +
|-
 +
| 0x7B90 || 0x10 || <center>'''Channel G. PT'''</center> || Unknown; shows up in the Page T debug menu.
 +
|-
 +
| 0x7BD0 || 0x10 || <center>'''Channel Mode (first byte) / Channel State (second byte)'''</center> || Unknown; shows up in the Page T debug menu.
 +
|-
 +
|}
 +
 +
 +
===Page Status / Command Line===
 +
{| class="wikitable"
 +
! Offset
 +
! Size
 +
! Description
 +
! Notes
 +
|-
 +
| 0x7E10 || 0x38 || <center>'''Page Status'''</center> || Displays the page name or any important messages
 +
|-
 +
| 0x7E48 || 0x38 || <center>'''Command Line'''</center>  || Commands are typed in here.  Always starts with the cursor character (0x1A).  The very last byte is always a space (0x20), because that is the character limit.
 +
|-
 +
|}
 +
 +
==Fairlight CMI *.IN File Structure==
 +
 +
===0x200: Voice Chunk===
 +
 +
{| class="wikitable"
 +
! Offset
 +
! Size
 +
! Description
 +
! Notes
 +
|-
 +
| 0x0 || 0x1 || <center>'''Start of Voice'''</center> || Always 0x31
 +
|-
 +
| 0x2 || 0x8 || <center>'''Voice Filename'''</center>  || Always 0x8 long.  If name is shorter than 8 characters, remaining characters are spaces (0x20)
 +
|-
 +
| 0x9 || 0x2 || <center>'''Voice File Extention'''</center>  || Always "VC" (0x5643)
 +
|-
 +
|}
 +
 +
 
==Fairlight CMI *.RS File Structure==
 
==Fairlight CMI *.RS File Structure==
  
Line 7: Line 64:
 
! Notes
 
! Notes
 
|-
 
|-
| 0x00 || 0x2 || Version/Revision || Always 0x0102
+
| 0x0 || 0x2 || <center>'''Version/Revision'''</center> || Always 0x0102
 +
|-
 +
| 0x2 || 0x2 || <center>'''Speed'''</center>  || 0xA3A = 2618 = 120 BPM.  To get the BPM, divide 314160 by the song's speed value (314160/2618 = 120).  To get the speed value, divide 314160 by the song's BPM (314160/120 = 2618)
 +
|-
 +
| 0x4 || 0x2 || <center>'''Global Time Signature'''</center>  || For example: 0x0404 = 4/4; 0x0608 = 6/8.  This will be the time signature for any blank patterns.  Any pattern that has data in it, will override this time signature
 +
|-
 +
| 0x6 || 0x2 || <center>'''Sync Flag'''</center>  || 0x0000 = INT; 0x0001 = EXT
 +
|-
 +
| 0x80 || 0xFF || <center>'''Patterns Used Index Chunk'''</center>  || Seems that any value (as long as it's not more than or equal to the patterns used total) will work.
 +
|-
 +
| 0x17F || 0x1 || <center>''unknown''</center>  ||
 +
|-
 +
| 0x180 || 0xFF || <center>''unknown''</center>  || This looks like a duplicate of the Patterns Used Index Chunk, except every value is a 1.  When loaded in the CMI's memory, this area was zeroed out.  Possibly unused?
 
|-
 
|-
| 0x02 || 0x2 || Speed || 0xA3A = 2618 = 120 BPM.  To get the BPM, divide 314160 by the song's speed value (314160/2618 = 120).  To get the speed value, divide 314160 by the song's BPM (314160/120 = 2618)
+
| 0x27F || 0x1 || <center>''unknown''</center> ||
 
|-
 
|-
| 0x04 || 0x2 || Global Time Signature || For example: 0x0404 = 4/4; 0x0608 = 6/8. This will be the time signature for any blank patterns.  Any pattern that has data in it, will override this time signature
+
| 0x280 || 0x1FE || <center>'''Song Step Index Chunk'''</center> || Every word is a step, first byte is the pattern number, second byte is how many repeats.  For example, 0x0106 = play pattern 1, 6 times. As soon as the sequencer sees the first zeroed byte in the index, all other bytes after that are ignored.
 
|-
 
|-
| 0x06 || 0x2 || Sync Flag  || 0x0000 = INT; 0x0001 = EXT
+
| 0x47E || 0x2 || <center>''Padding (unused)''</center> || An extra two bytes of 0x0001 pad out this chunk to make it 200-bytes long.
 
|-
 
|-
| 0x80 || 0x80 || Patterns Used Index Chunk  || Seems that any value (as long as it's not more than or equal to the patterns used total) will work.  
+
| 0x480 || 0x1D2 || <center>'''Section Step Index Chunk'''</center> || Every word is a step, first byte is the pattern number, second byte is how many repeats.  For example, 0x0106 = play pattern 1, 6 times. As soon as the sequencer sees the first zeroed byte in the index, all other bytes after that are ignored.
 
|-
 
|-
| 0x280 || 0x80 || Song Step Index Chunk  || Every word is a step, first byte is the pattern number, second byte is how many repeats.  For example, 0x0106 = play pattern 1, 6 times. As soon as the sequencer sees the first zeroed byte in the index, all other bytes after that are ignored.
+
| 0x652 || 0x2E || <center>''Padding (unused)''</center> || An extra set 0x0001 words pad out this chunk to make it 200-bytes long.
 
|-
 
|-
| 0x680 || 0x80 || "E5" Chunk?  || For some reason at offset 0x680, there is a chunk that is usually filled with 0xE5, or just zeroed out.
+
| 0x680 || 0x80 || <center>"E5" Chunk?</center> || For some reason at offset 0x680, there is a chunk that is usually filled with 0xE5, or just zeroed out.
 
|-
 
|-
 
|}
 
|}
Line 28: Line 97:
  
 
The highest bit of the second byte determines if the previous byte is a pattern number or a section letter.  For example, the value 0x4D can be either the decimal number "77", or the section letter "M".  0x4D01 means that pattern 77 will play once.  0x4D00 means the pattern 77 will play forever and 0x4D86 means that the sequencer will play section "M" 6 times.  This is why we can't repeat patterns or sections more than 127 times.
 
The highest bit of the second byte determines if the previous byte is a pattern number or a section letter.  For example, the value 0x4D can be either the decimal number "77", or the section letter "M".  0x4D01 means that pattern 77 will play once.  0x4D00 means the pattern 77 will play forever and 0x4D86 means that the sequencer will play section "M" 6 times.  This is why we can't repeat patterns or sections more than 127 times.
 +
 +
As soon as the sequencer encounters a zero where a pattern number should be, then the sequencer ignores all the remaining bytes (even ones that have valid data in them) and places an end marker denoting that the song is finished.
 +
 +
===Section Step Index Chunk===
 +
 +
This chunk is very similar to the Step Index chunk.  Every word contains the values for the pattern number or section letter, as well as the play count for the step and the section letter flag.
 +
 +
===Pattern Chunk===
 +
 +
The first pattern for the song is located at offset 0x700 in the file.  Each pattern is 0x680 bytes long.  The CMI's memory can only hold up to 8 patterns (0x3400 bytes), so a buffer table is used to point to the last 8 previously loaded patterns.
 +
 +
====Header====
 +
{| class="wikitable"
 +
! Offset
 +
! Size
 +
! Description
 +
! Notes
 +
|-
 +
| 0x0 || 0x2 || <center>'''Time Signature'''</center> || Overrides the global time signature in the header.
 +
|-
 +
| 0x2 || 0x2 || <center>''Speed?''</center> ||
 +
|-
 +
| 0x4 || 0x2 || <center>''ubeats per count?''</center> ||
 +
|-
 +
| 0x6 || 0x1 || <center>''ubeats per division?''</center> ||
 +
|-
 +
| 0x7 || 0x1 || <center>''divisions per count?''</center> ||
 +
|-
 +
| 0x8 || 0x1 || <center>''divisions per pattern?''</center> ||
 +
|-
 +
| 0x9 || 0x1 || <center>''PPQ?''</center> ||
 +
|-
 +
| 0xA || 0x1 || <center>''unused''</center> ||
 +
|-
 +
| 0xB || 0x2 || <center>''pointer back to buffer table (2 bytes)?''</center> ||
 +
|-
 +
| 0x68 || 0x10 || <center>'''Comment'''</center> || 16-character string used for comments
 +
|-
 +
| 0x78 || 0x08 || <center>''Padding''</center> ||
 +
|-
 +
| 0x80 || 0xC0 || <center>'''Note Data for Keyboard 1'''</center> ||
 +
|-
 +
| 0x140 || 0xC0 || <center>'''Note Data for Keyboard 2'''</center> ||
 +
|-
 +
| 0x200 || 0xC0 || <center>'''Note Data for Keyboard 3'''</center> ||
 +
|-
 +
| 0x2C0 || 0xC0 || <center>'''Note Data for Keyboard 4'''</center> ||
 +
|-
 +
| 0x380 || 0xC0 || <center>'''Note Data for Keyboard 5'''</center> ||
 +
|-
 +
| 0x440 || 0xC0 || <center>'''Note Data for Keyboard 6'''</center> ||
 +
|-
 +
| 0x500 || 0xC0 || <center>'''Note Data for Keyboard 7'''</center> ||
 +
|-
 +
| 0x5C0 || 0xC0 || <center>'''Note Data for Keyboard 8'''</center> ||
 +
|-
 +
|}
 +
 +
====Note Data====
 +
 +
Notes are represented in two bytes.  Specific bits are assigned to three different parameters, '''Key''' (Pitch), '''Vel''' (Velocity), and '''Dur''' (Duration).
 +
 +
The range of Key are from note F1 to F7.  Duration goes from 0 to 48, and Velocity goes from 1 to 8.
 +
 +
{| class="wikitable"
 +
! D15
 +
! D14
 +
! D13
 +
! D12
 +
! D11
 +
! D10
 +
! D9
 +
! D8
 +
! D7
 +
! D6
 +
! D5
 +
! D4
 +
! D3
 +
! D2
 +
! D1
 +
! D0
 +
|-
 +
| colspan="7" style="text-align: center;" | Key
 +
| colspan="6" style="text-align: center;" | Dur
 +
| colspan="3" style="text-align: center;" | Vel
 +
|}
 +
 +
Velocity is different from the other two parameters as it's value is inverted. So 0x0 = 8, 0x1 = 7, etc.
 +
 +
The maximum amount of notes per keyboard per pattern is 48.  The maximum amount of notes per pattern is 384 (48 notes x 8 keyboards).  To pad out the pattern, between every 48th note is a zeroed out word.  So, for example, we have several sequential 48th notes at Key C4, Vel 8, Dur 2 (0x5810).  They appear in the code as this: <tt>58 10 00 00 58 10 00 00 58 10 00 00 58 10 00 00</tt>, etc.
  
 
==MegaRace HERAD "DFADP.HSQ" Driver==
 
==MegaRace HERAD "DFADP.HSQ" Driver==
Line 306: Line 465:
 
| 0x8 || 0x8 || AW filename absolute offset || Points to the name of the AW file.  AW files contain all the ADPCM sample data.
 
| 0x8 || 0x8 || AW filename absolute offset || Points to the name of the AW file.  AW files contain all the ADPCM sample data.
 
|}
 
|}
 +
 +
==E-MU EXB File Structure==
 +
 +
===E4B===
 +
 +
====E4B Header====
 +
 +
Length is 0x20 and uses regular strings for preset names
 +
 +
{| class="wikitable"
 +
! Offset
 +
! Size
 +
! Description
 +
! Notes
 +
|-
 +
| 0x0 || 0x4 || "FORM" || Header
 +
|-
 +
| 0x4 || 0x4 || File size || Size of entire file
 +
|-
 +
| 0x8 || 0x8 || E4B0TOC1 || Table of Content v1
 +
|-
 +
| 0x10 || 0x4 || Table Size || Length of TOC
 +
|}
 +
 +
====E4P1 (Preset Data)====
 +
 +
{| class="wikitable"
 +
! Offset
 +
! Size
 +
! Description
 +
! Notes
 +
|-
 +
| 0x0 || 0x4 || "E4P1" || Header
 +
|-
 +
| 0x4 || 0x4 || Size after header (filesize minus 8 bytes) ||
 +
|-
 +
| 0x8 || 0x2 || Preset Number ||
 +
|-
 +
| 0xA || 0x10 || Preset name ||
 +
|-
 +
| 0x5C || 0x2 || Layer Chunk size ||
 +
|}
 +
 +
===E5B/EXB===
 +
 +
====E5B Header====
 +
 +
Length is 0x4E and uses array of zero-terminated UTF-16 Unicode strings
 +
 +
{| class="wikitable"
 +
! Offset
 +
! Size
 +
! Description
 +
! Notes
 +
|-
 +
| 0x0 || 0x4 || "FORM" || Header
 +
|-
 +
| 0x4 || 0x4 || File size || Size of entire file?
 +
|-
 +
| 0x8 || 0x8 || E5B0TOC2 || Table of Content v2
 +
|-
 +
| 0x10 || 0x4 || Table Size || Length of TOC
 +
|}
 +
 +
====E5P1 (Preset Data)====
 +
 +
{| class="wikitable"
 +
! Offset
 +
! Size
 +
! Description
 +
! Notes
 +
|-
 +
| 0x0 || 0x4 || "E5P1" || E-MU Preset Header
 +
|-
 +
| 0x4 || 0x4 || unknown ||?
 +
|-
 +
| 0x8 || 0x4 || Start of Preset Data || Points to offset of preset data
 +
|-
 +
| 0xC || 0x2 || Preset number ||
 +
|-
 +
| 0xE || 0x40 || Preset name / padding || zero-terminated UTF-16 Unicode string with zero padding ("a.m.b.:.A.i.o.o.n. .P.a.d.")
 +
|}
 +
 +
====E5ZLZhdr chunk====
 +
 +
This is where the Samplepool ID for the preset is stored.
 +
 +
{| class="wikitable"
 +
! Offset
 +
! Size
 +
! Description
 +
! Notes
 +
|-
 +
| 0x0 || 0x4 || "LIST" || Header
 +
|-
 +
| 0x4 || 0x4 || Chunk size || Size of chunk after header
 +
|-
 +
| 0x8 || 0x8 || E5ZLZhdr || Magic
 +
|-
 +
| 0x10 || 0x4 || Chunk size || Size of chunk after header
 +
|-
 +
| 0x14 || 0x4 || unknown || (seems to always be 0x2)
 +
|-
 +
| 0x18 || 0x2 || Samplepool ID || Sample ID number
 +
|}
 +
 +
==E-MU Proteus 2000 ROM File Structure==
 +
 +
 +
 +
===yh_1 (ROM Header)===
 +
 +
{| class="wikitable"
 +
! Offset
 +
! Size
 +
! Description
 +
! Notes
 +
|-
 +
| 0x0 || 0x4 || "yh_1" || Header
 +
|-
 +
| 0x4 || 0x4 || Chunk size || Size of entire chunk including header (seems to be always 0xC8)
 +
|-
 +
| 0xF || 0x1 || unknown || Seems to be the same last byte that's used to terminate chunks
 +
|-
 +
| 0x10 || 0x20 || Padding || always zero
 +
|-
 +
| 0x30 || 0x5 || ROM Name || 5 characters only
 +
|-
 +
| 0x35 || 0x93 || Padding || always zero
 +
|}
 +
 +
===ys_1 (Sample Data)===
 +
 +
Chunk size seems to always be 0x40.
 +
 +
{| class="wikitable"
 +
! Offset
 +
! Size
 +
! Description
 +
! Notes
 +
|-
 +
| 0x0 || 0x4 || "ys_1" || Header
 +
|-
 +
| 0x4 || 0x4 || Chunk size || Size of entire chunk including header (seems to be always 0x40)
 +
|-
 +
| 0x8 || 0x2 || Unique Chunk ID || Seems to be unique identifier
 +
|-
 +
| 0xA || 0x2 || Padding? || always 0x0000
 +
|-
 +
| 0xC || 0x10 || Sample name || 16-byte long ASCII string
 +
|-
 +
| 0x1C || 0x4 || unknown pointer? ||
 +
|-
 +
| 0x20 || 0x4 || unknown pointer? ||
 +
|-
 +
| 0x24 || 0x4 || unknown pointer? ||
 +
|-
 +
| 0x28 || 0x4 || unknown pointer? ||
 +
|-
 +
| 0x2C || 0x4 || unknown pointer? ||
 +
|-
 +
| 0x30 || 0x4 || unknown pointer? ||
 +
|-
 +
| 0x34 || 0x4 || unknown pointer? ||
 +
|-
 +
| 0x38 || 0x4 || unknown pointer? ||
 +
|-
 +
| 0x3C || 0x4 || unknown pointer? ||
 +
|-
 +
| 0x3D || 0x1 || unknown ||
 +
|-
 +
| 0x3E || 0x1 || unknown ||
 +
|-
 +
| 0x3F || 0x1 || End of chunk? || Seems to be the same last byte that's used to terminate chunks (as seen in the header)
 +
|}
 +
 +
===yp_1 (Preset Data)===
 +
 +
{| class="wikitable"
 +
! Offset
 +
! Size
 +
! Description
 +
! Notes
 +
|-
 +
| 0x0 || 0x4 || '''"yp_1"''' || Header
 +
|-
 +
| 0x4 || 0x4 || '''Chunk size''' || Size of entire chunk including header (seems to be always 0x3E0)
 +
|-
 +
| 0x8 || 0x2 || '''Unique Chunk ID''' || Seems to be unique identifier
 +
|-
 +
| 0xA || 0x2 || Padding? || always 0x0000
 +
|-
 +
| 0xC || 0x10 || '''Preset name''' || 16-byte long ASCII string
 +
|-
 +
| 0x24 || 0x10 || '''Chunk size''' || (seems to be always 0x64)
 +
|}
 +
 +
 +
Starting at 0xB0 is the first chunk that defines one of the four layers for Proteus 2000 patches; each one of the 4 chunks is 0xCC bytes in length.  The first part of each chunk defines the Sample ID number used for the layer.
 +
 +
{| class="wikitable"
 +
! Offset
 +
! Size
 +
! Description
 +
! Notes
 +
|-
 +
| 0xB0 || 0x2 || '''Layer 1 Chunk size''' || Always 0xCC
 +
|-
 +
| 0xB2 || 0x3 || Unknown || Always <tt>00 00 02</tt>
 +
|-
 +
| 0xB5 || 0x1 || '''Layer 1 Sample ROM MSB''' || This value denotes the MSB of the ROM where the sample is located
 +
|-
 +
| 0xB6 || 0x2 || '''Layer 1 Sample ID''' || Zeroed if unused
 +
|-
 +
| 0x17C || 0x2 || '''Layer 2 Chunk size''' || Always 0xCC
 +
|-
 +
| 0x17E || 0x3 || Unknown || Always <tt>00 00 02</tt>
 +
|-
 +
| 0x181 || 0x1 || '''Layer 2 Sample ROM MSB''' || This value denotes the MSB of the ROM where the sample is located
 +
|-
 +
| 0x182 || 0x2 || '''Layer 2 Sample ID''' || Zeroed if unused
 +
|-
 +
| 0x248 || 0x2 || '''Layer 3 Chunk size''' || Always 0xCC
 +
|-
 +
| 0x24A || 0x3 || Unknown || Always <tt>00 00 02</tt>
 +
|-
 +
| 0x24D || 0x1 || '''Layer 3 Sample ROM MSB''' || This value denotes the MSB of the ROM where the sample is located
 +
|-
 +
| 0x24E || 0x2 || '''Layer 3 Sample ID''' || Zeroed if unused
 +
|-
 +
| 0x314 || 0x2 || '''Layer 4 Chunk size''' || Always 0xCC
 +
|-
 +
| 0x316 || 0x3 || Unknown || Always <tt>00 00 02</tt>
 +
|-
 +
| 0x319 || 0x1 || '''Layer 4 Sample ROM MSB''' || This value denotes the MSB of the ROM where the sample is located
 +
|-
 +
| 0x31A || 0x2 || '''Layer 4 Sample ID''' || Zeroed if unused
 +
|-
 +
|}
 +
 +
===yi_1 (Instrument Data)===
 +
 +
{| class="wikitable"
 +
! Offset
 +
! Size
 +
! Description
 +
! Notes
 +
|-
 +
| 0x0 || 0x4 || "yi_1" || Header
 +
|-
 +
| 0x4 || 0x4 || Chunk size || Size of entire chunk including header
 +
|-
 +
| 0x8 || 0x2 || Unique Chunk ID || Seems to be unique identifier
 +
|-
 +
| 0xA || 0x2 || Padding? || always 0x0000
 +
|-
 +
| 0xC || 0x10 || Midimap name || 16-byte long ASCII string
 +
|-
 +
| 0x28 || 0x2 || Sample ID? ||
 +
|-
 +
| 0x2C || 0x1 || MIDI Root note ||
 +
|}
 +
 +
===yr_1 (Riff Data)===
 +
 +
{| class="wikitable"
 +
! Offset
 +
! Size
 +
! Description
 +
! Notes
 +
|-
 +
| 0x0 || 0x4 || "yr_1" || Header
 +
|-
 +
| 0x4 || 0x4 || Chunk size || Size of entire chunk including header
 +
|-
 +
| 0x8 || 0x2 || Unique Chunk ID || Seems to be unique identifier
 +
|-
 +
| 0xA || 0x2 || Padding? || always 0x0000
 +
|-
 +
| 0xC || 0x10 || Riff name || 16-byte long ASCII string
 +
|-
 +
| 0x1C || N/A || MIDI Data ||
 +
|}
 +
 +
==Snatcher (Sega CD) Music Driver==
 +
===Important Addresses and info===
 +
 +
====FMWR_1.BIN====
 +
 +
{| class="wikitable"
 +
! FMWR_1.BIN Offset
 +
! Description
 +
! Notes
 +
|-
 +
| 0x0-0x400 || Instruments offset table ||
 +
|-
 +
| 0x2846 || Sequence data offset table ||
 +
|-
 +
| 0x2936 || Start of sequence data ||
 +
|-
 +
| 0x0 || Track 1 Offset ||
 +
|-
 +
| 0x0 || Track 1 Offset ||
 +
|-
 +
| 0x0 || Track 1 Offset ||
 +
|-
 +
| 0x0 || Track 1 Offset ||
 +
|}
 +
 +
 +
All the music data is located in the '''FMWR_1.BIN''' file located in the Snatcher ISO.
 +
 +
Track RAM aka music driver internals are located at address $FF7A00, while the music sequence data is loaded into RAM at $FF8000.
 +
 +
====How music sequence data is loaded into RAM====
 +
 +
 +
 +
FF5614 (0x6538 in the ISO) and FF5620 (0x6544 in the ISO) are the instructions responsible for loading the Konami Logo music into the driver.  Both instructions use the 4-bytes "00 20 28 46".  FF5620 adds F0 from the A5 register to get "00 20 29 36"; the last two bytes is where the Konami logo music data is located.
 +
 +
===Music Sequence Header===
 +
 +
{| class="wikitable"
 +
! Offset
 +
! Size
 +
! Description
 +
! Notes
 +
|-
 +
| 0x0 || 0x4 || Track 1 Offset ||
 +
|-
 +
| 0x4 || 0x4 || Track 2 Offset ||
 +
|-
 +
| 0x8 || 0x4 || Track 3 Offset ||
 +
|-
 +
| 0xC || 0x4 || Track 4 Offset ||
 +
|-
 +
| 0x10 || 0x4 || Track 5 Offset ||
 +
|-
 +
| 0x14 || 0x4 || Track 6 Offset ||
 +
|-
 +
| 0x18 || 0x4 || Track 7 Offset ||
 +
|-
 +
| 0x1C || 0x4 || Track 8 Offset ||
 +
|}
 +
 +
===Test Tone data===
 +
 +
 +
The first event in each sequence track specifies the timer (Timer A?) as such: $EAxx, where xx is the value, FF being very fast and 01 being the slowest.
 +
 +
The second event is $EE xx, where xx controls volume (total level?)
 +
 +
 +
$EAxx = Track speed (Timer A?)
 +
$EExx = Track Volume (Total Level?; has no effect on PCM samples)
 +
$E2xx = FM Patch Program Change
 +
$E6 = Loop Start?
 +
$E7 = Loop point End?
 +
 +
 +
{| class="wikitable"
 +
! Offset
 +
! Size
 +
! Description
 +
! Notes
 +
|-
 +
| 0x0 || 0x1 || EA || Track speed (Timer A?)
 +
|-
 +
| 0x1 || 0x1 || 78 || Value (FF = fast; 01 = slow)
 +
|-
 +
| 0x2 || 0x1 || EE || Track volume (total level?)
 +
|-
 +
| 0x3 || 0x1 || 64 || Value
 +
|-
 +
| 0x4 || 0x1 || E2 || Track instrument
 +
|-
 +
| 0x5 || 0x1 || 01 || Instrument ID
 +
|-
 +
| 0x6 || 0x1 || 30 ||
 +
|-
 +
| 0x7 || 0x1 || 30 ||
 +
|-
 +
| 0x8 || 0x1 || 7D ||
 +
|-
 +
| 0x9 || 0x1 || 64 ||
 +
|-
 +
| 0xA || 0x2 || FF 00 || End of track
 +
|}
 +
 +
===JUNKER HQ Analysis===
 +
 +
Looks like first NoteOn is just the pitch followed by ticks, but if the next note has the same tick value, then you must specify pitch and then turn on the highest bit.
 +
 +
E6 13 18 7D 65 96 E5 98 E5 96
 +
 +
E6 = Loop Start
 +
 +
13 = Note On $13
 +
 +
18 = tick
 +
 +
7D = carrier level?
 +
 +
65 = mod level?
 +
 +
96 = Reuse Tick flag?/Note On $16
 +
 +
E5 = Note Off?
 +
 +
98 = Reuse Tick flag?/Note On $18
 +
 +
E5 = Note Off?
 +
 +
96 = Reuse Tick flag?/Note On $16

Latest revision as of 17:41, 21 May 2022

Fairlight CMI - Important Memory Maps

Page T

Page T's table is split up into three sections: Register, Stroke and Channel. Register starts at 0x7A80, Stroke starts at 0x7B00, and Channel starts at 0x7B80.

Offset Size Description Notes
0x7A80 0x10
Register File
Unknown; shows up in the Page T debug menu.
0x7B00 0x10
Stroke Key
Unknown; shows up in the Page T debug menu.
0x7B80 0x10
Channel G. IN
Unknown; shows up in the Page T debug menu.
0x7B90 0x10
Channel G. PT
Unknown; shows up in the Page T debug menu.
0x7BD0 0x10
Channel Mode (first byte) / Channel State (second byte)
Unknown; shows up in the Page T debug menu.


Page Status / Command Line

Offset Size Description Notes
0x7E10 0x38
Page Status
Displays the page name or any important messages
0x7E48 0x38
Command Line
Commands are typed in here. Always starts with the cursor character (0x1A). The very last byte is always a space (0x20), because that is the character limit.

Fairlight CMI *.IN File Structure

0x200: Voice Chunk

Offset Size Description Notes
0x0 0x1
Start of Voice
Always 0x31
0x2 0x8
Voice Filename
Always 0x8 long. If name is shorter than 8 characters, remaining characters are spaces (0x20)
0x9 0x2
Voice File Extention
Always "VC" (0x5643)


Fairlight CMI *.RS File Structure

Offset Size Description Notes
0x0 0x2
Version/Revision
Always 0x0102
0x2 0x2
Speed
0xA3A = 2618 = 120 BPM. To get the BPM, divide 314160 by the song's speed value (314160/2618 = 120). To get the speed value, divide 314160 by the song's BPM (314160/120 = 2618)
0x4 0x2
Global Time Signature
For example: 0x0404 = 4/4; 0x0608 = 6/8. This will be the time signature for any blank patterns. Any pattern that has data in it, will override this time signature
0x6 0x2
Sync Flag
0x0000 = INT; 0x0001 = EXT
0x80 0xFF
Patterns Used Index Chunk
Seems that any value (as long as it's not more than or equal to the patterns used total) will work.
0x17F 0x1
unknown
0x180 0xFF
unknown
This looks like a duplicate of the Patterns Used Index Chunk, except every value is a 1. When loaded in the CMI's memory, this area was zeroed out. Possibly unused?
0x27F 0x1
unknown
0x280 0x1FE
Song Step Index Chunk
Every word is a step, first byte is the pattern number, second byte is how many repeats. For example, 0x0106 = play pattern 1, 6 times. As soon as the sequencer sees the first zeroed byte in the index, all other bytes after that are ignored.
0x47E 0x2
Padding (unused)
An extra two bytes of 0x0001 pad out this chunk to make it 200-bytes long.
0x480 0x1D2
Section Step Index Chunk
Every word is a step, first byte is the pattern number, second byte is how many repeats. For example, 0x0106 = play pattern 1, 6 times. As soon as the sequencer sees the first zeroed byte in the index, all other bytes after that are ignored.
0x652 0x2E
Padding (unused)
An extra set 0x0001 words pad out this chunk to make it 200-bytes long.
0x680 0x80
"E5" Chunk?
For some reason at offset 0x680, there is a chunk that is usually filled with 0xE5, or just zeroed out.

Song Step Index Chunk

Every two bytes represent a step in in the emulator. The first byte is either the pattern number, or the section letter. The second byte has the value for how many times the pattern or section has to play but also contains a flag denoting if the first byte is a section letter or not.

The highest bit of the second byte determines if the previous byte is a pattern number or a section letter. For example, the value 0x4D can be either the decimal number "77", or the section letter "M". 0x4D01 means that pattern 77 will play once. 0x4D00 means the pattern 77 will play forever and 0x4D86 means that the sequencer will play section "M" 6 times. This is why we can't repeat patterns or sections more than 127 times.

As soon as the sequencer encounters a zero where a pattern number should be, then the sequencer ignores all the remaining bytes (even ones that have valid data in them) and places an end marker denoting that the song is finished.

Section Step Index Chunk

This chunk is very similar to the Step Index chunk. Every word contains the values for the pattern number or section letter, as well as the play count for the step and the section letter flag.

Pattern Chunk

The first pattern for the song is located at offset 0x700 in the file. Each pattern is 0x680 bytes long. The CMI's memory can only hold up to 8 patterns (0x3400 bytes), so a buffer table is used to point to the last 8 previously loaded patterns.

Header

Offset Size Description Notes
0x0 0x2
Time Signature
Overrides the global time signature in the header.
0x2 0x2
Speed?
0x4 0x2
ubeats per count?
0x6 0x1
ubeats per division?
0x7 0x1
divisions per count?
0x8 0x1
divisions per pattern?
0x9 0x1
PPQ?
0xA 0x1
unused
0xB 0x2
pointer back to buffer table (2 bytes)?
0x68 0x10
Comment
16-character string used for comments
0x78 0x08
Padding
0x80 0xC0
Note Data for Keyboard 1
0x140 0xC0
Note Data for Keyboard 2
0x200 0xC0
Note Data for Keyboard 3
0x2C0 0xC0
Note Data for Keyboard 4
0x380 0xC0
Note Data for Keyboard 5
0x440 0xC0
Note Data for Keyboard 6
0x500 0xC0
Note Data for Keyboard 7
0x5C0 0xC0
Note Data for Keyboard 8

Note Data

Notes are represented in two bytes. Specific bits are assigned to three different parameters, Key (Pitch), Vel (Velocity), and Dur (Duration).

The range of Key are from note F1 to F7. Duration goes from 0 to 48, and Velocity goes from 1 to 8.

D15 D14 D13 D12 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0
Key Dur Vel

Velocity is different from the other two parameters as it's value is inverted. So 0x0 = 8, 0x1 = 7, etc.

The maximum amount of notes per keyboard per pattern is 48. The maximum amount of notes per pattern is 384 (48 notes x 8 keyboards). To pad out the pattern, between every 48th note is a zeroed out word. So, for example, we have several sequential 48th notes at Key C4, Vel 8, Dur 2 (0x5810). They appear in the code as this: 58 10 00 00 58 10 00 00 58 10 00 00 58 10 00 00, etc.

MegaRace HERAD "DFADP.HSQ" Driver

This is the driver that is used for Sound Blaster Pro. Provided that the sounds are turned off in the setup options, the driver is located in memory at 3B08:0100. The song currently loaded is located at 3BB6:0000. Note that since the driver is loaded at 3B08:0100, the offsets listed here are off by 0x100 since the reverse engineering process began by referencing the driver file rather than the driver loaded in RAM. As a result, to get the correct offset, just simply add 0x100 to the value and that will be the offset used by the driver. For example, 0xA2 is actually referenced in the driver as 0x1A2.

Offset Size Description Notes
0x00 0x15  ? The game uses these jumps to control the driver
0x15 0x2 Magic? (Always 0x0002) The driver uses this value to do several things, such as using this to add to the relative offsets from the music file so that they become absolute offsets.
0x17 0x2 Song Segment This is where the music file is located (for example, 3BB6:0000)
0x19 0x2 Song Length (first two bytes from music file)
0x1B 0x2 Song Segment
0x1D 0x2 Timer Timer based off of the song's speed value
0x1F 0x2 MIDI Measure Counter (this counts up after every 96 MIDI ticks and is used for the song loop)
0x21 0x2 MIDI Tick Measure Counter (Counts down from 0x60 aka 96 MIDI Ticks)
0x23 0x2 Song Repeat Counter (Counts down from 0xFFFF after passing beginning loop measure)
0x25 0x10 MIDI Event Subroutine Lookup Table Each word is an offset to a subroutine in the driver that handles a particular MIDI Event:

06CF = NoteOff (80)
065D = NoteOn (90)
08E5 = Polyphonic Aftertouch (A0)
08E5 = Control Mode Change (B0)
05D2 = Program Change (C0)
072E = Aftertouch (D0)
07DD = Pitch Bend (E0)
06F5 = End of Track (FF)

Note that Polyphonic Aftertouch and Control Mode Change share the same offset. That is because HERAD doesn't support those MIDI events so the sequencer uses this table to ignore the events and proceed with playing the event as a regular NoteOn. HERAD 2 also doesn't support Aftertouch Events, so they are parsed but ignored.

0x35 0x6  ? Table (00 03 01 04 02 05)
0x3B 0x6  ? Table (08 0B 09 0C 0A 0D)
0x41 0x6  ? Table (10 13 11 14 12 15)
0x47 0x18 Frequency Table These are the FNUM values that make up the 12 note Chromatic musical scale for HERAD. Basically, changing these values will modify the "tuning" of the scale.
0x5F 0x12 FNUM/Block Number Register Values These register values are sent directly to the OPL chip, however these values are missing the Key-On bit (bit 5, 0xB0-0xB8).
0x71 0x12 OPL Register Lookup Table Table (00 01 02 08 09 0A 10 11 12 03 04 05 0B 0C 0D 13 14 15). Some subroutines use this to write to all the OPL registers.
0x7A 0x16 Fine Pitch Bend Table
0x90 0xA Coarse Pitch Bend Table
0x9A 0x2 Song Flag Left over from Dune. When set to 0x80, this plays the song, but when this changes to 0x00, playback stops. The driver checks to see if the highest bit is set to 1 and if it is, the song plays, so any value between 0x80 and 0xBF will work. 0xC0, was used to fade out songs in Dune, but this feature has been removed. 0xC0 is still used to end songs when the game quits.
0x9C 0x3  ? (Always 0xEEEEEE) Changing this doesn't affect playback but it is used by several subroutines in the driver.
0x9F 0x2  ? Two byte timer that counts up by rotating (bit shifting) to the left by 1
0xA1 0x1 Padding (Always 0x90, changing this doesn't affect playback)
0xA2 0x12 Current Midi Delay Counter (counts down until next event)
0xB4 0x12 MIDI Track Position (counts up until reaching the track end)
0xC6 0x12 Start of MIDI Tracks (Absolute address in music file, rather than relative address in music file header)
0xD8 0x12 List of MIDI tracks using drum keymap instrument If MIDI track uses keymap instrument, the absolute offset of the instrument in the music file will be used. If the instrument changes back to a normal instrument, the value zeros out.
0xEA 0x12 Current Instrument (first byte) / MIDI Pitch (second byte) The pitch here is after any transpose macros have been applied. Also, if the keymap instrument is used, the first byte will display the instrument(s) that are actually being played. If no instrument or note data exist, the values will be 0xFF/0x00 respectively. NoteOffs are enabled by setting the highest bit to 1 in the pitch byte.
0xFC 0x12 Pitch Slide Range Flag (first byte) / Root Note Transpose (second byte) for each MIDI track
0x10E 0x12 Pitch Slide Duration Counter (first byte) / Pitch Slide Duration (second byte) for each MIDI track The Pitch Slide Counter starts at the value assigned by the second byte.
0x120 0x12 Pitch Slide Counter (first byte) / Pitch Slide Range (second byte) for each MIDI track The Pitch Slide Counter starts at 0x40 (unless it is transposed) and either goes up or down depending on Pitch Slide Range value.
0x132 0x12 Modulator Output Level Scaling (first byte) / Carrier Output Level Scaling (Second byte) These values are taken from the current instrument.
0x144 0x12 Modulator Output Level (first byte) / Carrier Output Level (Second byte) These values are taken from the current instrument.
0X156 0x12 Modulator Output Level Register (first byte) / Carrier Output Level Register (Second byte) These are the final register values that are sent to the OPL chip.
0x168 0x12 Panning/Feedback/Connector Register Value
0x17A 0x12 Loop MIDI Delay Values These are the values that the MIDI delay counters load when the song loops.
0x18C 0x12 Loop Start Absolute Address for each MIDI track (loads after the song passes the loop beginning measure)
0x19E 0x24  ? Seems to be just zeros
0x1C2 0x1 Terminator (flashes 0xFF during playback)
0x1C3 EOF Binary Data (starts with "HSQ" with 0x2002 at the end) (0x4853512002)

Dune HERAD "DUNEADL.HSQ" Driver (Floppy Version)

Offset Size Description Notes
0x00 0x21  ? Changing some values crash the game, while others don't
0x21 0x2  ? Something to do with the song speed (Always 0x0240)
0x17 0x2  ? (Always 0x00E0)
0x19 0x2 Song length + 0x0040 This value is the first two bytes from music file with 0x0040 added, for example WORMSUIT.HSQ's song length (0x3C7E) will show up as 0x3CBE
0x1B 0x2  ? (Always 0x00E0)
0x29 0x2  ? (OPL Timer?)
0x2B 0x2 MIDI Measure Counter This counts up after every 96 MIDI ticks and is used for the song loop
0x2D 0x2 MIDI Tick Measure Counter Counts down from 0x60 aka 96 MIDI Ticks
0x2F 0x12  ? Changing some values crash the game, while others don't
0x41 0x6  ? Table (00 03 01 04 02 05)
0x47 0x6  ? Table (08 0B 09 0C 0A 0D)
0x4D 0x6  ? Table (10 13 11 14 12 15)
0x53 0x18 Frequency Table These are the FNUM values that make up the 12 note Chromatic musical scale for HERAD. Basically, changing these values will modify the "tuning" of the scale.
0x6B 0x12 FNUM/Block Number Register Values These register values are sent directly to the OPL chip, however these values are missing the Key-On bit (bit 5, 0xB0-0xB8).
0x7D 0x9  ? Table (00 01 02 08 09 0A 10 11 12)
0x86 0x16 Fine Pitch Bend Table
0x9C 0xA Coarse Pitch Bend Table
0xA6 0x1 Song Reset/Fade Out Controls 0x80 = Play song. 0x00 = resets the song back to the beginning, then the value switches back to 0x80 to play the song. 0xC0 = Fades the song out and waits until the Fade Out MIDI Tick Timer at 0xA8 counts to zero before resetting the song from the beginning).
0xA7 0x1 Change Song Depending on which screen the game is in, this is set to 0x1 so when the current song is finished playing or fades out, a new song will play. In the Options menu of Dune, if "Music On (CD-Style)" is selected, this byte is always 0x1 when a song is playing.
0xA8 0x1 Fade Out MIDI Tick Timer Counts down from 0xFF with each MIDI tick. Once this reaches zero, the value at 0xA6 changes back to 0x0000.
0xA9 0x2  ? Something to do with the fade out timer. When not active, this is at 0x1111. Seems to count in only 0x11,0x22,0x44,0x88.
0xAB 0x1 Padding (Always 0x90, changing this doesn't affect playback)
0xAC 0x12 Current Event Midi Tick Counter (counts down until next event)
0xBE 0x12 MIDI Track Position + 0x0040 Absolute value with 0x0040 added (counts up until reaching the track end)
0xD0 0x12 Start of MIDI Tracks + 0x0040 Absolute value with 0x0040 added (Absolute address in music file, rather than relative address in music file header)
0xE2 0x12 Current Instrument (first byte) / MIDI Pitch (second byte) The pitch here is after any transpose macros have been applied. If no instrument or note data exist, the values will be 0xFF/0x00 respectively. NoteOffs are enabled by zeroing out the pitch byte.
0xF4 0x12 Pitch Slide Range Flag (first byte) / Root Note Transpose (second byte) for each MIDI track
0x106 0x12 Pitch Slide Duration Counter (first byte) / Pitch Slide Duration (second byte) for each MIDI track The Pitch Slide Counter starts at the value assigned by the second byte.
0x118 0x12 Pitch Slide Counter (first byte) / Pitch Slide Range (second byte) for each MIDI track The Pitch Slide Counter starts at 0x40 (unless it is transposed) and either goes up or down depending on Pitch Slide Range value.
0x12A 0x12 Modulator Output Level Scaling (first byte) / Carrier Output Level Scaling (Second byte) These values are taken from the current instrument.
0x13C 0x12 Modulator Output Level (first byte) / Carrier Output Level (Second byte) These values are taken from the current instrument data and also include the Key scaling level register values.
0X14E 0x12 Modulator Output Level Register (first byte) / Carrier Output Level Register (Second byte) These are the final register values that are sent to the OPL chip. These values also include the Key scaling level register values.
0x160 0x12 Feedback Scaling - Velocity (first byte) / Feedback/Connector (second byte) These values are taken from the current instrument data, however the second byte is the unmodified register value of the feedback and connector settings.
0x172 0x12 Modulator Output Level Aftertouch Scaling (first byte) / Carrier Output Level Aftertouch Scaling (second byte) These values are taken from the current instrument data
0x184 0x12 Feedback Scaling - Aftertouch / Feedback/Connector Register Value The first value is taken from the current instrument data, however the second byte is the final modified register value of the feedback and connector settings that will be sent to the OPL2 chip.
0x196 0x12 Loop Counter Values These are the values that the MIDI tick counters load when the song loops.
0x1A8 0x12 Loop Start Absolute Address for each MIDI track + 0x0040 (loads after the song passes the loop beginning measure)
0x1BA EOF Binary Data (always starts with "HSQ" string with 0x16 at the end) (0x48535116)

Dune HERAD "DUNEADL.HSQ" Driver (CD Version)

To be completed.

Dune HERAD "DUNEAGD.HSQ" Driver (Floppy Version)

Offset Size Description Notes
0x3E4 EOF Binary Data (always starts with "AGD" string with 0x16 at the end) (0x41474416)

Dune HERAD "DUNEAGD.HSQ" Driver (CD Version)

To be completed.

Dune HERAD "DUNEADL.SQZ" Driver (Demo Version)

To be completed.

Nintendo WSYS File Structure

Header Chunk

Offset Size Description Notes
0x0 0x4 "WSYS" Header
0x4 0x4 File Size File Size
0x8 0x8 unknown Just zeros?
0x10 0x4 "WINF" absolute offset Need more info on WINF chunk
0x14 0x4 "WBCT" absolute offset Need more info on WBCT chunk
0x18 0x8 unknown Just zeros?

Sample data Chunk

Each sample entry is 0x24 bytes long.

Offset Size Description Notes
0x0 0x2 "E700" Header?
0x2 0x2 MIDI Pitch MIDI Pitch
0x4 0x4 Sample Rate Represented as a floating point value
0x8 0x4 Sample Start Offset Absolute offset inside the AW file where the start of the ADPCM sample is located
0xC 0x4 Sample Size Size of the ADPCM sample
0x10 0x4 Loop flag 00000000 = off; FFFFFFFF = on
0x14 0x4 Loop start point Sample where loop starts
0x18 0x4 Loop end point Sample where loop ends
0x1C 0x4 unknown? Something to do with the loop point samples
0x20 0x4 unknown?

"WINF" Chunk

More work needs to be done here.

Offset Size Description Notes
0x0 0x4 "WINF" Header
0x4 0x4 unknown Number of AW files?
0x8 0x8 AW filename absolute offset Points to the name of the AW file. AW files contain all the ADPCM sample data.

E-MU EXB File Structure

E4B

E4B Header

Length is 0x20 and uses regular strings for preset names

Offset Size Description Notes
0x0 0x4 "FORM" Header
0x4 0x4 File size Size of entire file
0x8 0x8 E4B0TOC1 Table of Content v1
0x10 0x4 Table Size Length of TOC

E4P1 (Preset Data)

Offset Size Description Notes
0x0 0x4 "E4P1" Header
0x4 0x4 Size after header (filesize minus 8 bytes)
0x8 0x2 Preset Number
0xA 0x10 Preset name
0x5C 0x2 Layer Chunk size

E5B/EXB

E5B Header

Length is 0x4E and uses array of zero-terminated UTF-16 Unicode strings

Offset Size Description Notes
0x0 0x4 "FORM" Header
0x4 0x4 File size Size of entire file?
0x8 0x8 E5B0TOC2 Table of Content v2
0x10 0x4 Table Size Length of TOC

E5P1 (Preset Data)

Offset Size Description Notes
0x0 0x4 "E5P1" E-MU Preset Header
0x4 0x4 unknown ?
0x8 0x4 Start of Preset Data Points to offset of preset data
0xC 0x2 Preset number
0xE 0x40 Preset name / padding zero-terminated UTF-16 Unicode string with zero padding ("a.m.b.:.A.i.o.o.n. .P.a.d.")

E5ZLZhdr chunk

This is where the Samplepool ID for the preset is stored.

Offset Size Description Notes
0x0 0x4 "LIST" Header
0x4 0x4 Chunk size Size of chunk after header
0x8 0x8 E5ZLZhdr Magic
0x10 0x4 Chunk size Size of chunk after header
0x14 0x4 unknown (seems to always be 0x2)
0x18 0x2 Samplepool ID Sample ID number

E-MU Proteus 2000 ROM File Structure

yh_1 (ROM Header)

Offset Size Description Notes
0x0 0x4 "yh_1" Header
0x4 0x4 Chunk size Size of entire chunk including header (seems to be always 0xC8)
0xF 0x1 unknown Seems to be the same last byte that's used to terminate chunks
0x10 0x20 Padding always zero
0x30 0x5 ROM Name 5 characters only
0x35 0x93 Padding always zero

ys_1 (Sample Data)

Chunk size seems to always be 0x40.

Offset Size Description Notes
0x0 0x4 "ys_1" Header
0x4 0x4 Chunk size Size of entire chunk including header (seems to be always 0x40)
0x8 0x2 Unique Chunk ID Seems to be unique identifier
0xA 0x2 Padding? always 0x0000
0xC 0x10 Sample name 16-byte long ASCII string
0x1C 0x4 unknown pointer?
0x20 0x4 unknown pointer?
0x24 0x4 unknown pointer?
0x28 0x4 unknown pointer?
0x2C 0x4 unknown pointer?
0x30 0x4 unknown pointer?
0x34 0x4 unknown pointer?
0x38 0x4 unknown pointer?
0x3C 0x4 unknown pointer?
0x3D 0x1 unknown
0x3E 0x1 unknown
0x3F 0x1 End of chunk? Seems to be the same last byte that's used to terminate chunks (as seen in the header)

yp_1 (Preset Data)

Offset Size Description Notes
0x0 0x4 "yp_1" Header
0x4 0x4 Chunk size Size of entire chunk including header (seems to be always 0x3E0)
0x8 0x2 Unique Chunk ID Seems to be unique identifier
0xA 0x2 Padding? always 0x0000
0xC 0x10 Preset name 16-byte long ASCII string
0x24 0x10 Chunk size (seems to be always 0x64)


Starting at 0xB0 is the first chunk that defines one of the four layers for Proteus 2000 patches; each one of the 4 chunks is 0xCC bytes in length. The first part of each chunk defines the Sample ID number used for the layer.

Offset Size Description Notes
0xB0 0x2 Layer 1 Chunk size Always 0xCC
0xB2 0x3 Unknown Always 00 00 02
0xB5 0x1 Layer 1 Sample ROM MSB This value denotes the MSB of the ROM where the sample is located
0xB6 0x2 Layer 1 Sample ID Zeroed if unused
0x17C 0x2 Layer 2 Chunk size Always 0xCC
0x17E 0x3 Unknown Always 00 00 02
0x181 0x1 Layer 2 Sample ROM MSB This value denotes the MSB of the ROM where the sample is located
0x182 0x2 Layer 2 Sample ID Zeroed if unused
0x248 0x2 Layer 3 Chunk size Always 0xCC
0x24A 0x3 Unknown Always 00 00 02
0x24D 0x1 Layer 3 Sample ROM MSB This value denotes the MSB of the ROM where the sample is located
0x24E 0x2 Layer 3 Sample ID Zeroed if unused
0x314 0x2 Layer 4 Chunk size Always 0xCC
0x316 0x3 Unknown Always 00 00 02
0x319 0x1 Layer 4 Sample ROM MSB This value denotes the MSB of the ROM where the sample is located
0x31A 0x2 Layer 4 Sample ID Zeroed if unused

yi_1 (Instrument Data)

Offset Size Description Notes
0x0 0x4 "yi_1" Header
0x4 0x4 Chunk size Size of entire chunk including header
0x8 0x2 Unique Chunk ID Seems to be unique identifier
0xA 0x2 Padding? always 0x0000
0xC 0x10 Midimap name 16-byte long ASCII string
0x28 0x2 Sample ID?
0x2C 0x1 MIDI Root note

yr_1 (Riff Data)

Offset Size Description Notes
0x0 0x4 "yr_1" Header
0x4 0x4 Chunk size Size of entire chunk including header
0x8 0x2 Unique Chunk ID Seems to be unique identifier
0xA 0x2 Padding? always 0x0000
0xC 0x10 Riff name 16-byte long ASCII string
0x1C N/A MIDI Data

Snatcher (Sega CD) Music Driver

Important Addresses and info

FMWR_1.BIN

FMWR_1.BIN Offset Description Notes
0x0-0x400 Instruments offset table
0x2846 Sequence data offset table
0x2936 Start of sequence data
0x0 Track 1 Offset
0x0 Track 1 Offset
0x0 Track 1 Offset
0x0 Track 1 Offset


All the music data is located in the FMWR_1.BIN file located in the Snatcher ISO.

Track RAM aka music driver internals are located at address $FF7A00, while the music sequence data is loaded into RAM at $FF8000.

How music sequence data is loaded into RAM

FF5614 (0x6538 in the ISO) and FF5620 (0x6544 in the ISO) are the instructions responsible for loading the Konami Logo music into the driver. Both instructions use the 4-bytes "00 20 28 46". FF5620 adds F0 from the A5 register to get "00 20 29 36"; the last two bytes is where the Konami logo music data is located.

Music Sequence Header

Offset Size Description Notes
0x0 0x4 Track 1 Offset
0x4 0x4 Track 2 Offset
0x8 0x4 Track 3 Offset
0xC 0x4 Track 4 Offset
0x10 0x4 Track 5 Offset
0x14 0x4 Track 6 Offset
0x18 0x4 Track 7 Offset
0x1C 0x4 Track 8 Offset

Test Tone data

The first event in each sequence track specifies the timer (Timer A?) as such: $EAxx, where xx is the value, FF being very fast and 01 being the slowest.

The second event is $EE xx, where xx controls volume (total level?)


$EAxx = Track speed (Timer A?) $EExx = Track Volume (Total Level?; has no effect on PCM samples) $E2xx = FM Patch Program Change $E6 = Loop Start? $E7 = Loop point End?


Offset Size Description Notes
0x0 0x1 EA Track speed (Timer A?)
0x1 0x1 78 Value (FF = fast; 01 = slow)
0x2 0x1 EE Track volume (total level?)
0x3 0x1 64 Value
0x4 0x1 E2 Track instrument
0x5 0x1 01 Instrument ID
0x6 0x1 30
0x7 0x1 30
0x8 0x1 7D
0x9 0x1 64
0xA 0x2 FF 00 End of track

JUNKER HQ Analysis

Looks like first NoteOn is just the pitch followed by ticks, but if the next note has the same tick value, then you must specify pitch and then turn on the highest bit.

E6 13 18 7D 65 96 E5 98 E5 96

E6 = Loop Start

13 = Note On $13

18 = tick

7D = carrier level?

65 = mod level?

96 = Reuse Tick flag?/Note On $16

E5 = Note Off?

98 = Reuse Tick flag?/Note On $18

E5 = Note Off?

96 = Reuse Tick flag?/Note On $16