Music Hacking/DAC Samples, Coordination Flags, Game Specifics, and Real-Time Music Editing
From Sonic Retro
Music Hacking: Pointer and Header Format | Voice and Note Editing | DAC Samples, Coordination Flags, Game Specifics, and Real-Time Music Editing | Other Games and Data Locations | Tricks of the Trade |
DAC Samples
DAC samples are raw PCM samples, generally used for drums and voices that you hear in game. You can customize these audio samples to your needs. Here is some information to do so below...
DAC Formats
Mega Drive
Typically (though not always), SMPS games do not store their sample data as 8-bit unsigned LPCM (the way the YM2612 takes it), but rather as 4-bit DPCM with a single shared delta array of
db 0, 1, 2, 4, 8, 10h, 20h, 40h db -80h, -1, -2, -4, -8, -10h, -20h, -40hThis form is almost always incorrectly referred to as "compressed;" jman2050 wrote a "compressor/decompressor" to convert samples stored in this format to standard 8-bit LCPM and vice versa.
There are a few exceptions to this rule:
- Michael Jackson's Moonwalker uses a different delta array for voice samples:
db 0, 1, 2, 4, 8, 10h, 20h, 40h db -80h, -1, -3, -4, -8, -10h, -20h, -40h
- Streets of Rage has the DPCM delta array for each sample as the first 16 bytes of the sample.
32X
SMPS-32X stores PWM samples as 8-bit unsigned LPCM. Note Tempo uses both DPCM samples on the MD side and PWM samples simultaneously; follow the above rules for the DPCM samples.
Sega CD
Each SMPS-PCM bank has a table of samples which are stored as 8-bit sign-magnitude; the same format as the Sega CD's PCM chip demands them. This means that each byte of the sample always consists of a 1-bit sign and 7-bit magnitude. So -1 would be represented as binary 10000001, which is $81. The only exception is $FF, which is used to mark the end of sample data (and time to go back to the loop point), so don't place this in the sample data.
Sonic 1
Samples in Sonic 1 are inside the Z80 portion of the sound driver, located at $72E7C, and compressed in Kosinski format. All following locations are for the decompressed sound driver.
DAC Sample Pointers
- DAC sample setup index: $D6
Each DAC pointer is listed one after another, and a single entry for one DAC sample is $8 bytes. The format is as follows:
Offset | Size | Description |
---|---|---|
$00-$01 | Word | Location of the DAC sample in decompressed driver.
|
$02-$03 | Word | Size of the compressed DAC sample in decompressed driver.
|
$04 | Byte | Sample rate/pitch. The lower the value, the faster the sample will play. |
$05-$07 | 3 Bytes | Unused/redundant. |
Sonic 1 has 3 DAC sample slots - one for the kick, one for the snare, and one for the Timpani. The other pitches of Timpani ($88-$8B) are defined by a special table, located at $71CC4, and are fully editable to suit other samples using the Timpani slot ($83).
Sonic 2
DAC Sample Pointers
- Pointers to DAC Samples in Sonic 2 Beta: $ECDA6
Specifics...
- $ECDA6 - Sample 81 pointer
- $ECDA8 - Sample 81 length
- $ECDAA - Sample 82 pointer
- $ECDAC - Sample 82 length (skip FF)
- $ECDAF - Sample 83 pointer
- $ECDB1 - Sample 83 length
- $ECDB3 - Sample 84 pointer
- $ECDB5 - Sample 84 length (skip FF)
- $ECDB8 - Sample 85 pointer
- $ECDBA - Sample 85 length
- $ECDBC - Sample 86 pointer
- $ECDBE - Sample 86 length -- This one is tricky. You need to skip the second FF, as the first FF is valid.
- Pointers to DAC Samples in Sonic 2 Final: $ECF7C
Specifics...
- $ECF7C - Sample 81 pointer
- $ECF7E - Sample 81 length
- $ECF81 - Sample 82 pointer
- $ECF83 - Sample 82 length
- $ECF85 - Sample 83 pointer
- $ECF87 - Sample 83 length
- $ECF8A - Sample 84 pointer
- $ECF8C - Sample 84 length
- $ECF8E - Sample 85 pointer
- $ECF90 - Sample 85 length
- $ECF93 - Sample 86 pointer
- $ECF95 - Sample 86 length
- $ECF97 - Sample 87 pointer
- $ECF99 - Sample 87 length
These pointers are 4 bytes in size. First two bytes are the pointer to the sample (the pointers add to E0000, little endian, and don't follow the music pointer format. Simple 16-bit absolute), and the other two bytes are the length of the sample (also little endian). If you see an FF, skip it and move on to the next byte.
DAC Master List
- DAC Master List in Sonic 2 Beta: $ECDC1
- DAC Master List in Sonic 2 Final: $ECF9C
These work similarly to the master playlist in concept.. The format is two bytes per sample. First byte defines the sample ID, and the second byte defines the rate that the sample is played at. The lower the rate value, the faster the sample is played. This is used to make certain samples (like toms) appear to have different pitches (high tom, low tom, etc). If you see an FF, skip it and move on to the next byte. If you touch the FF, you fuck the entire sound driver. Don't. :P
Sonic 3
Setup Pointers
- DAC $81-$9A Pointer Index (Adds to $E0000): $E0000
- DAC $9B-$AA Pointer Index (Adds to $E8000): $E8000
- DAC $AB-$C0 Pointer Index (Adds to $F0000): $F0000
These pointer indexes work by pointing to the sample setup data for the particular samples. You'll notice there are 3 pointer indexes - this is since not all the samples can fit in a single bank, so they span 3 banks. The pointers are repeated at all 3 indexes, but only the defined samples for the index (listed above) will be in the relevant ROM bank.
DAC Sample Setup Format
The format for a DAC sample entry is pretty simple. Follow along:
Offset | Size | Function |
---|---|---|
$00 | Byte | Sample rate/pitch. The lower the value, the faster the sample will play. |
$01-$02 | Word | Size of the DAC sample, in bytes.
|
$03-$04 | Word | Pointer to the DAC sample, within the current bank.
|
32X SMPS - PWM
32X games that use the PWM driver for song samples have a sample table of the form
Offset | Size | Function |
---|---|---|
$00 | Long | The virtual (SH-2 side) address of the sample — take out the first byte for the ROM address. |
$04 | Long | Size of the DAC sample, in bytes. |
$08 | Long | Zero. Purpose unknown. |
$0C | Long | Sample rate/pitch. The lower the value, the slower the playback rate. A sample rate of $00000800 is equal to 11025hz. |
Coordination flags
Coordination flags are values in the range of $E0-$FF in notation that perform special functions. The use of coordination flags can range from branching to specific locations in the song to altering volume, voice number, pitch, and other variables in real time.
Three of the coordination flags change between S1/S2 and S3/S&K. The rest are the same throughout.
Flamewing ended up showing me a table with more info than this one has, so here we go.
Flag | Purpose |
---|---|
$E0xx | Panning, AMS, FMS
|
$E1xx | Set the channel frequency displacement to signed byte xx — that is, this byte is added to the frequency value sent to the sound chip after grabbing that frequency value from the modified note ($E9/$FB) |
$E2FF | Sets an unused variable.(Sonic 1 & 2) Fade-in to previous song (needed on DAC channel, Sonic 3 & etc) |
$E3 | Return (Sonic 1 & 2) Silences FM channel then stops track (exactly as per coord. flag $F2). (Sonic 3 & etc.) |
$E4 | Fade-in to previous song (needed on DAC channel, Sonic 1 & 2) Set track volume. For FM channels, this is stripped of bit 7 and then XOR'ed with $7F before being stored (and it takes immediate effect). For PSG channels, this is shifted right 3 bits, stripped of the upper 4 bits and XOR'ed with $0F before being stored. In either case, this means that $00 is total silence and $7F (FM) or $78 (PSG) is maximum volume. (Sonic 3 & etc.) |
$E5xx | Change tempo divider to xx |
$E6xx | Change FM channel volume by xx; xx is signed
|
$E7 | Prevent next note from attacking |
$E8xx | Set note fill amount to xx |
$E9xx | Add signed xx to the channel key displacement; this value accumulates (that is, if the accumulated value was 4 and xx is 3, the new accumulated value is 7) (Sonic 1 & 2) |
$EAxx | Set tempo modifier to xx |
$EBxx | Set tempo divider to xx for ALL channels |
$ECxx | Change PSG channel volume by xx; xx is signed
|
$EE | Something with Voice Selection |
$EFxx | Change current voice to xx
|
$F0wwxxyyzz | Modulation (also turns modulation on)
|
$F1 | Turn on modulation |
$F2 | Stop the track |
$F3xx | Change current PSG noise to xx (For noise channel)
|
$F4 | Turn off modulation Sonic CD: Same as $F6 |
$F5xx | Change current PSG tone to xx |
$F6yyyy | Jump to position yyyy |
$F7xxyyzzzz | Repeat section of music
|
$F8yyyy | Jump to position yyyy (keep previous position in memory for returning) |
$F9 | Return (Sonic 3 & etc) |
$FBxx | Add signed value xx to channel key displacement; this value accumulates (that is, if the accumulated value was 4 and xx is 3, the new accumulated value is 7) (Sonic 3 & etc, Sonic CD) |
$FCyyyy | Loop Sound Effect from position yyyy. (Sonic 3 & etc) |
Note on $F3
The $F3 flag determines whether a PSG channel--usually the last one defined in the header--is a tone channel or the noise channel. There is only one noise channel, and 3 tone channels. Also worth noting is that a tone channel can become a noise channel mid-song; however, once it becomes a noise channel, it can not switch back to a tone at any point.
Note on $F8 and $F9/$E3
Flags $F8 and $F9/$E3 work similarly to the opcodes jsr and rts in terms of function. $F8 will branch to a location within the song, saving the previous location to the stack; once the data is parsed, the $F9/$E3 flag will pop the stack to the program counter, continuing on in the song after the initial $F8 branch. This effect is utilized by Puto frequently in the xm4smps program to structure SMPS files similarly internally to XM module files.
Notes on $E0
Only FM and DAC channels can be panned, the PSG channels will ignore this flag. In Sonic 1, if the sixth channel (either FM6 or the DAC) of your Game Over song is panned, the SEGA sound after the reset will be panned as well. In OutRun the DAC channel cannot be panned; each sample has its own panning setting, defined in the DAC table.
Game Specifics
Sonic 2
Master Playlist
Sonic 2 has a special "master playlist" that defines what music ID plays in what slot. It works by taking a base address - generally the start of a music bank - and, for each increment of the value, it reads ahead another word in the current ROM bank. So, say, $00 would be the first word in the bank ($00-$01), $01 would be the next ($02-$03), and so on. The base address for this bank, in both Sonic 2 Beta AND final, is $F0000, and the addressing range spans as far as the value can allow, which is two Z80 ROM banks ($10000 bytes).
However, as a simple guide to understanding how it works (at least, for the casual hacker), all values for the original, untouched music (for the most part, anyway) subtract $1 from the value. So, to change Track 81 to Track 82, change $80 to $81. $80 is $81, $81 is $82, etc. These values go up to slot $9F, or $1F (visually, anyway - the game still uses $80 > values internally) in the final version of the game. The only exception to this is in Sonic 2 Beta, where some songs use the upper $8000 bytes of the bank start address to store music (making the values for calling said music start with $00). The locations for the master playlist are as follows:
- Master Playlist in Sonic 2 Beta: $ECE9F
- Master Playlist in Sonic 2 Final: $ECF36
As previously mentioned, track 81 is represented by $80, 82 is reresented by $81, etc. If you see an $FF, skip it and move on to the next byte - these are compression bytes for the driver, and touching them will bork the decompressor in-game, and prevent the sound driver from booting. The "master playlist" is only in Sonic 2 (Beta/Final) as far as I know. If I find it in any other games, I will update this section.
Music Compression
In Sonic 2 Final, there is a compression applied to all music data in the game except for the credits. This format has been dubbed the saxman compression, named after the person who cracked the format. I will not note how to manually decompress this format -- Refer to saxman's hacking guide to do so. The music can be decompressed by using Magus' Sega Data Compressor. Refer to the pointer format to edit the music properly.
Sonic 3
Universal Voice Bank
In Sonic 3, some songs have the value "$D817" as their voice pointer. When a song has this in its voice pointer, that means it's being prepped to use a global set of multiple voices that any song in the game can use. This is generally used to save space for songs that use the same voices. Interestingly enough, though, the Special Stage music has the first 5 voices used in the Universal Voice Bank, and all in the same order, so it's puzzling why they didn't just have the song use the bank (as it's fully capable of doing so).
- Universal Voice Bank in Sonic 3: $E77D8
Universal Voice Bank definitions
Using the Universal Voice Bank is akin to using voices in a normal song - each voice has a value, defined by coordination flag $EF. Here are some of the voices used in the Universal Voice Bank.
Value | Description |
---|---|
$00 | Synth Bass 2 |
$01 | Trumpet 1 |
$02 | Slap Bass 2 |
$03 | Synth Bass 1 |
$04 | Bell Synth 1 |
$05 | Bell Synth 2 |
$06 | Synth Brass 1 |
$07 | Synth like Bassoon |
$08 | Bell Horn type thing |
$09 | Synth Bass 3 |
$0A | Synth Trumpet |
$0B | Wood Block |
$0C | Tubular Bell |
$0D | Strike Bass |
$0E | Elec Piano |
$0F | Bright Piano |
$10 | Church Bell |
$11 | Synth Brass 2 |
$12 | Bell Piano |
$13 | Wet Wood Bass |
$14 | Silent Bass |
$15 | Picked Bass |
$16 | Xylophone |
$17 | Sine Flute |
$18 | Pipe Organ |
$19 | Synth Brass 2 |
$1A | Harpischord |
$1B | Metallic Bass |
$1C | Alternate Metallic Bass |
$1D | Backdropped Metallic Bass |
$1E | Sine like Bell |
$1F | Synth like Metallic with Small Bell. |
$20 | Nice Synth like lead. |
$21 | Rock Organ |
$22 | Strike like Slap Bass |
Realtime Music Editing
By editing values in savestates, you can edit music, pointers and other various values in realtime. Re-load the savestate to see your changes applied!
Sonic 3/Sonic & Knuckles
Offset | Z80 RAM Location | Purpose |
---|---|---|
$001A8C | 1618 | Music Pointers (Sonic & Knuckles) |
$001A8E | 161A | Music Pointers (Sonic 3) |
$001778 | 1304 | Pointer for Music Pointers |
$000FD9 | 0B65 | Music Bank IDs (Sonic & Knuckles) |
$000FBC | 0B48 | Music Bank IDs (Sonic 3) |
$00177A | 1306 | Pointer for Sound Effect Pointers |
$001AF2 | 167E | Sound Effect Pointers |
Sonic 3D
Offset | Z80 RAM Location | Purpose |
---|---|---|
$001AD0 | 165C | Music Pointers |
$001778 | 1304 | Pointer for Music Pointers |
$00177A | 1306 | Pointer for Sound Effect Pointers |
$001AD0 | 165C | Music Pointers |
$001B34 | 16C0 | Sound Effect Pointers |
Sonic 2 Final
Offset | Z80 RAM Location | Purpose |
---|---|---|
$001669 | 11F5 | Master Playlist |
$000C16 | 07A2 | Pointer for Master Playlist |
$000DF9 | 0985 | Pointer for Sound Effects list |