Capcom "6C80" Sound Engine/Music Format Documentation ======================================= version 0.3 (??th ? 2008) by Matrixz Games that use this sound engine -------------------------------- DarkWing Duck (Has no bankswitching code) MegaMan 3 MegaMan 4 MegaMan 5 MegaMan 6 Mighty Final Fight TaleSpin The Little Mermaid Wily and Light's Rockboard Other games i think use this sound engine (or a similiar variant) ------------------------------------------------------------------ Adventures in the Magic Kingdom Destiny Of An Emperor 2 Chip' n' Dale Chip' n' Dale 2 Gargoyle's Quest 2 Little Nemo: The Dream Master (Has no bankswitching code) Duck Tales 2 Street Fighter 2010 6C80?? ------ Had to give the thing a name, so i did after what's usually byte 2 and 3 in the sound engine. Acknowledgements ---------------- Credits to Sephiroth3 for insight on music data. This is an age-old document which were updated as a result of personal use, and so i decided to improve it even more and do a new release. Game-specific notes ------------------- Darkwing Duck / Little Mermaid: Darkwing Duck uses MMC1 mapper board, and Little Mermaid uses UxROM (Mapper #2). Still, the sound engine in both games has bankswitching code which is designed for MMC3. But, the bankswitching is never done in either game due to only having one sound bank. (MMC1/UxROM ROM bank on $4000 bytes) Song Banks ====================================== I belive that all games using this format uses the MMC3 mapper. The games uses two 8kb rom banks for the sound engine, music and sound effects wich is loaded to $8000 and $A000 in the memory map. And in the games i've seen, an extra 8kb bank is disposed for extra music or/and sound effects, which is swapped into $A000. These can be any of the switchable 8kb banks in the rom. To find the start of the sound engine bank, open the rom in a hex editor and try searching for $4C,$6C,$80. Here is a little list of bank adresses in some games: Sound Engine/ Additional BGM/SFX BGM/SFX 2 BGM/SFX Bank - Adress - Bank - Adress - Bank - Adress MMC3 games: MegaMan 3: $16 - $2C010 $17 - $2E010 $18 - $30010 MegaMan 4: $1E - $3C010 $1F - $3E010 $1D - $3A010 MegaMan 5: $18 - $30010 $19 - $32010 $1A - $34010 MegaMan 6: $34 - $68010 $35 - $6A010 $36 - $6C010 MMC1 games (All data is in a 16k bank ($4000 bytes)): Darkwing: $03 - $C010 Moving on, i will use Megaman 3 as an example for rom offsets. Song/Sound Effect Adress Table ============================== The song adress table is in the 1st bank (Sound Engine Bank). As far as i know, the address table is always at the offset of the Sound Engine Bank + $A43. In Megaman 3 this is at $2CA53. From there is a 2-byte pointer for every song and sound effect, in Big-Endian order (High byte then Low byte). Songs and sound effects are mixed together. These are NES Memory pointers, so you'll have to convert them to ROM pointers to find them in the rom. How-to: Subtract $8000 and add the offset of the Sound Engine Bank. This approach should always work, except if the bank layout is not straight-forward, as is the case with Mega Man 4. For Megaman 4, $A000 converts to $3E010 (start of 2nd bank), while $C000 converts to $3A010 (start of 3rd bank). Example: Song pointer: $81A5 Sound Engine Bank adress: $30010 This means, the rom offset of the song is $301B5 Megaman 3 Example ----------------- As said before, the ROM address of the Song/SFX Address Table is at $2CA53. Let's find the ROM offset of Needleman's music. Needleman's music is the 2nd track of the game. One method to find the pointer to the song is do some math: ([song index-counting from 0] * 2) + $2CA53. Counting from 0? Yes, when doing the math above, the song index must be the song index, where the 1st song is 0. In other words, the NSF song index, minus 1. Just for those not familiar with Base 0 indexing. Anyway, the pointer for Needleman's music, which is song #1 (counting from 0.): (1 * 2) + $2CA53 Easy math, the result is $2CA55. Now, looking at $2CA55: We see teh giant flyin cow!11 Instrument Table ================ The instrument table is a series of 8-byte chunks which is used globally for all songs and sound effects. The information it holds is volume envelope info, volume and pitch vibration depth/speed, and a random noise flag when used with the NES noise channel. There can be any number of instruments. It seems those used for music are usually found first, and those used for sound effects come as the second half. The location of the Instrument Table is by default after the Song/SFX Address Table. It has a pointer pointing to it, so that the sound engine knows where the Instrument Table is located. This is right before the Song/SFX Address Table, at Sound Engine Bank offset + $A41. Just like songs/sfx pointers, this is a Big-Endian memory pointer. See the Instruments section at the end of the document for detailed info on instrument bytes. Song Format =========== If the first byte in the song is 0, it's a song. Or else, it's actually a sound effect. The song is divided into 4 channels: Square 1, Square 2, Triangle (Bass, Bassdrums etc.) and Noise (Used as drums etc.) Following the first byte, comes four 2-byte-pointers, wich points to the start of the data for each channel. These work exactly in the same manner as the pointers in the song adress table, so: Just subtract $8000 and add the adreess of the Sound Engine Bank to do that. The channel data is mixed up of commands and notes. Commands tells how the notes shall sound, controls loops, tempo etc. They can use one or more operands to them. In my list, a +[?] means a operand on one byte. Here is a list of commands. All the ID's are in, but im not sure how all works yet. ------------------------------------------------------------------------------------------------------ ID Name Operands Comment ------------------------------------------------------------------------------------------------------ 00 Triplet Connect notes to make a triplet. 01 Connect Connect note length of one or more notes. (Use before notes) 02 PlusHalf Adds 1/2 length to the note following this command. 03 OctPlus Swap Octave by 2 upwards, on and off. 04 Set Flags +[Value] Set some flags. See "Command $04 Flags." 05 Speed +[High],+[Low] Higher Value means Higher Speed. Default: 01,00 06 Length +[Time] Set Tone Lenght. $00 to $FF. 07 Volume +[Volume] Set Volume ($00 - $0F) 08 Instrument +[Instrument] Set Instrument to use. 09 Octave +[Octave] Set Octave (0-7, 8 and 9 is lower than 0. A equals 0) 0A Global Transpose +[Value] Transpose All Channels. Default: 00 0B Transpose +[Value] Transpose for Channel. Default: 00 0C Tune +[Value] Tune Pitch. Lower val=Higher, Higher val=Lower pitch. Default: 00 0D Slide +[Speed] Pitch slide between notes. 0E Loop1 +[Times]+[High]+[Low] Loop, Counter 1. Times = Logical # of Times 0F Loop2 +[Times]+[High]+[Low] Loop, Counter 2 Depth. Times = Logical # of Times 10 Loop3 +[Times]+[High]+[Low] Loop, Counter 3 Depth. Times = Logical # of Times 11 Loop4 +[Times]+[High]+[Low] Loop, Counter 4 Depth. Times = Logical # of Times 12 Break1 +[Flags]+[High]+[Low] Jump to Address if Loop1 is at last round, set flags to [Flags] 13 Break2 +[Flags]+[High]+[Low] Jump to Address if Loop2 is at last round, set flags to [Flags] 14 Break3 +[Flags]+[High]+[Low] Jump to Address if Loop3 is at last round, set flags to [Flags] 15 Break4 +[Flags]+[High]+[Low] Jump to Address if Loop4 is at last round, set flags to [Flags] 16 Jump +[High]+[Low] Jump to Adress 17 End Channel End 18 Tone Type +[Type] Bits 0-1: Duty Cycle, bits 2-7: Downslide Speed???/Volume? Here is a list of note byte ID's: -------------------------------- ID Note Lenght -------------------------------- 20 Delay 64th 21 C-1 64th 22 C#1 64th 23 D-1 64th 24 D#1 64th 25 E-1 64th 26 F-1 64th 27 F#1 64th 28 G-1 64th 29 G#1 64th 2A A-1 64th 2B A#1 64th 2C B-1 64th 2D C-2 64th 2E C#2 64th 2F D-2 64th 30 D#2 64th 31 E-2 64th 32 F-2 64th 33 F#2 64th 34 G-2 64th 35 G#2 64th 36 A-2 64th 37 A#2 64th 38 B-2 64th 39 C-3 64th 3A C#3 64th 3B D-3 64th 3C D#3 64th 3D E-3 64th 3E F-3 64th 3F F#3 64th -------------------------------- 40-5F = 32th Note 60-7F = 16th Note 80-9F = 8th Note A0-BF = Quarter Note C0-DF = Half Note E0-FF = Whole Note The following ID's also have delay and the notes from C-1 to F#3, just with different lenght. You can just look up the table above. Detailed Information on Commands ================================ 00: Triplet ----------- This connects series of 3 notes together to make a single unit. The number of notes connected should be dividable by 3, it seems. If not, the channel will eventually go out of sync with the other channels. Usage: 0,$81,$83,$85,0 0,$81,$83,$85,$87,$89,$8B,$8F,0 01: Connect ----------- This will combine the note length of two or more notes. This command is used before the first note to connect, and before the last note to connect, in order to disable it. Example: 1,$85,1,$45 ;E-1 It is possible to change instrument settings and the like between the two notes. This method is used to start a vibrato effect in the middle of a note, but technically it is two notes made to be one. Example: $08,$04 ;Set instrument to $04. Has no vibrato. $01 ;Begin connect. $85 ;1/2 of the note $08,$05 ;Set instrument to $05. Has vibrato. $01 ;End connect $85 ;2/2 of the note 02: PlusHalf ------------ Adds one half length of the note length to the note following this command, making it half a time longer. Note: It seems this doesn't work for Whole Note ($E0-$FF). Usage: 2,$85,2,$85 06: Length ---------- This sets how long the note is held, but doesnt affect the synchronicity of the notes. It seems for most instruments, the higher the operand value of this command is, the longer the note will be "held" in, while for other instruments, the lesser the value is, the longer. 08: Instrument -------------- Chooses an instrument from the instrument table to use for various effects. Break Function: --------------- If (Loop Counter - 1) = 0: Set Loop Counter to 0. Jump. 17: End ------- This command isn't really neccesary for looped channels. Command $04 and Break Command Flags =========================== MSB bit0: Disable Pitch Effects? bit1: Disable Certain Instruments (for a while) ??? bit2: Fast Speed..? bit3: Smal Delay bit4: Higher Octave bit5: -- bit6: -- bit7: -- LSB Sound Effects ============= Sound Effect Data: BYTE Sound Effect Priority. Must be >0. Usually below 9. If a sound effect is init'ed while another sound effect is playing, this byte decides which should be given priority. In other words, in such a case it will only play the sound effect if this byte is greater than the Priority byte of the sound effect that is already playing. bit0: Play forever? (If set.) Chunk data: BYTE Command Enable Bits A MSB bit0: Bit Flag : End bit5: Bit Flag : ?? bit6: Bit Flag : Note Length bit7: Bit Flag : Loop Bit LSB If the first bit is set, it means the end of the sound effect's data. If Bit Flag : Loop Bit is Set ( = 1) {BYTE Loop Times } {WORD Pointer } (In the case of a loop, it will jump to the pointer's location or continue after the word pointer, and the rest of the data is ignored. It seems the next thing it does in either case is start read a new chunk. If Bit Flag : Note Length is Set ( = 1) {BYTE Note Length (?) } BYTE Length of note, in Vblank frames. BYTE NES Channels to use (More than one can be used.) MSB bit4: Noise bit5: Triangle bit6: Square 2 bit7: Square 1 LSB For each used channel { BYTE Command Enable Bits B MSB bit3 : Bit Flag : ?? bit4 : Bit Flag : Pitch Slide Byte bit5 : Bit Flag : Volume Byte bit6 : Bit Flag : Duty Cycle Byte bit7 : Bit Flag : Instrument Byte LSB If Bit Flag : Instrument Byte is Set ( = 1) {BYTE Instrument } If Bit Flag : Duty Cycle Byte is Set ( = 1) {BYTE Duty Cycle } If Bit Flag : Volume Byte is Set ( = 1) {BYTE Volume Byte } If Bit Flag : Pitch Slide Byte is Set ( = 1) {BYTE Pitch Slide Byte } BYTE Note } After finishing playing the chunk, it starts read a new chunk. Instrument, Duty Cycle and Volume Byte functions the same way as for music. Instruments =========== Each instruments has 8 bytes. 0: Initial Volume. 1: Immediate Volume Fade Rate 2: bit0-bit3: Immediate Volume Fade Destination Volume 3: Note off Volume Fade Rate 4: Pitch/Volume Vibrato Speed bit0: New note - Vibrato Reset Bit bit1-bit7: Pitch/Volume Vibrato Speed 5: Pitch Vibrato Depth 6: Volume Vibrato Depth 7: MSB bit0: Random Noise Flag. (For Noise Channel) bit1-7: ??? Changing this seems to affect sound, but i've never seen it used. LSB