H-Sound Engine: Difference between revisions
KungFuFurby (talk | contribs) (All VCMDs documented.) |
(master volume -> main volume like the official docs) |
||
(20 intermediate revisions by 2 users not shown) | |||
Line 5: | Line 5: | ||
Only one version, 0.5, was ever used. However, there are technically three different builds, each with very minor differences: | Only one version, 0.5, was ever used. However, there are technically three different builds, each with very minor differences: | ||
* Yuujin no Furi Furi Girls, compared to Kamen Rider SD, has extra valid percussion note slots and a single extra opcode that overwrites the timer value to use at the start, thus almost not even qualifying as a build variant. | * ''Yuujin no Furi Furi Girls'', compared to ''Kamen Rider SD'', has extra valid percussion note slots and a single extra opcode that overwrites the timer value to use at the start, thus almost not even qualifying as a build variant. | ||
* The other three games, compared to Kamen Rider SD, are missing an optional inversion operation for the echo volume. | * The other three games, compared to ''Kamen Rider SD'', have extra valid percussion note slots and are missing an optional inversion operation for the echo volume. The latter only affects the mono/stereo setting. | ||
{| class="wikitable sortable" | {| class="wikitable sortable" | ||
Line 22: | Line 22: | ||
| Janyuuki Gokuu Randa || 3 || <tt>0x0C69</tt> || <tt>0x1D8000</tt> | | Janyuuki Gokuu Randa || 3 || <tt>0x0C69</tt> || <tt>0x1D8000</tt> | ||
|} | |} | ||
The raw build sorting notes can be found [[H-Sound Engine/Build Sorting|here]]. | |||
==Communication with the SNES== | |||
Each command is triggered by sending the command ID to $2140/$F4. To send the same command ID again, toggle either of the highest two bits. | |||
===Output to the SNES=== | |||
Two out of the four CPUIO registers are used as output from a command ID, and thus will be covered below under Command IDs. | |||
<pre>%00xxxxxx ?? ?? yy</pre> | |||
* <tt>%xxxxxx</tt> is the last non-zero command ID sent. | |||
* <tt>yy</tt> is the output of an RNG function. This is updated continuously while timer 0 is outputting a zero (meaning it has not yet ticked). | |||
===Command IDs=== | |||
{| class="wikitable sortable" | |||
|- | |||
! Command ID !! Description !! Register Values & Arguments | |||
|- | |||
|<tt>%??000000</tt><br><tt>$00/$40/$80/$C0</tt> || NOP || <tt>%??000000 ?? ?? ??</tt> | |||
|- | |||
|<tt>%??000001</tt><br><tt>$01/$41/$81/$C1</tt> || Play Music/SFX || <tt>%??000001 xx ?? ??</tt> | |||
|- | |||
|<tt>%??000010</tt><br><tt>$02/$42/$82/$C2</tt> || Stop All Sound || <tt>%??000010 ?? ?? ??</tt> | |||
|- | |||
|<tt>%??000011</tt><br><tt>$03/$43/$83/$C3</tt> || Mute Channels || <tt>%??000011 %xxxxxxxx ?? ??</tt> | |||
|- | |||
|<tt>%??000100</tt><br><tt>$04/$44/$84/$C4</tt> || Echo Volume || <tt>%??000100 xx ?? ??</tt> | |||
|- | |||
|<tt>%??000101</tt><br><tt>$05/$45/$85/$C5</tt>|| Main Volume || <tt>%??000101 xx yy ??</tt> | |||
|- | |||
|<tt>%??000110</tt><br><tt>$06/$46/$86/$C6</tt> || FLG DSP Register Set || <tt>%??000110 xx ?? ??</tt> | |||
|- | |||
|<tt>%??000111</tt><br><tt>$07/$47/$87/$C7</tt> || Acknowledge || <tt>%??000111 ?? ?? ??</tt> | |||
|- | |||
|<tt>%??001000</tt><br><tt>$08/$48/$88/$C8</tt> || Echo Feedback || <tt>%??001000 xx ?? ??</tt> | |||
|- | |||
|<tt>%??001001</tt><br><tt>$09/$49/$89/$C9</tt> || Global Absolute Transposition || <tt>%??001001 xx ?? ??</tt> | |||
|- | |||
|<tt>%??001010</tt><br><tt>$0A/$4A/$8A/$CA</tt> || Song Tempo Offset || <tt>%??001010 xx ?? ??</tt> | |||
|- | |||
|<tt>%??001011</tt><br><tt>$0B/$4B/$8B/$CB</tt> || Echo Enable Bits || <tt>%??001011 %xxxxxxxx ?? ??</tt> | |||
|- | |||
|<tt>%??001100</tt><br><tt>$0C/$4C/$8C/$CC</tt> || FIR Coefficient Table ID || <tt>%??001100 xx ?? ??</tt> | |||
|- | |||
|<tt>%??001101</tt><br><tt>$0D/$4D/$8D/$CD</tt> || Acknowledge + Stop All Sound + Load New Data || <tt>%??001101 ?? ?? ??</tt> | |||
|- | |||
|<tt>%??001110</tt><br><tt>$0E/$4E/$8E/$CE</tt> || Acknowledge + Load New Data || <tt>%??001110 ?? ?? ??</tt> | |||
|- | |||
|<tt>%??001111</tt><br><tt>$0F/$4F/$8F/$CF</tt> || Acknowledge + Stop All Sound + Load New Data + Play Music ID $00 || <tt>%??001111 ?? ?? ??</tt> | |||
|- | |||
|<tt>%??010000</tt><br><tt>$10/$50/$90/$D0</tt> || Set Instrument ID For Channel || <tt>%??010000 %?????xxx yy ??</tt> | |||
|- | |||
|<tt>%??010001</tt><br><tt>$11/$51/$91/$D1</tt> || Set Instrument ADSR For Channel || <tt>%??010001 %?????xxx yy zz</tt> | |||
|- | |||
|<tt>%??010010</tt><br><tt>$12/$52/$92/$D2</tt> || Inverted Relative Main & Echo Volume || <tt>%??010010 xx yy ??</tt> | |||
|- | |||
|<tt>%??010011</tt><br><tt>$13/$53/$93/$D3</tt> || Relative Main & Echo Volume || <tt>%??010011 xx yy ??</tt> | |||
|- | |||
|<tt>%??010100</tt><br><tt>$14/$54/$94/$D4</tt> || Inverted Relative Song Tempo Offset || <tt>%??010100 xx ?? ??</tt> | |||
|- | |||
|<tt>%??010101</tt><br><tt>$15/$55/$95/$D5</tt> || Relative Song Tempo Offset || <tt>%??010101 xx ?? ??</tt> | |||
|- | |||
|<tt>%??010110</tt><br><tt>$16/$56/$96/$D6</tt> || Pitch Offset for Channel || <tt>%??010110 xx yy zz</tt> | |||
|- | |||
|<tt>%??010111</tt><br><tt>$17/$57/$97/$D7</tt> || Set Stereo Mode || <tt>%??010111 ?? ?? ??</tt> | |||
|- | |||
|<tt>%??011000</tt><br><tt>$18/$58/$98/$D8</tt> || Redefine FIR Coefficient in Table || <tt>%??011000 xx yy zz</tt> | |||
|- | |||
|<tt>%??011001</tt><br><tt>$19/$59/$99/$D9</tt> || Instrument Pitch Base Offset For Channel || <tt>%??011001 %?????xxx yy ??</tt> | |||
|- | |||
|<tt>%??011010</tt><br><tt>$1A/$5A/$9A/$DA</tt> || Restart Program || <tt>%??011010 ?? ?? ??</tt> | |||
|- | |||
|<tt>%??010011</tt><br><tt>$1B/$5B/$9B/$DB</tt> || Set Mono Mode || <tt>%??010011 ?? ?? ??</tt> | |||
|- | |||
|<tt>%??01010?</tt><br><tt>$1C-$1D/$5C-$5D/$9C-$9D/$DC-$DD</tt> || Stop All SFX || <tt>%??01010? ?? ?? ??</tt> | |||
|- | |||
|<tt>%??010110</tt><br><tt>$1E/$5E/$9E/$DE</tt> || Fade Out || <tt>%??010110 ?? ?? ??</tt> | |||
|- | |||
|<tt>%??010111</tt><br><tt>$1F/$5F/$9F/$DF</tt> || Stop All SFX || <tt>%??010111 ?? ?? ??</tt> | |||
|- | |||
|<tt>%??100000</tt><br><tt>$20/$60/$A0/$E0</tt> || Redefine Attack For Channel || <tt>%??100000 %0xxx0000 %0000yyyy ??</tt> | |||
|- | |||
|<tt>%??100001</tt><br><tt>$21/$61/$A1/$E1</tt> || Redefine Decay For Channel || <tt>%??100001 %0xxx0000 %00000yyy ??</tt> | |||
|- | |||
|<tt>%??100010</tt><br><tt>$22/$62/$A2/$E2</tt> || Redefine Sustain Level For Channel || <tt>%??100010 %0xxx0000 %00000yyy ?? ??</tt> | |||
|- | |||
|<tt>%??100011</tt><br><tt>$23/$63/$A3/$E3</tt> || Redefine Sustain Rate For Channel || <tt>%??100011 %0xxx0000 %000yyyyy ?? ??</tt> | |||
|- | |||
|<tt>$24-$3F/$64-$7F/$A4-$BF/$E4-$FF</tt> || Acknowledge || <tt>$24-$3F/$64-$7F/$A4-$BF/$E4-$FF ?? ?? ??</tt> | |||
|} | |||
===Acknowledge=== | |||
Merely reads the bytes sent, then acknowledges the command ID sent back to $2140/$F4. It does nothing else. | |||
===NOP (Command ID <tt>$00/$40/$80/$C0</tt>)=== | |||
Does absolutely nothing other than read the bytes sent. It doesn't even send an acknowledgement, unlike all other command IDs. | |||
===Play Music/SFX (Command ID <tt>$01/$41/$81/$C1</tt>)=== | |||
<pre>%??000001 xx ?? ??</pre> | |||
* <tt>xx</tt> is the ID to play. If it is less than <tt>$20</tt>, it is a music ID. Otherwise, it is a SFX ID. The MVOL DSP registers are always set to `$60` and the EVOL DSP registers are always set to `$30` (with one of them optionally getting inverted afterwards) when this command is executed. | |||
===Stop All Sound (Command ID <tt>$02/$42/$82/$C2</tt>)=== | |||
Terminates all music and SFX playback as well as zeroing out the main and echo volumes. | |||
===Mute Channels (Command ID <tt>$03/$43/$83/$C3</tt>)=== | |||
<pre>%??000011 %xxxxxxxx ?? ??</pre> | |||
* <tt>%xxxxxxxx</tt> are the channel bits to mute. | |||
===Echo Volume (Command ID <tt>$04/$44/$84/$C4</tt>)=== | |||
<pre>%??000100 xx ?? ??</pre> | |||
* <tt>xx</tt> defines the volume used for the EVOLL and EVOLR DSP registers. | |||
===Main Volume (Command ID <tt>$05/$45/$85/$C5</tt>)=== | |||
<pre>%??000101 xx ?? ??</pre> | |||
* <tt>xx</tt> defines the volume used for the MVOLL and MVOLR DSP registers. | |||
===FLG DSP Register Set (Command ID <tt>$06/$46/$86/$C6</tt>)=== | |||
<pre>%??000110 xx ?? ??</pre> | |||
* <tt>xx</tt> defines the value used for the FLG DSP register. | |||
===Echo Feedback (Command ID <tt>$08/$48/$88/$C8</tt>)=== | |||
<pre>%??001000 xx ?? ??</pre> | |||
* <tt>xx</tt> defines the value used for the EFB DSP register. | |||
===Global Absolute Transposition (Command ID <tt>$09/$49/$89/$C9</tt>)=== | |||
<pre>%??001001 xx ?? ??</pre> | |||
* <tt>xx</tt> is a signed value defining the number of semitones to transpose subsequent notes. Note that this affects all channels, not just one channel, *and* it overwrites whatever the music had set previously. | |||
===Song Tempo Offset (Command ID <tt>$0A/$4A/$8A/$CA</tt>)=== | |||
<pre>%??001010 xx ?? ??</pre> | |||
* <tt>xx</tt> is a signed value that sets the amount to offset the song tempo. | |||
===Echo Enable Bits (Command ID <tt>$0B/$4B/$8B/$CB</tt>)=== | |||
<pre>%??001011 %xxxxxxxx ?? ??</pre> | |||
* <tt>%xxxxxxxx</tt> defines the value used for EON DSP register. | |||
===FIR Coefficient Table ID (Command ID <tt>$0C/$4C/$8C/$CC</tt>)=== | |||
<pre>%??001100 xx ?? ??</pre> | |||
* <tt>xx</tt> is an ID for a table of FIR coefficient IDs. | |||
===Load New Data (Command <tt>$0D-$0F/$4D-$4F/$8D-$8F/$CD-$CF</tt>)=== | |||
Each command ID has a different approach prior to loading new data: | |||
* <tt>$0D/$4D/$8D/$CD</tt> acknowledges with a fixed ID of $0D to $2140/$F4, then stops all sound (via executing command ID <tt>$02/$42/$82/$C2</tt>'s routine). | |||
* <tt>$0E/$4E/$8E/$CE</tt> acknowledges with the raw data from $2140/$F4 (that is, prior to ANDing it by $3F) ANDed by $1F, which de-facto results in an $0E being output. It doesn't stop sound, though. | |||
* <tt>$0F/$4F/$8F/$CF</tt> acknowledges with a fixed ID of $0F to $2140/$F4, then stops all sound (via executing command ID <tt>$02/$42/$82/$C2</tt>'s routine). | |||
''TODO Loading New Data (the loading protocol is nearly identical to IPL Boot ROM, with a couple of differences, and doesn't send out $AA $BB to $2140/$F4 and $2141/$F5, nor does it normally allow for jumping to other pieces of code)'' | |||
Each command ID also has a different approach to concluding a data loading session: | |||
* <tt>$0D/$4D/$8D/$CD</tt> acknowledges by zeroing out $2140/$F4. | |||
* <tt>$0E/$4E/$8E/$CE</tt> outputs no acknowledgement. | |||
* <tt>$0F/$4F/$8F/$CF</tt> acknowledges by zeroing out $2140/$F4 and playing music ID $00. | |||
===Set Instrument ID For Channel (Command ID <tt>$10/$50/$90/$D0</tt>)=== | |||
<pre>%??010000 %?????xxx yy ???</pre> | |||
* <tt>%xxx</tt> is the channel ID. | |||
* <tt>yy</tt> is the instrument ID to assign for this channel. | |||
===Set Instrument ADSR For Channel (Command ID <tt>$11/$51/$91/$D1</tt>)=== | |||
<pre>%??010001 %?????xxx yy zz</pre> | |||
* <tt>%xxx</tt> is the channel ID. | |||
* <tt>yy</tt> translates to a direct write to the VxADSR1 register for the instrument ID currently playing on the channel specified. The highest bit is automatically set to force ADSR mode. | |||
* <tt>zz</tt> translates to a direct write to the VxADSR2 register for the instrument ID currently playing on the channel specified. | |||
'''WARNING: This command permanently overwrites the ADSR settings for the instrument currently playing on the channel ID specified!''' | |||
===Inverted Relative Main & Echo Volume (Command ID <tt>$12/$52/$92/$D2</tt>)=== | |||
<pre>%??010010 xx yy ??</pre> | |||
* <tt>xx</tt> is the amount to decrease the volume used for the MVOLL and MVOLR DSP registers. | |||
* <tt>yy</tt> is the amount to decrease the volume used for the EVOLL and EVOLR DSP registers... well, if it weren't for a bug that causes the EVOLL DSP register to be referred to twice by mistake, leaving the EVOLR DSP register reference untouched. | |||
===Relative Main & Echo Volume (Command ID <tt>$13/$53/$93/$D3</tt>)=== | |||
<pre>%??010011 xx yy ??</pre> | |||
* <tt>xx</tt> is the amount to increase the volume used for the MVOLL and MVOLR DSP registers. | |||
* <tt>yy</tt> is the amount to increase the volume used for the EVOLL and EVOLR DSP registers... well, if it weren't for a bug that causes the EVOLL DSP register to be referred to twice by mistake, leaving the EVOLR DSP register reference untouched. | |||
===Inverted Relative Song Tempo Offset (Command ID <tt>$14/$54/$94/$D4</tt>)=== | |||
<pre>%??010100 xx ?? ??</pre> | |||
* <tt>xx</tt> is the amount to decrease the amount to offset the song tempo. | |||
===Relative Song Tempo Offset (Command ID <tt>$15/$55/$95/$D5</tt>)=== | |||
<pre>%??010101 xx ?? ??</pre> | |||
* <tt>xx</tt> is the amount to increase the amount to offset the song tempo. | |||
===Pitch Offset for Channel (Command ID <tt>$16/$56/$96/$D6</tt>)=== | |||
<pre>%??010110 xx yy zz</pre> | |||
* <tt>xx</tt> is the channel ID. | |||
* <tt>yy</tt> is the amount in VxPITCHL units to offset the channel's pitch. | |||
* <tt>zz</tt> is the amount in VxPITCHH units to offset the channel's pitch. | |||
===Set Stereo Mode (Command ID <tt>$17/$57/$97/$D7</tt>)=== | |||
Sets the sound mode to stereo and outputs a $01 to $2141/$F5. In addition, on Kamen Rider SD and Yuujin no Furi Furi Girls (build IDs 1 and 2), it inverts the EVOLL DSP register. | |||
<u>Output</u> | |||
<pre>?? 01 ?? ??</pre> | |||
===Redefine FIR Coefficient in Table (Command ID <tt>$18/$58/$98/$D8</tt>)=== | |||
<pre>%??011000 xx yy zz</pre> | |||
* <tt>xx</tt> is the table ID. | |||
* <tt>yy</tt> is the FIR coefficient ID. | |||
* <tt>zz</tt> is the new FIR coefficient to set. | |||
===Instrument Pitch Base Offset For Channel (Command ID <tt>$19/$59/$99/$D9</tt>)=== | |||
<pre>%??011001 %?????xxx yy ??</pre> | |||
* <tt>%xxx</tt> is the channel ID. | |||
* <tt>yy</tt> does one of two things to the pitch base multiplier for the instrument... | |||
** If set to zero, the pitch base multiplier is decremented by 2/256. | |||
** Otherwise, the pitch base multiplier is incremented by 2/256. | |||
'''WARNING: This command permanently overwrites the pitch base settings for the instrument currently playing on the channel ID specified!''' | |||
===Restart Program (Command ID <tt>$1A/$5A/$9A/$DA</tt>)=== | |||
Causes the program to completely restart, not by jumping to the IPL Boot ROM, but rather by jumping back to the start of the program and reinitializing everything. | |||
===Set Mono Mode (Command ID <tt>$1B/$5B/$9B/$DB</tt>)=== | |||
Sets the sound mode to mono and outputs a $00 to $2141/$F5. In addition, on Kamen Rider SD and Yuujin no Furi Furi Girls (build IDs 1 and 2), the inversion operation on the EVOLL DSP register is canceled. | |||
<u>Output</u> | |||
<pre>?? 00 ?? ??</pre> | |||
===Stop All SFX (Command ID <tt>$1C-$1D, $1F/$5C-$5D, $5F/$9C-$9D, $9F/$DC-$DD, $DF</tt>)=== | |||
Stops all SFX currently playing. | |||
===Fade Out (Command ID <tt>$1E/$5E/$9E/$DE</tt>)=== | |||
Fades out the main and echo volumes one timer 0 tick after this is executed. The fade rate is as following: | |||
* Main volume: 3 per five timer 0 ticks | |||
* Echo volume: 2 per five timer 0 ticks | |||
The echo volume is not affected by a bug that affects the relative main & echo volume command, where the same register reference was used twice by mistake. | |||
<u>Output</u> | |||
<pre>?? xx yy ??</pre> | |||
* <tt>xx</tt> is the MVOLL DSP register value prior to fading out. | |||
* <tt>yy</tt> is the EVOLL DSP register value prior to fading out. | |||
===Redefine Attack For Channel (Command ID <tt>$20/$60/$A0/$E0</tt>)=== | |||
<pre>%??100000 %0xxx0000 %0000yyyy ??</pre> | |||
* <tt>%xxx</tt> is the channel number whose VxADSR DSP registers will be modified. All other bits outside the one being set should be set to zero due to them not being filtered out: otherwise, the DSP register reference will be incorrect. | |||
* <tt>%yyyy</tt> is the attack value to overwrite in the VxADSR1 DSP register. In addition to overwriting the attack value, the highest bit is automatically set to force ADSR mode. All other bits outside the one being set should be set to zero due to them not being filtered out: otherwise, you may accidentally set some bits when updating the ADSR1 DSP register. | |||
===Redefine Decay For Channel (Command ID <tt>$21/$61/$A1/$E1</tt>)=== | |||
<pre>%??100001 %0xxx0000 %00000yyy ??</pre> | |||
* <tt>%xxx</tt> is the channel number whose VxADSR DSP registers will be modified. All other bits outside the one being set should be set to zero due to them not being filtered out: otherwise, the DSP register reference will be incorrect. | |||
* <tt>%yyy</tt> is the decay value to overwrite in the VxADSR1 DSP register. In addition to overwriting the decay value, the highest bit is automatically set to force ADSR mode. All other bits outside the one being set should be set to zero due to them not being filtered out: otherwise, you may accidentally set some bits when updating the ADSR1 DSP register. | |||
===Redefine Sustain Level For Channel (Command ID <tt>$22/$62/$A2/$E2</tt>)=== | |||
<pre>%??100010 %0xxx0000 %00000yyy ??</pre> | |||
* <tt>%xxx</tt> is the channel number whose VxADSR DSP registers will be modified. All other bits outside the one being set should be set to zero due to them not being filtered out: otherwise, the DSP register reference will be incorrect. | |||
* <tt>%yyy</tt> is the sustain level value to overwrite in the VxADSR2 DSP register. In addition to overwriting the sustain level value, the highest bit is automatically set in the VxADSR1 DSP register to force ADSR mode. All other bits outside the one being set should be set to zero due to them not being filtered out: otherwise, you may accidentally set some bits when updating the VxADSR1 DSP register. | |||
===Redefine Sustain Rate For Channel (Command ID <tt>$23/$63/$A3/$E3</tt>)=== | |||
<pre>%??100011 %0xxx0000 %000yyyyy ?? ??</pre> | |||
* <tt>%xxx</tt> is the channel number whose VxADSR DSP registers will be modified. All other bits outside the one being set should be set to zero due to them not being filtered out: otherwise, the DSP register reference will be incorrect. | |||
* <tt>%yyyyy</tt> is the sustain rate value to overwrite in the VxADSR2 DSP register. In addition to overwriting the sustain rate value, the highest bit is automatically set in the VxADSR1 DSP register to force ADSR mode. All other bits outside the one being set should be set to zero due to them not being filtered out: otherwise, you may accidentally set some bits when updating the VxADSR1 DSP register. | |||
==Instrument Format== | ==Instrument Format== | ||
The instrument format is N-SPC/Kankichi-kun compatible minus noise support for SRCN values above 127. | The instrument format is N-SPC/Kankichi-kun compatible minus noise support for SRCN values above 127. | ||
The instrument format is defined as | The instrument format is defined as the following bytes... | ||
* | <pre>xx yy zz aa bb cc</pre> | ||
* | * <tt>xx</tt> is a direct write to the VxSRCN DSP register. | ||
* | * <tt>yy</tt> is a direct write to the VxADSR1 DSP register. | ||
* | * <tt>zz</tt> is a direct write to the VxADSR2 DSP register. | ||
* | * <tt>aa</tt> is a direct write to the VxGAIN DSP register. | ||
* | * <tt>bb</tt> is a pitch base multiplier. | ||
* <tt>cc</tt> is a fractional pitch base multiplier, defined in 256ths. | |||
==Header Format== | ==Header Format== | ||
Each song's header is a series of eight four byte entries, one per channel. Each entry contains the following bytes | Each song's header is a series of eight four-byte entries, one per channel. Thus, they show up like this in the data... | ||
* | <pre>xx xx yy ?? xx xx yy ?? xx xx yy ?? xx xx yy ?? xx xx yy ?? xx xx yy ?? xx xx yy ?? xx xx yy ??</pre> | ||
* | Each entry (consisting of one track) contains the following bytes... | ||
<pre>xx xx yy ??</pre> | |||
* <tt>xx xx</tt> is a [[little endian]] track pointer. | |||
* <tt>yy</tt> is a master track ID. For the music, this is zero. For SFX, this is a non-zero value. | |||
==Voice Command Format== | ==Voice Command Format== | ||
Line 67: | Line 319: | ||
|<tt>$E2</tt> || Note Volume || <tt>xx</tt> | |<tt>$E2</tt> || Note Volume || <tt>xx</tt> | ||
|- | |- | ||
|<tt>$E3</tt> || NOP || | |<tt>$E3</tt> || NOP || | ||
|- | |- | ||
|<tt>$E4</tt> || Pitch Offset || <tt>xx</tt> | |<tt>$E4</tt> || Pitch Offset || <tt>xx</tt> | ||
Line 215: | Line 467: | ||
<pre>$F2 xx xx</pre> | <pre>$F2 xx xx</pre> | ||
* <tt>xx xx</tt> is a little endian pointer indicating where to jump to. | * <tt>xx xx</tt> is a [[little endian]] pointer indicating where to jump to. | ||
===Noise Clock (VCMD <tt>$F3</tt>)=== | ===Noise Clock (VCMD <tt>$F3</tt>)=== | ||
<pre>$F3 %???xxxxx</pre> | <pre>$F3 %???xxxxx</pre> | ||
* <tt>xxxxx</tt> defines the speed of the noise clock in five bits. | * <tt>%xxxxx</tt> defines the speed of the noise clock in five bits. | ||
===Noise On (VCMD <tt>$F4</tt>)=== | ===Noise On (VCMD <tt>$F4</tt>)=== |
Latest revision as of 01:40, 21 May 2023
H-Sound is a sound engine created by Tsutomu Hagiwara of Sol for the SPC700 [1] [2]. The sound driver was used in five games.
Only one version, 0.5, was ever used. However, there are technically three different builds, each with very minor differences:
- Yuujin no Furi Furi Girls, compared to Kamen Rider SD, has extra valid percussion note slots and a single extra opcode that overwrites the timer value to use at the start, thus almost not even qualifying as a build variant.
- The other three games, compared to Kamen Rider SD, have extra valid percussion note slots and are missing an optional inversion operation for the echo volume. The latter only affects the mono/stereo setting.
Game Name | Build ID | VCMD Table Location ($E0 and up) | ROM Offset |
---|---|---|---|
Kamen Rider SD | 1 | 0x0C3D | 0x0C9B91 |
Yuujin no Furi Furi Girls | 2 | 0x0C45 | 0x888000 |
Hisshou Pachi-Slot Fun | 3 | 0x0C69 | 0x088000 |
Honkakuha Igo - Gosei | 3 | 0x0C69 | 0x0C8000 |
Janyuuki Gokuu Randa | 3 | 0x0C69 | 0x1D8000 |
The raw build sorting notes can be found here.
Communication with the SNES
Each command is triggered by sending the command ID to $2140/$F4. To send the same command ID again, toggle either of the highest two bits.
Output to the SNES
Two out of the four CPUIO registers are used as output from a command ID, and thus will be covered below under Command IDs.
%00xxxxxx ?? ?? yy
- %xxxxxx is the last non-zero command ID sent.
- yy is the output of an RNG function. This is updated continuously while timer 0 is outputting a zero (meaning it has not yet ticked).
Command IDs
Command ID | Description | Register Values & Arguments |
---|---|---|
%??000000 $00/$40/$80/$C0 |
NOP | %??000000 ?? ?? ?? |
%??000001 $01/$41/$81/$C1 |
Play Music/SFX | %??000001 xx ?? ?? |
%??000010 $02/$42/$82/$C2 |
Stop All Sound | %??000010 ?? ?? ?? |
%??000011 $03/$43/$83/$C3 |
Mute Channels | %??000011 %xxxxxxxx ?? ?? |
%??000100 $04/$44/$84/$C4 |
Echo Volume | %??000100 xx ?? ?? |
%??000101 $05/$45/$85/$C5 |
Main Volume | %??000101 xx yy ?? |
%??000110 $06/$46/$86/$C6 |
FLG DSP Register Set | %??000110 xx ?? ?? |
%??000111 $07/$47/$87/$C7 |
Acknowledge | %??000111 ?? ?? ?? |
%??001000 $08/$48/$88/$C8 |
Echo Feedback | %??001000 xx ?? ?? |
%??001001 $09/$49/$89/$C9 |
Global Absolute Transposition | %??001001 xx ?? ?? |
%??001010 $0A/$4A/$8A/$CA |
Song Tempo Offset | %??001010 xx ?? ?? |
%??001011 $0B/$4B/$8B/$CB |
Echo Enable Bits | %??001011 %xxxxxxxx ?? ?? |
%??001100 $0C/$4C/$8C/$CC |
FIR Coefficient Table ID | %??001100 xx ?? ?? |
%??001101 $0D/$4D/$8D/$CD |
Acknowledge + Stop All Sound + Load New Data | %??001101 ?? ?? ?? |
%??001110 $0E/$4E/$8E/$CE |
Acknowledge + Load New Data | %??001110 ?? ?? ?? |
%??001111 $0F/$4F/$8F/$CF |
Acknowledge + Stop All Sound + Load New Data + Play Music ID $00 | %??001111 ?? ?? ?? |
%??010000 $10/$50/$90/$D0 |
Set Instrument ID For Channel | %??010000 %?????xxx yy ?? |
%??010001 $11/$51/$91/$D1 |
Set Instrument ADSR For Channel | %??010001 %?????xxx yy zz |
%??010010 $12/$52/$92/$D2 |
Inverted Relative Main & Echo Volume | %??010010 xx yy ?? |
%??010011 $13/$53/$93/$D3 |
Relative Main & Echo Volume | %??010011 xx yy ?? |
%??010100 $14/$54/$94/$D4 |
Inverted Relative Song Tempo Offset | %??010100 xx ?? ?? |
%??010101 $15/$55/$95/$D5 |
Relative Song Tempo Offset | %??010101 xx ?? ?? |
%??010110 $16/$56/$96/$D6 |
Pitch Offset for Channel | %??010110 xx yy zz |
%??010111 $17/$57/$97/$D7 |
Set Stereo Mode | %??010111 ?? ?? ?? |
%??011000 $18/$58/$98/$D8 |
Redefine FIR Coefficient in Table | %??011000 xx yy zz |
%??011001 $19/$59/$99/$D9 |
Instrument Pitch Base Offset For Channel | %??011001 %?????xxx yy ?? |
%??011010 $1A/$5A/$9A/$DA |
Restart Program | %??011010 ?? ?? ?? |
%??010011 $1B/$5B/$9B/$DB |
Set Mono Mode | %??010011 ?? ?? ?? |
%??01010? $1C-$1D/$5C-$5D/$9C-$9D/$DC-$DD |
Stop All SFX | %??01010? ?? ?? ?? |
%??010110 $1E/$5E/$9E/$DE |
Fade Out | %??010110 ?? ?? ?? |
%??010111 $1F/$5F/$9F/$DF |
Stop All SFX | %??010111 ?? ?? ?? |
%??100000 $20/$60/$A0/$E0 |
Redefine Attack For Channel | %??100000 %0xxx0000 %0000yyyy ?? |
%??100001 $21/$61/$A1/$E1 |
Redefine Decay For Channel | %??100001 %0xxx0000 %00000yyy ?? |
%??100010 $22/$62/$A2/$E2 |
Redefine Sustain Level For Channel | %??100010 %0xxx0000 %00000yyy ?? ?? |
%??100011 $23/$63/$A3/$E3 |
Redefine Sustain Rate For Channel | %??100011 %0xxx0000 %000yyyyy ?? ?? |
$24-$3F/$64-$7F/$A4-$BF/$E4-$FF | Acknowledge | $24-$3F/$64-$7F/$A4-$BF/$E4-$FF ?? ?? ?? |
Acknowledge
Merely reads the bytes sent, then acknowledges the command ID sent back to $2140/$F4. It does nothing else.
NOP (Command ID $00/$40/$80/$C0)
Does absolutely nothing other than read the bytes sent. It doesn't even send an acknowledgement, unlike all other command IDs.
Play Music/SFX (Command ID $01/$41/$81/$C1)
%??000001 xx ?? ??
- xx is the ID to play. If it is less than $20, it is a music ID. Otherwise, it is a SFX ID. The MVOL DSP registers are always set to `$60` and the EVOL DSP registers are always set to `$30` (with one of them optionally getting inverted afterwards) when this command is executed.
Stop All Sound (Command ID $02/$42/$82/$C2)
Terminates all music and SFX playback as well as zeroing out the main and echo volumes.
Mute Channels (Command ID $03/$43/$83/$C3)
%??000011 %xxxxxxxx ?? ??
- %xxxxxxxx are the channel bits to mute.
Echo Volume (Command ID $04/$44/$84/$C4)
%??000100 xx ?? ??
- xx defines the volume used for the EVOLL and EVOLR DSP registers.
Main Volume (Command ID $05/$45/$85/$C5)
%??000101 xx ?? ??
- xx defines the volume used for the MVOLL and MVOLR DSP registers.
FLG DSP Register Set (Command ID $06/$46/$86/$C6)
%??000110 xx ?? ??
- xx defines the value used for the FLG DSP register.
Echo Feedback (Command ID $08/$48/$88/$C8)
%??001000 xx ?? ??
- xx defines the value used for the EFB DSP register.
Global Absolute Transposition (Command ID $09/$49/$89/$C9)
%??001001 xx ?? ??
- xx is a signed value defining the number of semitones to transpose subsequent notes. Note that this affects all channels, not just one channel, *and* it overwrites whatever the music had set previously.
Song Tempo Offset (Command ID $0A/$4A/$8A/$CA)
%??001010 xx ?? ??
- xx is a signed value that sets the amount to offset the song tempo.
Echo Enable Bits (Command ID $0B/$4B/$8B/$CB)
%??001011 %xxxxxxxx ?? ??
- %xxxxxxxx defines the value used for EON DSP register.
FIR Coefficient Table ID (Command ID $0C/$4C/$8C/$CC)
%??001100 xx ?? ??
- xx is an ID for a table of FIR coefficient IDs.
Load New Data (Command $0D-$0F/$4D-$4F/$8D-$8F/$CD-$CF)
Each command ID has a different approach prior to loading new data:
- $0D/$4D/$8D/$CD acknowledges with a fixed ID of $0D to $2140/$F4, then stops all sound (via executing command ID $02/$42/$82/$C2's routine).
- $0E/$4E/$8E/$CE acknowledges with the raw data from $2140/$F4 (that is, prior to ANDing it by $3F) ANDed by $1F, which de-facto results in an $0E being output. It doesn't stop sound, though.
- $0F/$4F/$8F/$CF acknowledges with a fixed ID of $0F to $2140/$F4, then stops all sound (via executing command ID $02/$42/$82/$C2's routine).
TODO Loading New Data (the loading protocol is nearly identical to IPL Boot ROM, with a couple of differences, and doesn't send out $AA $BB to $2140/$F4 and $2141/$F5, nor does it normally allow for jumping to other pieces of code)
Each command ID also has a different approach to concluding a data loading session:
- $0D/$4D/$8D/$CD acknowledges by zeroing out $2140/$F4.
- $0E/$4E/$8E/$CE outputs no acknowledgement.
- $0F/$4F/$8F/$CF acknowledges by zeroing out $2140/$F4 and playing music ID $00.
Set Instrument ID For Channel (Command ID $10/$50/$90/$D0)
%??010000 %?????xxx yy ???
- %xxx is the channel ID.
- yy is the instrument ID to assign for this channel.
Set Instrument ADSR For Channel (Command ID $11/$51/$91/$D1)
%??010001 %?????xxx yy zz
- %xxx is the channel ID.
- yy translates to a direct write to the VxADSR1 register for the instrument ID currently playing on the channel specified. The highest bit is automatically set to force ADSR mode.
- zz translates to a direct write to the VxADSR2 register for the instrument ID currently playing on the channel specified.
WARNING: This command permanently overwrites the ADSR settings for the instrument currently playing on the channel ID specified!
Inverted Relative Main & Echo Volume (Command ID $12/$52/$92/$D2)
%??010010 xx yy ??
- xx is the amount to decrease the volume used for the MVOLL and MVOLR DSP registers.
- yy is the amount to decrease the volume used for the EVOLL and EVOLR DSP registers... well, if it weren't for a bug that causes the EVOLL DSP register to be referred to twice by mistake, leaving the EVOLR DSP register reference untouched.
Relative Main & Echo Volume (Command ID $13/$53/$93/$D3)
%??010011 xx yy ??
- xx is the amount to increase the volume used for the MVOLL and MVOLR DSP registers.
- yy is the amount to increase the volume used for the EVOLL and EVOLR DSP registers... well, if it weren't for a bug that causes the EVOLL DSP register to be referred to twice by mistake, leaving the EVOLR DSP register reference untouched.
Inverted Relative Song Tempo Offset (Command ID $14/$54/$94/$D4)
%??010100 xx ?? ??
- xx is the amount to decrease the amount to offset the song tempo.
Relative Song Tempo Offset (Command ID $15/$55/$95/$D5)
%??010101 xx ?? ??
- xx is the amount to increase the amount to offset the song tempo.
Pitch Offset for Channel (Command ID $16/$56/$96/$D6)
%??010110 xx yy zz
- xx is the channel ID.
- yy is the amount in VxPITCHL units to offset the channel's pitch.
- zz is the amount in VxPITCHH units to offset the channel's pitch.
Set Stereo Mode (Command ID $17/$57/$97/$D7)
Sets the sound mode to stereo and outputs a $01 to $2141/$F5. In addition, on Kamen Rider SD and Yuujin no Furi Furi Girls (build IDs 1 and 2), it inverts the EVOLL DSP register.
Output
?? 01 ?? ??
Redefine FIR Coefficient in Table (Command ID $18/$58/$98/$D8)
%??011000 xx yy zz
- xx is the table ID.
- yy is the FIR coefficient ID.
- zz is the new FIR coefficient to set.
Instrument Pitch Base Offset For Channel (Command ID $19/$59/$99/$D9)
%??011001 %?????xxx yy ??
- %xxx is the channel ID.
- yy does one of two things to the pitch base multiplier for the instrument...
- If set to zero, the pitch base multiplier is decremented by 2/256.
- Otherwise, the pitch base multiplier is incremented by 2/256.
WARNING: This command permanently overwrites the pitch base settings for the instrument currently playing on the channel ID specified!
Restart Program (Command ID $1A/$5A/$9A/$DA)
Causes the program to completely restart, not by jumping to the IPL Boot ROM, but rather by jumping back to the start of the program and reinitializing everything.
Set Mono Mode (Command ID $1B/$5B/$9B/$DB)
Sets the sound mode to mono and outputs a $00 to $2141/$F5. In addition, on Kamen Rider SD and Yuujin no Furi Furi Girls (build IDs 1 and 2), the inversion operation on the EVOLL DSP register is canceled.
Output
?? 00 ?? ??
Stop All SFX (Command ID $1C-$1D, $1F/$5C-$5D, $5F/$9C-$9D, $9F/$DC-$DD, $DF)
Stops all SFX currently playing.
Fade Out (Command ID $1E/$5E/$9E/$DE)
Fades out the main and echo volumes one timer 0 tick after this is executed. The fade rate is as following:
- Main volume: 3 per five timer 0 ticks
- Echo volume: 2 per five timer 0 ticks
The echo volume is not affected by a bug that affects the relative main & echo volume command, where the same register reference was used twice by mistake.
Output
?? xx yy ??
- xx is the MVOLL DSP register value prior to fading out.
- yy is the EVOLL DSP register value prior to fading out.
Redefine Attack For Channel (Command ID $20/$60/$A0/$E0)
%??100000 %0xxx0000 %0000yyyy ??
- %xxx is the channel number whose VxADSR DSP registers will be modified. All other bits outside the one being set should be set to zero due to them not being filtered out: otherwise, the DSP register reference will be incorrect.
- %yyyy is the attack value to overwrite in the VxADSR1 DSP register. In addition to overwriting the attack value, the highest bit is automatically set to force ADSR mode. All other bits outside the one being set should be set to zero due to them not being filtered out: otherwise, you may accidentally set some bits when updating the ADSR1 DSP register.
Redefine Decay For Channel (Command ID $21/$61/$A1/$E1)
%??100001 %0xxx0000 %00000yyy ??
- %xxx is the channel number whose VxADSR DSP registers will be modified. All other bits outside the one being set should be set to zero due to them not being filtered out: otherwise, the DSP register reference will be incorrect.
- %yyy is the decay value to overwrite in the VxADSR1 DSP register. In addition to overwriting the decay value, the highest bit is automatically set to force ADSR mode. All other bits outside the one being set should be set to zero due to them not being filtered out: otherwise, you may accidentally set some bits when updating the ADSR1 DSP register.
Redefine Sustain Level For Channel (Command ID $22/$62/$A2/$E2)
%??100010 %0xxx0000 %00000yyy ??
- %xxx is the channel number whose VxADSR DSP registers will be modified. All other bits outside the one being set should be set to zero due to them not being filtered out: otherwise, the DSP register reference will be incorrect.
- %yyy is the sustain level value to overwrite in the VxADSR2 DSP register. In addition to overwriting the sustain level value, the highest bit is automatically set in the VxADSR1 DSP register to force ADSR mode. All other bits outside the one being set should be set to zero due to them not being filtered out: otherwise, you may accidentally set some bits when updating the VxADSR1 DSP register.
Redefine Sustain Rate For Channel (Command ID $23/$63/$A3/$E3)
%??100011 %0xxx0000 %000yyyyy ?? ??
- %xxx is the channel number whose VxADSR DSP registers will be modified. All other bits outside the one being set should be set to zero due to them not being filtered out: otherwise, the DSP register reference will be incorrect.
- %yyyyy is the sustain rate value to overwrite in the VxADSR2 DSP register. In addition to overwriting the sustain rate value, the highest bit is automatically set in the VxADSR1 DSP register to force ADSR mode. All other bits outside the one being set should be set to zero due to them not being filtered out: otherwise, you may accidentally set some bits when updating the VxADSR1 DSP register.
Instrument Format
The instrument format is N-SPC/Kankichi-kun compatible minus noise support for SRCN values above 127.
The instrument format is defined as the following bytes...
xx yy zz aa bb cc
- xx is a direct write to the VxSRCN DSP register.
- yy is a direct write to the VxADSR1 DSP register.
- zz is a direct write to the VxADSR2 DSP register.
- aa is a direct write to the VxGAIN DSP register.
- bb is a pitch base multiplier.
- cc is a fractional pitch base multiplier, defined in 256ths.
Header Format
Each song's header is a series of eight four-byte entries, one per channel. Thus, they show up like this in the data...
xx xx yy ?? xx xx yy ?? xx xx yy ?? xx xx yy ?? xx xx yy ?? xx xx yy ?? xx xx yy ?? xx xx yy ??
Each entry (consisting of one track) contains the following bytes...
xx xx yy ??
- xx xx is a little endian track pointer.
- yy is a master track ID. For the music, this is zero. For SFX, this is a non-zero value.
Voice Command Format
VCMD ID | Description | Arguments |
---|---|---|
$00-$60 | Note Length | |
$61-$71 | Invalid Velocity | |
$72-$79 | Velocity | |
$7A-$7F | Quantization | |
$80-$C7 | Note | |
$C8 | Instant Slide To Note | |
$C9 | Tie | |
$CA-$DF | Percussion | |
$E0 | Instrument | xx |
$E1 | Panning | xx |
$E2 | Note Volume | xx |
$E3 | NOP | |
$E4 | Pitch Offset | xx |
$E5 | Absolute Transposition | xx |
$E6 | Global Absolute Transposition | xx |
$E7 | Loop Section Start | |
$E8 | Loop Section End | xx |
$E9 | Tempo | xx |
$EA | NOP | |
$EB | Activate Percussion Mode | |
$EC | Echo On | |
$ED | Echo Off | |
$EE | ADSR | xx yy |
$EF | GAIN | xx |
$F0-$F1 | NOP | |
$F2 | Jump | xx xx |
$F3 | Noise Clock | %???xxxxx |
$F4 | Noise On | |
$F5 | Noise Off | |
$F6 | Key Off On Quantization Elapse Enable | |
$F7 | Key Off On Quantization Elapse Disable | |
$F8 | FIR Coefficient Table ID | xx |
$F9 | Echo Volume | xx |
$FA | Echo Feedback | xx |
$FB-$FD | NOP | |
$FE | End of Track | |
$FF | NOP |
NOP (VCMD $E3, $EA, $F0-$F1, $FB-$FD, $FF)
Does absolutely nothing.
Note Length (VCMD $00-$60)
Defines a note length in tempo ticks plus one.
Invalid Velocity (VCMD $61-$71)
These are invalid VCMD IDs. They technically work, just that they read invalid velocity parameters as a side effect.
Velocity (VCMD $72-$79)
Refers to an array that contains a value to multiply by when combined with other volume parameters.
Quantization (VCMD $7A-$7F)
Refers to an array that contains a percentage in 256ths for how far along the note to play before keying it off in tempo ticks.
NOTE: This affects all channels due to a bug in its implementation (specifically, there's no indexed loading when calculating the number of ticks before keying off), and it only works when the first channel defines the quantization.
Note (VCMD $80-$C7)
Plays a note and delays the channel for one note length before reading another VCMD.
Instant Slide To Note (VCMD $C8)
Sets up the next note to not be keyed on and instead merely changes the pitch to the next note indicated. Other VCMDs can be processed first prior to the note being defined.
Tie (VCMD $C9)
Continues playing the previous note and delays the channel for one note length before reading another VCMD.
Percussion (VCMD $CA-$DF)
Plays a percussion note. Each percussion note takes up an instrument slot starting at a hardcoded fixed offset, and has a dedicated fixed pitch to play at referred to via a separate table.
Instrument (VCMD $E0)
$E0 xx
- xx is an instrument ID to an array of instruments. See Instrument Format above for the format.
Panning (VCMD $E1)
$E1 xx
- xx is the panning value. $00 is left, and $FF is right.
Note Volume (VCMD $E2)
$E2 xx
- xx is the volume of the note.
Pitch Offset (VCMD $E4)
$E4 xx
- xx defines the offset in units used for the VxPITCHH DSP registers. This is applied after multiplying out all of the other pitches.
Absolute Transposition (VCMD $E5)
$E5 xx
- xx is a signed value defining the number of semitones to transpose subsequent notes.
Global Absolute Transposition (VCMD $E6)
$E6 xx
- xx is a signed value defining the number of semitones to transpose subsequent notes. Note that this affects all channels, not just one channel.
Loop Section Start (VCMD $E7)
Defines a starting point for a loop section. No nesting is allowed.
Loop Section End (VCMD $E8)
$E8 xx
- xx defines the number of times to go back to the loop section start marker.
Tempo (VCMD $E9)
$E9 xx
- xx defines the tempo. One tempo is equal to one timer 0 tick multiplied by .
Activate Percussion Mode (VCMD $EB)
Causes standard notes to be invalid and percussion notes to be valid. Without using this VCMD, percussion notes are a NOP instead.
Echo On (VCMD $EC)
Activates echo for the channel.
Echo Off (VCMD $ED)
Disables echo for the channel.
ADSR (VCMD $EE)
$EE xx yy
- xx is a direct write to the VxADSR1 register. The highest bit is automatically set to force ADSR mode.
- yy is a direct write to the VxADSR2 register.
GAIN (VCMD $EF)
$EF xx
The highest bit in the VxADSR1 register is automatically cleared to force GAIN mode.
- xx is a direct write to the VxGAIN register.
Jump (VCMD $F2)
$F2 xx xx
- xx xx is a little endian pointer indicating where to jump to.
Noise Clock (VCMD $F3)
$F3 %???xxxxx
- %xxxxx defines the speed of the noise clock in five bits.
Noise On (VCMD $F4)
Activates noise for the channel.
Noise Off (VCMD $F5)
Disables noise for the channel.
Key Off On Quantization Elapse Enable (VCMD $F6)
This enables an automatic key off when a percentage of the note length defined by the quantization value has elapsed.
Key Off On Quantization Elapse Disable (VCMD $F7)
This disables an automatic key off when a percentage of the note length defined by the quantization value has elapsed.
FIR Coefficient Table ID (VCMD $F8)
$F8 xx
- xx is an ID for a table of FIR coefficient IDs.
Echo Volume (VCMD $F9)
$F9 xx
- xx defines the volume used for the EVOLL and EVOLR DSP registers.
Echo Feedback (VCMD $FA)
$FA xx
- xx defines the value used for the EFB DSP register.
End of Track (VCMD $FE)
Stops the track from playing.