David Whittaker Sound Engine: Difference between revisions
KungFuFurby (talk | contribs) (Adding link to build engine sorting page) |
KungFuFurby (talk | contribs) (Adding some preliminary V2.0-V4.0b notes to pre-existing SFX) |
||
Line 95: | Line 95: | ||
|} | |} | ||
===Command IDs (V2.0- | ===Command IDs (V2.0-V4.0a)=== | ||
''TODO document V2.0 and up (some of this will occur on a per-game basis)'' | ''TODO document V2.0 and up (some of this will occur on a per-game basis)'' | ||
===Command IDs (V4. | ===Command IDs (V4.0b)=== | ||
''TODO document V2.0 and up (some of this will occur on a per-game basis)'' | ''TODO document V2.0 and up (some of this will occur on a per-game basis)'' | ||
Line 121: | Line 121: | ||
Resumes a paused song. | Resumes a paused song. | ||
===Play SFX (Command <tt>$04-$05</tt> (V0.0-V1.0), <tt>$04-$0B</tt> (V2.0- | ===Play SFX (Command <tt>$04-$05</tt> (V0.0-V1.0), <tt>$04-$0B</tt> (V2.0-V4.0a), <tt>$04</tt> (V4.0b))=== | ||
<pre>ii xx yz ??</pre> | <pre>ii xx yz ??</pre> | ||
Plays a piece of SFX. | Plays a piece of SFX. | ||
Line 130: | Line 130: | ||
*** Channel 7: <tt>$04</tt> | *** Channel 7: <tt>$04</tt> | ||
*** Channel 8: <tt>$05</tt> | *** Channel 8: <tt>$05</tt> | ||
** <u>V2.0- | ** <u>V2.0-V4.0a:</u> | ||
*** Channel 1: <tt>$04</tt> | *** Channel 1: <tt>$04</tt> | ||
*** Channel 2: <tt>$05</tt> | *** Channel 2: <tt>$05</tt> | ||
Line 139: | Line 139: | ||
*** Channel 7: <tt>$0A</tt> | *** Channel 7: <tt>$0A</tt> | ||
*** Channel 8: <tt>$0B</tt> | *** Channel 8: <tt>$0B</tt> | ||
** V4.0b instead dynamically allocates the channel that the SFX is played on. | |||
* <tt>xx</tt> defines the SFX ID. Setting the highest bit (covering IDs <tt>$80-$FF</tt> keys off the SFX instead of playing it. | * <tt>xx</tt> defines the SFX ID. Setting the highest bit (covering IDs <tt>$80-$FF</tt> keys off the SFX instead of playing it. | ||
** V1.0 and up have boundary checks that prevent invalid SFX IDs from being played, and only accept <tt>$FF</tt> as an ID to key off SFX on that channel. | ** V1.0 and up have boundary checks that prevent invalid SFX IDs from being played, and only accept <tt>$FF</tt> as an ID to key off SFX on that channel. | ||
* <tt>y</tt> defines the left volume. This is not signed. | * <tt>y</tt> defines the left volume. This is not signed. | ||
* <tt>z</tt> defines the right volume. This is not signed. | * <tt>z</tt> defines the right volume. This is not signed. | ||
''TODO adapt this for V2.0-V4.0b as needed if there's anything extra to note'' | |||
====SFX Data Format==== | ====SFX Data Format==== | ||
Line 169: | Line 172: | ||
''TODO only V0.0 and V1.0 have really been checked: check V2.0 and up'' | ''TODO only V0.0 and V1.0 have really been checked: check V2.0 and up'' | ||
===Fast Forward On (Command <tt>$06</tt> (V0.0-V1.0))=== | ===Fast Forward On (Command <tt>$06</tt> (V0.0-V1.0), <tt>$0C</tt> (V2.0-V4.0a), <tt>$08</tt> (V4.0b))=== | ||
Causes the music to play at maximum tempo... which means every ten timer 0 ticks. This is equivalent to a tempo of 256. | Causes the music to play at maximum tempo... which means every ten timer 0 ticks. This is equivalent to a tempo of 256. | ||
===Fast Forward Off (Command <tt>$07</tt> (V0.0-V1.0))=== | ===Fast Forward Off (Command <tt>$07</tt> (V0.0-V1.0), <tt>$0D</tt> (V2.0-V4.0a), <tt>$09</tt> (V4.0b))=== | ||
Causes the music to play at normal tempo. | Causes the music to play at normal tempo. | ||
===Master Volume (Command <tt>$08</tt> (V1.0))=== | ===Master Volume (Command <tt>$08</tt> (V1.0), <tt>$0E</tt> (V2.0-V4.0a), <tt>$06</tt> (V4.0b))=== | ||
<pre>$08 xx ?? ??</pre> | <pre>$08 xx ?? ??</pre> | ||
* <tt>xx</tt> is a direct write to the MVOLL and MVOLR DSP registers. | * <tt>xx</tt> is a direct write to the MVOLL and MVOLR DSP registers. | ||
''TODO some games for V2.0 and up affect echo volume as well, indicate which ones (and this is always applied scaled to Master Volume)'' | |||
==Song Entry== | ==Song Entry== |
Revision as of 04:13, 3 November 2020
David Whittaker Sound Engine is a sound driver for the SPC700 programmed by David Whittaker.
Many games have multiple different builds stored in the game at once, sometimes with code differences. Almost every single game has at least one unique build not shared by any of the other games: the exceptions are...
- The opening logos for Lemmings 2: The Tribes and Apocalypse II
- Kick Off 3 Beta's Title Screen and Lawnmower Man/Virtual Wars' US Beta
- Lemmings 2: The Tribes' most common build and Riddick Bowe Boxing's Japanese version
The raw build sorting notes can be found here.
These are the games where the sound engine was used:
Game Name | Music Version | VCMD Code Location | ROM Offset |
---|---|---|---|
Dream TV | 0.0 (Beta 2) 2.0 (all other versions) |
0x098A (Beta 2) 0x0614 (all other versions) |
0x0196A2 (Beta 2, uncompressed) 0x039B16 (all other versions, RNC compressed) |
Krusty's Super Fun House | 1.0 | 0x04F1 | 0x0E8000 (all versions) |
Kick Off/Super Kick Off | 1.0 | 0x04E6 | 0x098000 (all versions) |
Batman: Revenge of the Joker | 2.0 | 0x0610 | 0x068000 |
Super SWIV/Firepower 2000 | 2.1 | 0x06AD | 0x158000 |
Gods | 2.2 | 0x0500/0x0600/0x0612 | 0x980000/0x98AFAC/0x99D448/0x9A8000 (all versions, three unique build variants, RNC compressed) |
World Class Rugby | 2.2 | 0x0608 | 0x0B8000 (all versions) |
Battle Cars | 3.0 | 0x0717 | 0x0A8000 |
Chavez/Riddick Bowe Boxing | 3.0 (US version) 3.1 (all other versions) |
0x0621 (Japanese version) 0x067C (US version) 0x067D (Chavez) |
0x0D8000 (all versions)/0x0E8000 (all versions except Chavez) (three unique build variants, one per version between Chavez, US & Japanese versions) |
Lawnmower Man/Virtual Wars | 3.1 | 0x06BD (US beta) 0x06A4 (all other versions) |
0x9C8000 (all versions except US beta)/0x9E8000 (all versions) |
Apocalypse II | 3.1 | 0x05AF/0x0624 | 0x118000/0x168000 |
Elite Soccer/World Cup Striker | 3.1 | 0x0601 (US and European version In-Game) 0x060B (US and Japanese version Title Screen) 0x0704 (Japanese version In-Game) 0x070B (European version Title Screen) |
0x1B8000 (all versions)/0x08D500 (US & Japanese version)/0x08D550 (European beta version)/0x08D640 (European version) (Four unique build variants: two Title Screen (US/JP compared to EU) and two In-Game (US/EU compare to JP)) |
Kick Off 3 (Beta version only) | 3.1 | 0x0658/0x06BD | 0x1A8000/0x1D8000 |
Lemmings 2: The Tribes | 3.1 | 0x05AF/0x060F/0x0614/0x0621/0x0697 | (omitted for now: there are 16 copies of the code in the ROM, with five different build variants being present: four of them are used in one instance each, that being the opening logo, the Title Screen, the Beach Tribe and the Cavelem Tribe, and the others use a single common copy of the code with modifications of constants and non-code pointers) |
Porky Pig's Haunted Holiday (Beta version only) | 3.1 | 0x06CA | (omitted for now: there are 36 copies of the code in the ROM, none of which are unique except for the sound data and modifications of constants and non-code pointers) |
Shaq Fu | 4.0a | 0x0539 | 0xD96408 (all versions) |
Michael Jordan: Chaos in the Windy City | 4.0b | 0x0539 | 0xD2B18F (all versions) |
Communication with the SNES
Each command is triggered by sending the parameters to $2141-$2143 first, then the command ID to $2140. The latches are cleared afterwards on all registers, which means the same command IDs can be sent again, provided the parameters are resent.
Output to the SNES
V0.0
There is no acknowledgement to the SNES beyond the latches being cleared.
V1.0
On initialization, initially $2140-$2141 are sent a zero while the sound driver sets itself up. When initialization finishes, a $55 is sent to $2140-$2141.
After the first command ID is sent, $2140-$2142 are updated every time a command ID is sent, and $2143 is updated every timer 0 tick.
When a command ID is sent, the latches are cleared, allowing the SNES to send the same command ID again. However, this also means that the parameters have to be resent if the same parameters are to be used again.
xx yy zz %00000abc
- xx is the command ID that was just sent.
- yy is a parameter that was sent to $2141 to execute the command.
- zz is the command ID that was just sent.
- a indicates that a piece of SFX is playing on channel 7.
- b indicates that a piece of SFX is playing on channel 8.
- c indicates that music is playing.
TODO the sound driver outputs something to the SNES at all times, at least on later versions... what?
Command IDs (V0.0-V1.0)
Command ID | Description | Register Values & Arguments | Minimum Version |
---|---|---|---|
$00 | NOP | $00 ?? ?? ?? | 0.0 |
$01 | Play Music | $01 xx ?? ?? | 0.0 |
$02 | Pause Music | $02 ?? ?? ?? | 0.0 |
$03 | Continue Music | $03 ?? ?? ?? | 0.0 |
$04 | Play SFX (Channel 7) | $04 xx yz ?? | 0.0 |
$05 | Play SFX (Channel 8) | $05 xx yz ?? | 0.0 |
$06 | Fast Forward On | $06 ?? ?? ?? | 0.0 |
$07 | Fast Forward Off | $07 ?? ?? ?? | 0.0 |
$08 | Master Volume | $08 ?? ?? ?? | 1.0 |
$09-$FF | Latch Clear | $09-$FF ?? ?? ?? | 0.0 |
Command IDs (V2.0-V4.0a)
TODO document V2.0 and up (some of this will occur on a per-game basis)
Command IDs (V4.0b)
TODO document V2.0 and up (some of this will occur on a per-game basis)
Latch Clear
Clears the latches on the CPUIO registers and does nothing else, thus making this effectively a NOP. This occurs on all invalid command IDs.
NOP (Command $00)
Does absolutely nothing.
Play Music (Command $01)
$01 xx ?? ??
Stops a previous piece of music, then plays a piece of music.
- xx is the music ID.
- V1.0 and up have boundary checks that prevent invalid music IDs from being played.
Pause Music (Command $02)
Stops music, allowing it to be resumed later.
Continue Music (Command $03)
Resumes a paused song.
Play SFX (Command $04-$05 (V0.0-V1.0), $04-$0B (V2.0-V4.0a), $04 (V4.0b))
ii xx yz ??
Plays a piece of SFX.
- ii, the command ID used for the SFX, defines the channel used.
- V0.0-V1.0:
- Channels 1-6: Not supported
- Channel 7: $04
- Channel 8: $05
- V2.0-V4.0a:
- Channel 1: $04
- Channel 2: $05
- Channel 3: $06
- Channel 4: $07
- Channel 5: $08
- Channel 6: $09
- Channel 7: $0A
- Channel 8: $0B
- V4.0b instead dynamically allocates the channel that the SFX is played on.
- V0.0-V1.0:
- xx defines the SFX ID. Setting the highest bit (covering IDs $80-$FF keys off the SFX instead of playing it.
- V1.0 and up have boundary checks that prevent invalid SFX IDs from being played, and only accept $FF as an ID to key off SFX on that channel.
- y defines the left volume. This is not signed.
- z defines the right volume. This is not signed.
TODO adapt this for V2.0-V4.0b as needed if there's anything extra to note
SFX Data Format
Each SFX entry is a pointer to a 14-byte entry containing a series of parameters to utilize on a per-SFX basis. Only one channel's worth is defined here.
xx yy zz aa bb cc dd ee ff gg hh ii jj kk
- xx is the number of timer 0 ticks (times 10) to play the SFX for.
- yy is the number of timer 0 ticks (times 10) to slide pitches before resetting and doing the slide again.
- zz is either a starting value for the PITCHL DSP register or a noise frequency.
- aa is a starting value for the PITCHH DSP register.
- bb is the offset to apply to either the PITCHL DSP register or noise frequency per step.
- cc is a offset to apply to the PITCHH DSP register per step.
- dd is a direct write to the SRCN DSP register. $80 and up instead cause this to use noise.
- ee overwrites the pitch settings and instead uses RNG for the pitch.
- ff defines the sign for the pitch offset.
- $00 turns off pitch slides for the SFX.
- $01-$7F apply a positive offset.
- $80-$FF apply a negative offset.
- gg is the number of timer 0 ticks (times 10) to perform the pitch slide for.
- hh is a direct write to the ADSR1 DSP register.
- ii is a direct write to the ADSR2 DSP register.
- jj, when non-zero, causes the SFX to be played endlessly until keyed off or interrupted. It also causes pitch slides to run forever.
- kk is the number of timer 0 ticks (times 10) per step.
TODO only V0.0 and V1.0 have really been checked: check V2.0 and up
Fast Forward On (Command $06 (V0.0-V1.0), $0C (V2.0-V4.0a), $08 (V4.0b))
Causes the music to play at maximum tempo... which means every ten timer 0 ticks. This is equivalent to a tempo of 256.
Fast Forward Off (Command $07 (V0.0-V1.0), $0D (V2.0-V4.0a), $09 (V4.0b))
Causes the music to play at normal tempo.
Master Volume (Command $08 (V1.0), $0E (V2.0-V4.0a), $06 (V4.0b))
$08 xx ?? ??
- xx is a direct write to the MVOLL and MVOLR DSP registers.
TODO some games for V2.0 and up affect echo volume as well, indicate which ones (and this is always applied scaled to Master Volume)
Song Entry
For each song entry in an array of song definitions, one byte is defined as a starting tempo, followed by a series of pointers defined little endian style for each channel. For Dream TV Beta and Kick Off, only five pointers are defined. For Krusty's Super Fun House, only six pointers are defined. For all other games, eight pointers are defined.
xx yy yy zz zz aa aa bb bb cc cc dd dd ee ee ff ff
- xx is the starting tempo.
- yy yy is a little endian pointer to a pattern order list for channel 1.
- zz zz is a little endian pointer to a pattern order list for channel 2.
- aa aa is a little endian pointer to a pattern order list for channel 3.
- bb bb is a little endian pointer to a pattern order list for channel 4.
- cc cc is a little endian pointer to a pattern order list for channel 5.
- dd dd is a little endian pointer to a pattern order list for channel 6. (Krusty's Super Fun House only pre-V2.0)
- ee ee is a little endian pointer to a pattern order list for channel 7. (not supported pre-V2.0)
- ff ff is a little endian pointer to a pattern order list for channel 8. (not supported pre-V2.0)
Two builds don't support song entries at all:
- The opening logos for Lemmings 2: The Tribes and Apocalypse II
- Kick Off 3 Beta (In-Game)
Pattern Order List
Each channel has a list of little endian pointers on a per-channel basis. If the pointer is zero, then you jump back to the beginning of the pattern order list for that channel.
Instrument Format
The instrument format at V0.0 is N-SPC/Kankichi-kun compatible minus noise support for SRCN values above 127. Post V1.0, one of the bytes loses its usage.
The instrument format is defined as direct writes to DSP registers for the first four bytes, followed by two pitch-related bytes. They are defined in this order, from top to bottom...
- SRCN
- ADSR1
- ADSR2
- GAIN (unused byte post-V1.0)
- Pitch Base Multiplier
- Pitch Base Fractional Multiplier (in 256ths)
Voice Command Format
VCMD ID | Description | Arguments | Minimum Version |
---|---|---|---|
$00-$5F | Note | 0.0 | |
$60-$7F | Note Length | 0.0 | |
$80-$EC | Invalid | 0.0 | |
$ED | Instant Pitch Change to Note | xx | 4.0a only |
$ED | Set Master Volume | xx | 4.0b only |
$EE | Volume Scaler by Fraction | xx yy | 3.0 |
$EF | Set ADSR | xx yy | 2.0 |
$F0 | Fine Tune | xx | 1.0 |
$F1 | Pitch Bend | xx | 1.0 |
$F2 | Pitch Envelope ID | xx | 0.0 |
$F3 | L/R Voice Volume | xx yy | 0.0 |
$F4 | Tempo | xx | 0.0 |
$F5 | Jump to Pattern in Order List | xx xx | 0.0 |
$F6-$F7 | Invalid | 0.0 | |
$F8 | Key Off | 0.0 | |
$F9 | One Note Delay | 0.0 | |
$FA | Instrument | xx | 0.0 |
$FB | Absolute Global Transposition | xx | 0.0 |
$FC | Absolute Transposition | xx | 0.0 |
$FD | Invalid | 0.0 | |
$FE | Song End | 0.0 | |
$FF | Pattern End | 0.0 |
Invalid (VCMDs $80-$EC, $F6-$F7, $FD, $ED (pre-V4.0), $EE (pre-V3.0), $EF (pre-V2.0), $F0-$F1 (pre-V1.0))
The sound driver deliberately freezes itself via an infinite branch always loop rather than crashing or skipping the byte. This also takes up VCMD slots that are not filled in earlier versions.
Note (VCMDs $00-$5F)
Plays a note and delays the channel for one note length.
The initial pitch of the note is calculated using a pitch table that contains one octave (and a note)'s worth of pitch values. This value is shifted according to the octave used, and multiplied that by the instrument's pitch base to get the pitch for the note.
Note Length (VCMDs $60-$7F)
%011xxxxx
- xxxxx represents your note length (as five bits).
Note lengths are defined as the number of tempo ticks plus one. Notes are keyed off either on another note or on the key off VCMD ($F9).
Instant Pitch Change to Note (VCMD $ED)
Requires V4.0a to use. Lower versions freeze the sound driver instead.
$ED xx
- xx defines the note to change the pitch to.
Set Master Volume (VCMD $ED)
Requires V4.0b to use. Lower versions freeze the sound driver instead.
$ED xx
- xx defines the value to directly write to the MVOL DSP registers.
Volume Scaler by Fraction (VCMD $EE)
Requires V3.0 or later to use. Lower versions freeze the sound driver instead.
$EE xx yy
- xx is the numerator, and is the value to multiply the volume by. The scaling process is skipped if this is zero.
- yy is the denominator, and is the value to divide the multiplied volume by.
Put the two together, and you get the current volume multiplied by .
Set ADSR (VCMD $EF)
Requires V2.0 or later to use. Lower versions freeze the sound driver instead.
$EF xx yy
- xx is a direct write to the VxADSR1 DSP register.
- yy is a direct write to the VxADSR2 DSP register.
Fine Tune (VCMD $F0)
Requires V1.0 or later to use. Lower versions freeze the sound driver instead.
$F0 xx
- xx is a signed delta value for the pitch. These are in units used directly for the VxPITCH DSP registers.
Pitch Bend (VCMD $F1)
Requires V1.0 or later to use. Lower versions freeze the sound driver instead.
$F1 xx
- xx is a signed delta value for the pitch. These are in units used directly for the VxPITCH DSP registers.
Pitch bends are performed every 10 timer 0 ticks independently of the tempo. They are automatically terminated after one note.
Pitch Envelope ID (VCMD $F2)
$F2 xx
- xx is an index to an array to a pointer of pitch envelopes. The pitch envelopes always loop and are clocked at a rate of 10 timer 0 ticks independently of the tempo ticker.
Pitch Envelope Format
Pitch envelopes are defined using a signed value. These are in units used directly for the VxPITCH DSP registers. If $80 is defined, the envelope loops back to the beginning.
L/R Voice Volume (VCMD $F3)
$F3 xx yy
- This is a direct DSP register write to the VxVOL registers, with xx being the left volume and yy being the right volume.
This VCMD's operation changes depending on the version:
- V0.0-V2.1: Just a straight write with no modifications made to the input.
- V2.2: The input values are shifted left once.
- V3.0-V4.0b: The input values are scaled by VCMD $F3, then shifted left once.
- V4.0a: The input values are scaled by the values used for VCMD $F3. The shifting operation is not done here.
Tempo (VCMD $F4)
$F4 xx
- xx defines one tempo tick as timer 0 ticks. Zero freezes the song except for pitch bends and envelopes, which are not affected by the tempo ticker.
Jump to Pattern in Order List (VCMD $F5)
$F5 xx xx
- xx xx is a little endian pointer to a pattern pointer in the order list.
Key Off (VCMD $F8)
Keys off the note and delays the channel for one note length.
One Note Delay (VCMD $F9)
Delays the channel for one note length.
Instrument (VCMD $FA)
$FA xx
- xx is an instrument ID to an array of instruments. See Instrument Format above for the format.
Absolute Global Transposition (VCMD $FB)
$FB xx
- xx is a signed note offset to apply for all channels for the music.
Absolute Transposition (VCMD $FC)
$FC xx
- xx is a signed note offset to apply for the channel.
Song End (VCMD $FE)
Terminates the song for all of the channels.
Pattern End (VCMD $FF)
Ends the pattern and goes to the pattern order list to fetch another pattern.