Actions

SCHG

Difference between revisions of "Music Hacking/DAC Samples, Coordination Flags, Game Specifics, and Real-Time Music Editing"

From Sonic Retro

(Sonic 3 and beyond)
(Made explicit some information on fade flag in S1 and S2)
Line 168: Line 168:
 
|$E3||none||Return from subroutine. See also coord. flag $F8. No parameters.
 
|$E3||none||Return from subroutine. See also coord. flag $F8. No parameters.
 
|-
 
|-
|$E4||none||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.
+
|$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.
 
|$E5||$[tt]|| Set dividing timing for the current track to the parameter byte.
Line 227: Line 227:
 
|$E3||none||Return from subroutine. See also coord. flag $F8. No parameters.
 
|$E3||none||Return from subroutine. See also coord. flag $F8. No parameters.
 
|-
 
|-
|$E4||none||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.
+
|$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.
 
|$E5||$[tt]|| Set dividing timing for the current track to the parameter byte.
Line 283: Line 283:
 
|-
 
|-
 
|$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!
 
|$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).
 
|$E3||none||Silences FM channel then stops track (exactly as per coord. flag $F2).
Line 290: Line 289:
 
|-
 
|-
 
|$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.
 
|$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.
 
|$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.
 
|$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.

Revision as of 11:32, 18 October 2011

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, -40h
This form is almost always incorrectly referred to as "compressed;" jman2050
Sonic Retro
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:

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.
  • NOTE: Value is little endian, so swap the bytes to get the real value.
$02-$03 Word Size of the compressed DAC sample in decompressed driver.
  • NOTE: Value is little endian, so swap the bytes to get the real value.
$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.
  • NOTE: Value is little endian, so remember to swap the bytes to get the real value.
$03-$04 Word Pointer to the DAC sample, within the current bank.
  • NOTE: Value is little endian, so remember to swap the bytes to get the real value.

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][aa]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.
$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.
$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 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][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 $[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 (why you would even want to use it is beyond me, other than for the compressed module support) 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.
Metaflag Parameters Purpose
$00 $[tt] Set current main tempo to parameter byte.
$01 $[ii] Play sound by index. The parameter byte is the index of the music or SFX to play (same index as sound test).
$02 none Halts or resumes all music tracks. A halted track does not play. Any music or SFX can use this to halt music, but only SFX can then use it again to resume the music; the single parameter byte determines if the music is to be halted (nonzero) or resumed (zero).
$03 $[ssss][zz] WARNING! for experts only! Copy data. It has 3 bytes of parameters, a pointer to source of data and a 1-byte length of data to copy. The data is copied immediately after this coord. flag's parameters, and the song will continue after the last byte copied. This should only be used if the song has been stored in z80 RAM, and even then only if you know what you are doing.
$04 $[dd] Set dividing timing for music to the parameter byte. This does not effect SFX tracks.
$05 $[aa][bb][cc][dd] Set SSG-EG data for FM track. Has 4 1-byte parameters, the SSG-EG data for each operator of the current track.
$06 $[ii][mm] Start/end FM flutter. Has two 1-byte parameters: the index+1 of the PSG tone data to use and a bit mask indicating which TL operators should receive flutter (in the form %0004231). For best results, the bit mask should be (%00001000, %00001000, %00001000, %00001000, %00001010, %00001110, %00001110, %00001111) according to the current FM voice's algorithm (0-7). You can disable this flutter by having either or both parameters zero. A negative index causes all sorts of woe as it indicates custom SSG-EG data *instead*.
$07 none Reset spindash rev to zero. See also coord. flag $E9. No parameters.

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
Sonic Community Hacking Guide
General
SonED2 Manual | Subroutine Equivalency List
Game-Specific
Sonic the Hedgehog (16-bit) | Sonic the Hedgehog (8-bit) | Sonic CD (prototype 510) | Sonic CD | Sonic CD (PC) | Sonic CD (2011) | Sonic 2 (Simon Wai prototype) | Sonic 2 (16-bit) | Sonic 2 (Master System) | Sonic 3 | Sonic 3 & Knuckles | Chaotix | Sonic Jam | Sonic Jam 6 | Sonic Adventure | Sonic Adventure DX: Director's Cut | Sonic Adventure DX: PC | Sonic Adventure (2010) | Sonic Adventure 2 | Sonic Adventure 2: Battle | Sonic Adventure 2 (PC) | Sonic Heroes | Sonic Riders | Sonic the Hedgehog (2006) | Sonic & Sega All-Stars Racing | Sonic Unleashed (Xbox 360/PS3) | Sonic Colours | Sonic Generations | Sonic Forces
Technical information
Sonic Eraser | Sonic 2 (Nick Arcade prototype) | Sonic CD (prototype; 1992-12-04) | Dr. Robotnik's Mean Bean Machine | Sonic Triple Trouble | Tails Adventures | Sonic Crackers | Sonic 3D: Flickies' Island | Sonic & Knuckles Collection | Sonic R | Sonic Shuffle | Sonic Advance | Sonic Advance 3 | Sonic Battle | Shadow the Hedgehog | Sonic Rush | Sonic Classic Collection | Sonic Free Riders | Sonic Lost World
Legacy Guides
The Nemesis Hacking Guides The Esrael Hacking Guides
ROM: Sonic 1 | Sonic 2 | Sonic 2 Beta | Sonic 3

Savestate: Sonic 1 | Sonic 2 Beta/Final | Sonic 3

Sonic 1 (English / Portuguese) | Sonic 2 Beta (English / Portuguese) | Sonic 2 and Knuckles (English / Portuguese)
Move to Sega Retro
Number Systems (or scrap) | Assembly Hacking Guide | 68000 Instruction Set | 68000 ASM-to-Hex Code Reference | SMPS Music Hacking Guide | Mega Drive technical information