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 |
Contents
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 "Option 2" DPCM, where the difference between consecutive samples (the delta) is quantized. Note that, because the deltas themselves are quantized, there is an inherent loss of precision compared to the 8-bit unsigned LPCM. The quantized deltas are stored into a dictionary (which, in this case, is usually called delta array by Sonic hackers), which may or may not be the same in all samples; in either case, games using this format use 4-bit indices to index the delta array, which gives a 50% reduction in file size at some quality loss.
Most SMPS games use the following delta array for all samples:
db 0, 1, 2, 4, 8, 10h, 20h, 40h db -80h, -1, -2, -4, -8, -10h, -20h, -40hjman2050 wrote a "compressor/decompressor" to convert samples stored in this format to standard 8-bit LPCM and vice versa. A better alternative to jman2050's program would be the pcm2dpcm and dpcm2pcm tools included in ValleyBell's SMPS Research Pack, which checks for overflow when converting to DPCM to prevent clipping.
Some games use different delta arrays in some or all cases:
- 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 of each sample as the first 16 bytes of the sample.
- Pre-SMPS games often use a different delta array. This is the delta array for Rent A Hero:
db 1, 3, 6, 0Ch, 18h, 28h, 50h, 90h db -1, -3, -6, -0Ch, -18h, -28h, -50h, -90h
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.
Mega-CD
Each SMPS-PCM bank has a table of samples which are stored as 8-bit sign-magnitude; the same format as the Mega-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: $00D6
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 Simon Wai Beta: $ECDA6 ($0F75 in Z80 RAM)
Specifics...
ROM Offset | Z80 Offset | Description |
---|---|---|
$ECDA6 | $0F75 | Sample 81 pointer |
$ECDA8 | $0F77 | Sample 81 length |
$ECDAA | $0F79 | Sample 82 pointer |
$ECDAC | $0F7B | Sample 82 length (skip FF) |
$ECDAF | $0F7D | Sample 83 pointer |
$ECDB1 | $0F7F | Sample 83 length |
$ECDB3 | $0F81 | Sample 84 pointer |
$ECDB5 | $0F83 | Sample 84 length (skip FF) |
$ECDB8 | $0F85 | Sample 85 pointer |
$ECDBA | $0F87 | Sample 85 length |
$ECDBC | $0F89 | Sample 86 pointer |
$ECDBE | $0F8B | 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 ($1233 in Z80 RAM)
Specifics...
ROM Offset | Z80 Offset | Description |
---|---|---|
$ECF7C | $1233 | Sample 81 pointer |
$ECF7E | $1235 | Sample 81 length |
$ECF81 | $1237 | Sample 82 pointer |
$ECF83 | $1239 | Sample 82 length |
$ECF85 | $123B | Sample 83 pointer |
$ECF87 | $123D | Sample 83 length |
$ECF8A | $123F | Sample 84 pointer |
$ECF8C | $1241 | Sample 84 length |
$ECF8E | $1243 | Sample 85 pointer |
$ECF90 | $1245 | Sample 85 length |
$ECF93 | $1247 | Sample 86 pointer |
$ECF95 | $1249 | Sample 86 length |
$ECF97 | $124B | Sample 87 pointer |
$ECF99 | $124D | 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 are editing the compressed driver data and see an FF, skip it and move on to the next byte.
DAC Master list
- DAC Master List in Sonic 2 Beta: $ECDC1 ($0F8D in Z80 RAM)
- DAC Master List in Sonic 2 Final: $ECF9C ($124F in Z80 RAM)
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 are editing the compressed driver data and 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.
note: flamewing and andlabs are updating the Sega Retro version for non-Sonic game versions of the SMPS driver, while I, kram1024 am updating the Sonic Retro version, so that all differences between sonic 1, 2, and 3 can be seen. Flamewing has given me permission to do this.
what are all these parameter bytes?
Coordinance flags most of the time have parameters to tell the flags what to to just as any commandline does or even the asm in your disassembly do. Here is a list of things in that area and what they mean:
Symbol | What it is |
---|---|
[ww] | the bits or nibbles inside the brackets are a parameter that the flag actually uses. |
{xx} | the bits or nibbles inside the braces are a parameter that the flag could use in certain situations. |
$ | data is represented in hex (0-9,A-F) and can be a byte, word, or long word. |
% | data is represented in binary (0 and 1) and can be a byte, word, or long word. |
Sonic 1
These are the coordinance flags after Flamewing's research completed.
Flag | Parameters | Purpose |
---|---|---|
$E0 | %[l][r][aaa]0[ff] | Alter panning. Does not work for PSG tracks. The flag can be used to alter AMS and FMS, but it is not meant to; it can only set those bits if they were zero to begin with — you can never clear them. Has one parameter byte. |
$E1 | $[ff] | Set the channel frequency displacement to the parameter byte (signed). |
$E2 | $[vv] | Sets RAM variable at $FFFFF007 to the parameter byte. Useless |
$E3 | none | Return from subroutine. See also coord. flag $F8. No parameters. |
$E4 | none | Stops the track and initiates a fade-in to previous song. Has no parameters (not that it matters...). Can be in any channel; since the DAC channel is the first to be run, this prevents note artifacts from the other channels if placed on it. |
$E5 | $[tt] | Set dividing timing for the current track to the parameter byte. |
$E6 | $[vv] | Add parameter byte to volume attenuation, effective immediately. This is not intended for PSG tracks, and will wreak havoc on unrelated FM tracks if used on a PSG track. (This flag is designed for FM channels) |
$E7 | none | Prevent note from attacking. This is reset after every note expires; so to keep it going, you must put this coordination flag before each note you wish to effect. No parameters. |
$E8 | $[ff] | Sets note fill to the parameter byte. The note fill is a timeout: the number of frames during which the note will be allowed to play. After that, the note will be killed and will stay dead until it is time for another note. |
$E9 | $[ff] | Adds (signed) parameter to channel key displacement. |
$EA | $[tt] | Set main tempo to the parameter byte. Only affects music, not SFX. Has immediate effect, and may shorten the currently playing notes on all tracks. |
$EB | $[dd] | Sets dividing timing to be equal to the parameter byte for all *music* tracks — it does not effect SFX. |
$EC | $[vv] | Changes channel volume by adding the parameter byte (signed) to the track's volume. For FM channels, only takes effect on the next voice change. (This flag is designed for PSG channels) |
$ED | none | Clears 'pushing block' flag. This flag is set when SFX $A7 is played, and prevents it from playing again. No parameters. |
$EE | none | Stops a track. This coordination flag assumes that the track in question is channel FM4 for a sound effect with index $D0-$DF, so don't use it for anything else. If the FM4 channel was being overridden by a normal sound effect, nothing else happens; otherwise, it will upload the current FM4 instrument for the currently playing music. No parameters. |
$EF | $[vv] | Change FM instrument to parameter byte. Uploads the corresponding instrument to the YM2612, which means: NOT for PSG or DAC. |
$F0 | $[ww][mm][cc][ss] | Sets modulation parameters and enables it. Takes 4 1-byte parameters, which are, in order: wait speed before modulation starts, modulation speed, change per step, number of steps. Using this flag will clear accumulated modulation. A wait of zero means no wait; compare with equivalent Sonic 3+ flag. |
$F1 | none | Enables modulation. Can be safely used only after coord. flag $F0 has been used for the current track. No parameters. |
$F2 | none | Stop track. FM voices and PSG noise tones are updated if needed. |
$F3 | $[nn] | Sets PSG track to noise and sets PSG noise to parameter byte, which should be from $E0 to $E7 (inclusive). The transformation into a noise channel is irreversible. |
$F4 | none | Disable modulation. No parameters. |
$F5 | $[tt] | Change PSG tone (index into flutter table) to parameter byte. |
$F6 | $[dddd] | Jump to target location. Parameter is 2-byte Big Endian offset to target location that points to one more than the offset says. |
$F7 | $[ll][cc][dddd] | Repeat section of music. Has 4 bytes of parameters: a 1-byte loop index, a 1-byte repeat count and a 2-byte target for jump. Jump target is 2-byte Big Endian offset to target location that points to one more than the offset says. |
$F8 | $[dddd] | Call subroutine. Stores current location for use with coord. flag $E3. Parameter is 2-byte Big Endian, signed, relative offset to target location that points to one more than the offset says. |
$F9 | none | Sets D1L to maximum volume (minimum attenuation) and RR to maximum for operators 3 and 4 of FM1. Does not have parameters. |
If it is not on this table and your sound driver is the sonic 1 driver and you did not create any more new flags, then any others past this point do not exist and anyone who tries to add such nonexistent flags to their music is a stupid idiot and thus will not be taken seriously.
Sonic 2
These are the coordinance flags after Flamewing's research completed.
Flag | Parameters | Purpose |
---|---|---|
$E0 | %[l][r][aaa]0[ff] | Alter panning. Does not work for PSG tracks or if set to not attack on the next note. The flag can be used to alter AMS and FMS, but it is not meant to; it can only set those bits if they were zero to begin with — you can never clear them. Has one parameter byte. |
$E1 | $[ff] | Set the channel frequency displacement to the parameter byte (signed). |
$E2 | $[vv] | Sets z80 RAM variable at $1B86 to the parameter byte. Useless |
$E3 | none | Return from subroutine. See also coord. flag $F8. No parameters. |
$E4 | none | Stops the track and initiates a fade-in to previous song. Has no parameters (not that it matters...). Can be in any channel; since the DAC channel is the first to be run, this prevents note artifacts from the other channels if placed on it. |
$E5 | $[tt] | Set dividing timing for the current track to the parameter byte. |
$E6 | $[vv] | Add parameter byte to volume attenuation, effective immediately. This can be used on FM and PSG tracks. |
$E7 | none | Prevent note from attacking. This is reset after every note expires; so to keep it going, you must put this coordination flag before each note you wish to effect. No parameters. |
$E8 | $[ff] | Sets note fill to the parameter byte. The note fill is a timeout: the number of frames during which the note will be allowed to play. After that, the note will be killed and will stay dead until it is time for another note. |
$E9 | $[ff] | Adds (signed) parameter to channel key displacement. |
$EA | $[tt] | Set main tempo to the parameter byte. Only affects music, not SFX. |
$EB | $[dd] | Sets dividing timing to be equal to the parameter byte for all *music* tracks — it does not effect SFX. |
$EC | $[vv] | Changes channel volume by adding the parameter byte (signed) to the track's volume. For FM channels, only takes effect on the next voice change. |
$ED | $[vv] | Does nothing but eat one parameter byte. |
$EE | none | Does nothing. No parameters. |
$EF | $[vv] | Change FM instrument to parameter byte. Uploads the corresponding instrument to the YM2612, which means: NOT for PSG or DAC. |
$F0 | $[ww][mm][cc][ss] | Sets modulation parameters and enables it. Takes 4 1-byte parameters, which are, in order: wait speed before modulation starts, modulation speed, change per step, number of steps. Using this flag will clear accumulated modulation, but only if 'do not attack next note' is *not* set. A wait of zero means no wait; compare with equivalent Sonic 3+ flag. |
$F1 | none | Enables modulation. Can be safely used only after coord. flag $F0 has been used for the current track. No parameters. |
$F2 | none | Stop track. FM voices and PSG noise tones are updated if needed. |
$F3 | $[nn] | Sets PSG track to noise and sets PSG noise to parameter byte, which should be from $E0 to $E7 (inclusive). The transformation into a noise channel is irreversible. |
$F4 | none | Disable modulation. No parameters. |
$F5 | $[tt] | Change PSG tone (index into flutter table) to parameter byte. |
$F6 | $[dddd] | Jump to target location. Parameter is a pointer to target location. |
$F7 | $[ll][cc][dddd] | Repeat section of music. Has 4 bytes of parameters: a 1-byte loop index, a 1-byte repeat count and a 2-byte target for jump. Jump target is a pointer to target location. |
$F8 | $[dddd] | Call subroutine. Stores current location for use with coord. flag $E3. Parameter is a pointer to target location. |
$F9 | none | Sets D1L to maximum volume (minimum attenuation) and RR to maximum for operators 3 and 4 of FM1. Does not have parameters. |
If if is not on this table and your sound driver is the sonic 2 driver and you did not create any more new flags, then any others past this point do not exist and anyone who tries to add such nonexistant flags to their music is a stupid idiot and thus will not be taken seriously.
Sonic 3 and beyond
These are the coordinance flags after Flamewing's research completed.
Flag | Parameters | Purpose | |||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
$E0 | %[l][r][aa]0[ff] | Alter panning. Does not work for PSG tracks or if set to not attack on the next note. The flag can be used to alter AMS and FMS, but it is not meant to; it can only set those bits if they were zero to begin with — you can never clear them. Has one parameter byte. | |||||||||||||||||||||||||||
$E1 | $[ff] | Set the channel frequency displacement to the parameter byte (signed). | |||||||||||||||||||||||||||
$E2 | $[ii] | Set 'fade to previous' flag to parameter byte. If this is equal to $29 (one less than 1-Up ID), nothing much will happen: the sound driver will prevent new SFX and music from being played (except for the 1-Up music and the credits music). If the parameter if $FF, it will trigger a fade to the previous song. If set to anything else, the sound driver will play all queued songs and SFX and will not fade in. Note that, unlike what happens in Sonic 1 or Sonic 2, this flag does not stop the track! | |||||||||||||||||||||||||||
$E3 | none | Silences FM channel then stops track (exactly as per coord. flag $F2). | |||||||||||||||||||||||||||
$E4 | $[vv] | 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. | |||||||||||||||||||||||||||
$E5 | $[ii][vv] | Almost exactly like coord. flag $E6, except that it has two 1-byte parameters, the first of which is ignored and the second of which is added to the volume attenuation. | |||||||||||||||||||||||||||
$E6 | $[vv] | Adds the parameter byte to the volume attenuation of an FM channel. The result is clamped to the [0-127] range. Has one parameter byte, the change in volume attenuation. | |||||||||||||||||||||||||||
$E7 | none | Prevent note from attacking. This is reset after every note expires; so to keep it going, you must put this coordination flag before each note you wish to effect. No parameters. | |||||||||||||||||||||||||||
$E8 | $[ff] | Sets note fill to the parameter byte multiplied by the current tempo divider. The note fill is a timeout: the number of frames after during which the note will be allowed to play. After that, the note will be killed and will stay dead until it is time for another note. Note that, while similar, this coordination flag is different from that of Sonic 1 or Sonic 2. | |||||||||||||||||||||||||||
$E9 | none | Spindash rev. Increases track key displacement by a cumulative value. Due to what is likely a bug, this cumulative value increases without bound, and so does the tracks' key displacement. For all but the spindash SFX and for continuous SFX (see below), the cumulative key displacement is reset when the a new SFX is started. No parameters. See also meta coord. flag $FF,$07. | |||||||||||||||||||||||||||
$EA | $[ss] | Play DAC sample. The DAC sample is queued for play after V-Int ends, as if it had been set from a DAC track. Note that this can be used from FM and PSG tracks, and it can be used from SFX tracks (which are otherwise unable to play DAC samples); in these cases, the sample set from the DAC channel will not be played. | |||||||||||||||||||||||||||
$EB | $[ll][dddd] | Conditional jump. This works in tandem with coord. flag $F7; it shares the same loop counters as it does, and relies on that flag to update them. If the loop counter is exactly 1 (that is, the next encounter with coord. flag $E7 will reduce it to zero), the loop counter will be cleared and the jump will be performed; otherwise, this coord. flag does nothing. Has 3 parameter bytes: a 1-byte loop index and a pointer to target for jump. | |||||||||||||||||||||||||||
$EC | $[vv] | Change volume attenuation of PSG track. The single parameter byte is added to track's current volume attenuation; anything greater than $0F (unsigned comparison) is set to $0F (silence). Also, the flutter index is reduced by 1. | |||||||||||||||||||||||||||
$ED | $[ff] | Set track's key displacement. The key displacement is set to be the parameter byte minus $40. | |||||||||||||||||||||||||||
$EE | $[rr][vv] | Send command to YM2612. The commands are written to $4000, and the data to $4001, so not all YM2612 registers can be set this way (in particular, FM4, FM5 and FM6 can't be changed by this in general). | |||||||||||||||||||||||||||
$EF | $[vv]{ii} | Sets new FM instrument/PSG tone. If the parameter byte is positive, this coord. flag has a single parameter byte; if it is negative, then the coord. flag will have two parameter bytes. For PSG tracks, the second byte (if present) will be ignored, and the first is the index in PSG tone table. For FM channels, the first byte (stripped of sign) is the index of FM instrument on the appropriate voice table. If the first byte was positive, this voice table is the one set for the track at the music/SFX headers. If the first byte was negative, then the voice table will be that of the song whose ID +$81 is specified on the second parameter byte. | |||||||||||||||||||||||||||
$F0 | $[ww][mm][cc][ss] | Sets modulation parameters and enables it. Takes 4 1-byte parameters, which are, in order: wait speed before modulation starts, modulation speed, change per step, number of steps. This is the normal ($80) modulation type. A wait of zero is equal to 256; compare with equivalent Sonic 1 and Sonic 2 flag. | |||||||||||||||||||||||||||
$F1 | $[ff][pp] | Set modulation type for current track. Has two 1-byte parameters, the modulation type for FM tracks and the modulation type for PSG tracks. $80 is normal modulation, and should be used only after coord. flag $F0 is used or all hell will break loose. $00 is no modulation. For nonzero values, this is frequency flutter (jitter?) which FM and non-noise PSG tracks can use. This frequency flutter should only be used if you know what you are doing — particularly since it is very buggy, and prone to reading data from the code section. | |||||||||||||||||||||||||||
$F2 | none | Stop track. | |||||||||||||||||||||||||||
$F3 | $[nn] | If parameter byte is zero, the channel is converted back into a normal PSG channel and the noise channel is silenced. Otherwise, sets the PSG track to noise and sets PSG noise to parameter byte, which should be from $E0 to $E7 (inclusive). | |||||||||||||||||||||||||||
$F4 | $[vv] | Like coord. flag $F1, but has only one parameter byte which is used as the new modulation type for FM and PSG tracks alike. | |||||||||||||||||||||||||||
$F5 | $[tt] | Set PSG tone to parameter byte. Does nothing for FM tracks. | |||||||||||||||||||||||||||
$F6 | $[dddd] | Jump to target location. Parameter is a pointer to target location. | |||||||||||||||||||||||||||
$F7 | $[ll][cc][dddd] | Repeat section of music. Has 4 bytes of parameters: a 1-byte loop index, a 1-byte repeat count and a pointer to target location. Can be used with coord. flag $EB, see it for details. | |||||||||||||||||||||||||||
$F8 | $[dddd] | Call subroutine. Stores current location for use with coord. flag $F9. Parameter is a pointer to target location. | |||||||||||||||||||||||||||
$F9 | none | Return from subroutine. See also coord. flag $F8. No parameters. | |||||||||||||||||||||||||||
$FA | none | Disable normal ($80) modulation type, or clears bit 7 of other types. No parameters. | |||||||||||||||||||||||||||
$FB | $[ff] | Adds parameter to track's key displacement. Has one parameter. | |||||||||||||||||||||||||||
$FC | $[dddd] | For continuous SFX, will loop the SFX a number of times equal to its total track count (FM + PSG) then stop. If the current SFX is queued to be played again, this counter will be reset instead, and the SFX will keep looping. Does nothing for non-continuous SFX. Has a 2-byte parameter, a pointer to the jump target. | |||||||||||||||||||||||||||
$FD | $[aa] | If parameter byte is 1, enables alternate SMPS mode for track; if not 1, alternate SMPS mode is disabled. | |||||||||||||||||||||||||||
$FE | $[aa][bb][cc][dd] | WARNING! for experts only! Put FM3 in special mode. The code is very buggy, and will overwrite the switch table handler of the meta coord. flag $FF (see below), and it will also read frequency data from random parts of the code section when it is time to send it to the YM2612. Don't use unless you are willing to fix the bugs first. Has 4 1-byte parameters. | |||||||||||||||||||||||||||
$FF | at least one byte | Meta coordination flag: unfolds into 8 coordination flags, which are selected using the first parameter. Values of $00 to $07 are valid; all others are invalid.
|
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 only switch back to a tone channel on certain drivers.
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 |
Dac Samples (By Game)
Sonic 1 (and 2)
Name | ID | Notes |
---|---|---|
Kick | $81 | |
Snare | $82 | |
Timpani | $83 | A Duplicate Of Hi-Timpani |
SegaPCM | $87 | |
Hi-Timpani | $88 | |
Mid-Timpani | $89 | |
Mid-Low-Timpani | $8A | |
Low-Timpani | $8A |
The Following are exclusive to Sonic 2
Name | ID | Notes |
---|---|---|
Clap | $83 | |
Scratch | $84 | |
Hi-Tom | $86 | |
Bongo | $87 | |
Mid-Tom | $8C | |
Low-Tom | $8D | |
Floor-Tom | $8E | |
Hi-Bongo | $8F | |
Mid-Bongo | $90 | |
Low-Bongo | $91 |
S3 S&K and S3D
Name | ID | Notes |
---|---|---|
Snare | $81 | |
Hi-Tom | $82 | |
Mid-Tom | $83 | |
Low-Tom | $84 | |
Floor-Tom | $85 | |
Kick | $86 | |
Muffled-Snare | $87 | |
Crash-Cymbal | $88 | |
Ride-Cymbal | $89 | |
Low-Metal-Hit | $8A | |
Metal-Hit | $8B | |
High-Metal-Hit | $8C | |
Higher-Metal-Hit | $8D | |
Mid-Metal-Hit | $8E | |
Clap | $8F | |
Electric-High-Tom | $90 | |
Electric-Mid-Tom | $91 | |
Electric-Low-Tom | $92 | |
Electric-Floor-Tom | $93 | |
Tight-Snare | $94 | |
Mid-Pitch-Snare | $95 | |
Loose-Snare | $96 | |
Looser-Snare | $97 | |
Hi-Timpani | $98 | |
Low-Timpani | $99 | |
Mid-Timpani | $9A | |
Quick-Loose-Snare | $9B | |
Click | $9C | |
Power-Kick | $9D | |
Quick-Glass-Crash | $9E |
The Following are exclusive to S3K.
Name | ID | Notes |
---|---|---|
GlassCrashSnare | $9F | |
GlassCrash | $A0 | |
GlassCrashKick | $A1 | |
QuietGlassCrash | $A2 | |
GlassCrashSnare | $A3 | |
OddSnareKick | $A4 | |
KickExtraBass | $A5 | |
ComeOn | $A6 | |
DanceSnare | $A7 | |
LooseKick | $A8 | |
ModLooseKick | $A9 | |
Woo | $AA | |
Go | $AB | |
SnareGo | $AC | |
PowerTom | $AF | |
HiWoodBlock | $B0 | |
LowWoodBlock | $B1 | |
HiHitDrum | $B2 | |
KickExtraBass | $B3 | |
LowHitDrum | $B4 | |
MetalCrashHit | $B5 | |
EchoedClapHit | $B6 | Different In S3 |
LowerEchoedClapHit | $B7 | Different In S3 |
HipHopHitKick | $B8 | |
HipHopHitPowerKick | $B9 | |
BassHey | $B9 | |
DanceStyleKick | $BA | |
HipHopHitKick2 | $BB | |
Unfinised |
References
|Music Hacking/DAC Samples, Game Specifics, and Real-Time Music Editing]]