N-SPC Engine/Prototype

From SnesLab
Jump to: navigation, search

Go back to N-SPC Engine

Contents

The Prototype variant was used in two games: Super Mario World and Pilotwings. They are the only versions of the code that clearly pre-date the source code version provided with the IS-Sound unit. From a sound effect programming point of view, it can also be considered a predecessor to five other games that post-date the source code: SimCity, Legend of Zelda - A Link to the Past/Zelda no Densetsu - Kamigami no Triforce, Star Fox/Star Wing, Super Mario All-Stars/Super Mario Collection and Super Mario: Yoshi Island/Super Mario World 2: Yoshi's Island.

Game Name Music Version VCMD Table Location ($DA and up) ROM Offset
Super Mario World 0.0 0x0F90, relative to 0x0EDC (all other versions)
0x0FC4, relative to 0x0F10 (Super Mario All Stars + Super Mario World)
0x0E8000 (all other versions)
0x4E8000 (Super Mario All-Stars + Super Mario World)
Pilotwings 0.1 0x1317, relative to 0x1263 (US and Japanese versions)
0x12B4, relative to 0x1200 (European version)
0x0C8000 (all versions)

The build difference between the standalone Super Mario World and its variant in Super Mario All-Stars is an extra command for $2141/$F5: $F0. This command zeroes out the echo volume DSP registers, keys off all notes, zeroes out several memory locations then activates and jumps to the IPL boot program. The copy itself used for the $FF command is stored at $FE00 rather than in the middle of the program.

The build difference between the other versions and the European version of Pilotwings is similar to Super Mario All Stars and Super Mario World, except it's more like a complete replacement since it changes the operation of the $FF command for $2141/$F5. The echo volume DSP registers are zeroed out, all notes are keyed off, the EON register is cleared, echo writes are disabled, then we activate and jump to the IPL boot program instead of using a variant of it embedded in the program.

The raw build sorting notes can be found here.

Communication with the SNES

The communication protocol is game-specific. Both games have dedicated uses for each CPUIO register.

Super Mario World

CPUIO0 ($2140/$F4)

This register controls the SFX to play on channel 5.

Command ID Description
$00 NOP
%0xxxxxxx
$01-$7F
Play SFX Sequence Set 1
%1???????
$80-$FF
Hurry Up!
NOP (Command $00)

Does absolutely nothing.

Play SFX Sequence Set 1 (Command $01-$7F)
%0xxxxxxx
  • %xxxxxxx is the SFX ID to play. The ID currently playing is echoed back to $2140 on the SNES.
    • $11 zeroes out the song volume and pauses the music once it finishes playing.
    • $11 and $1D do not permit the Hurry Up! SFX command to be played until it is finished. They also cannot be interrupted, except by $11 or $12.

The $FF VCMD for this set only is programmed to restart the SFX from the beginning.

SFX Sequence Format

See the SFX Sequence Format subpage.

Hurry Up! (Command $80-$FF)

Plays SFX ID $1D on both SFX sequence sets and offsets the tempo by $0A without overflow checks. This can stack if it is played multiple times, but only the first one will remain in effect until forced off.

CPUIO1 ($2141/$F5)

This register controls the SFX on channel 8 and the Yoshi drums on channel 6.

Command ID Description
$00 NOP
$01 Jump
$02 Enable Yoshi Drums
$03 Disable Yoshi Drums
$04 Two-Note SFX
$05-$EF NOP
$F0 Go to IPL Boot ROM (All-Stars variant only)
$F1-$FE NOP
$FF Load New Data
NOP (Command $00, $05-$EF, $F1-$FE)

Does absolutely nothing.

Jump (Command $01)

Plays Mario's jumping SFX on channel 8. The value is echoed back to the SNES via $2141 while the SFX is playing.

Enable Yoshi Drums (Command $02)

Enables Yoshi drums. This is not echoed back to the SNES.

Yoshi drums are only supported on music IDs $01-$03 and $06. Channel 6 is set to SFX instrument ID $09 if this is true.

Disable Yoshi Drums (Command $03)

Disables Yoshi drums. This is not echoed back to the SNES.

Two-Note SFX (Command $04)

Plays two notes on channel 8. The value is echoed back to the SNES via $2141 while the SFX is playing.

Go to IPL Boot ROM (Command $F0)

This only works in the build variant used in Super Mario All Stars + Super Mario World.

TODO go into specifics on what exactly is cleared out here before going to the loader

Load New Data (Command $FF)

TODO go into specifics on what exactly is cleared out here before going to the loader
See the source build's Load New Data command for the loading protocol, as it is identical binary-wise to the copy used in this one minus the *Ver S1.20* string.

CPUIO2 ($2142/$F6)

This register controls the music.

Command ID Description
$00 NOP
%0xxxxxxx
$00-$7F
Play Music
%1???????
$80-$FF
Fade Out
NOP (Command $00)

Does absolutely nothing.

Play Music (Command $01-$7F)
%0xxxxxxx
  • %xxxxxxx is the music ID to play. The ID currently playing is echoed back to $2142 on the SNES.
    • $09-$0C, $0F, $10 and $16 reset the tempo speedup effect done by the Hurry Up! command.
Fade Out (Command $80-$FF)
%1???????

Fades out the music by sliding the song volume to zero over 240 tempo ticks.

CPUIO3 ($2143/$F7)

This register controls the SFX to play on channel 7.

Command ID Description
$00 NOP
xx
$01-$FF
Play SFX Sequence Set 2
NOP (Command $00)

Does absolutely nothing.

Play SFX Sequence Set 2 (Command $01-$FF)
xx
  • xx is the SFX ID to play. The ID currently playing is echoed back to $2143 on the SNES.
    • $05, $1D and $24 cannot be interrupted by any other instances. In order of priority, though, $24 can interrupt $1D, which in turn can interrupt $05.

The $FF VCMD for this set only is programmed to move the pointer back one byte instead of forward.

SFX Sequence Format

See the SFX Sequence Format subpage.

Pilotwings

CPUIO0 ($2140/$F4)

This register plays the music and controls the BRR wind noise.

Command ID Description
$00 NOP
%xyyzzzzz
$01-$FE
Play Music/BRR Wind Noise Frequency
$FF Fade Out
NOP (Command $00)

Does absolutely nothing.

Play Music/BRR Wind Noise Frequency (Command $01-$FE)

Input

%xyzaaaaa

Output

%000aaaaa

Plays a piece of music.

  • %x disables BRR wind noise playback on channel 8. This is forced on IDs $02, $0D and $11 if %x, %y and %z are all zero.
  • %y, with %x cleared, enables a higher-frequency wind noise. This takes precedence over %z.
  • %z, with %x cleared, enables a lower-frequency wind noise.
  • %zzzzz is the music ID. If zero, then the music will keep playing normally. Although the absolute limit is $1F, in reality it's $15 because the song table only goes that high up ID-wise. The ID currently playing is echoed back to $2140 on the SNES.
Fade Out (Command $FF)

Fades out the music by sliding the song volume to zero over 192 tempo ticks.

CPUIO1 ($2141/$F5)

This register controls the sound effects in channels 3 and 8.

Command ID Description
$00 NOP
xy
$01-$FE
Play SFX Sequence
$FF Load Data
NOP (Command $00)

Does absolutely nothing.

Play SFX Sequence (Command $01-$FE)

Input

xy

Output

0y

Two SFX can be triggered at once. Plus, each one has its own SFX collection to use.

  • x is a four-bit/one nibble SFX ID for channel 8.
    • $E mutes all other channels sound upon playing the SFX (including the music, which causes new values to not be acknowledged). Any other ID played afterwards unmutes the music. This also cannot be interrupted by other SFX value entered here except for $F.
    • $1 cannot be interrupted by other SFX in this same area except for $E and $F.
    • $5 plays nothing, although it still works for unmuting music and other channels.
  • y is a four-bit/one nibble SFX ID for channel 3. The ID currently playing is echoed back to $2141 on the SNES.
    • Some SFX are not interruptible. In order of uninterruptibility priority with other SFX IDs, we have $A, $7 ($5 is allowed to overwrite $7 in this instance), then $9.
    • $F plays nothing.
SFX Sequence Format

See the SFX Sequence Format subpage.

Load Data (Command $FF)

The operation is slightly different depending on what build you're using. Both clean up DSP registers first: specifically by keying off all notes and zeroing out the EVOL DSP registers, along disabling echo writes. Additionally, the European version clears out the EON DSP register, and the other versions mute the amplifier until the loading routine exits.

The European version jumps directly to the IPL Boot ROM, while all other versions instead use a modified copy.

See the source build's Load New Data command command for the loading protocol for the non-European versions, as it is identical binary-wise to the copy used in this one minus the *Ver S1.20* string.

CPUIO2 ($2142/$F6)

This controls the aircraft engine noise in channels 5 and 6.

Command ID Description
$00 NOP
%0xyyyyyy
$00-$7F
Engine Control
%10xxxxxx
$80-$BF
Break
%11??????
$C0-$FE
Skid
$FF Stop Engine
NOP (Command $00)

Does absolutely nothing.

Engine Control (Command $01-$7F)
%0xyyyyyy

The current engine value is echoed back to $2142 on the SNES.

  • %x, when starting the aircraft engine, determines what kind of noise it makes. A different command (other than NOP) must be used before changing the engine noise.
  • %yyyyy controls the engine noise frequency.
Break (Command $80-$BF)
%10xxxxxx
  • %xxxxxx only does something different when set to $01, which is a slight pitch variant. Otherwise, there's not much control here.
Skid (Command $C0-$FE)
%11??????
Stop Engine (Command $FF)

Basically acts as a reset for the aircraft engine back to default settings, in addition to stopping it.

CPUIO3 ($2143/$F7)

This controls a couple of pieces of miscellaneous SFX on channel 4. The ID currently playing is echoed back to $2143 on the SNES.

Command ID Description
$00, $03-$FF NOP
$01 Engine-Controlled SFX
$02 Beep
NOP (Command $00, $03-$FF)

Does absolutely nothing.

Engine-Controlled SFX (Command $01)

Plays a fixed sequence of notes on channel 4 at a variable note length controlled by the engine frequency that goes faster the higher the frequency. Only works with a CPUIO2 value of $02-$11: otherwise, it's a NOP.

The note length used is defined as $1B minus the frequency of the engine shifted right. This value is decremented twice on the last note.

Beep (Command $02)

Plays a single note on channel 4. No other conditions are required here.

Instrument Format

Compared to common N-SPC, this is mostly the same, except it is missing the pitch base fractional multiplier, and V0.0 doesn't have noise support. Otherwise, it's the same as before, defined as following...

V0.0

yy zz aa bb cc

V0.1

%xyyyyyyy zz aa bb cc
  • x is a noise clock switch. This is only valid in V0.1.
    • If set, noise is used and %??yyyyy represents the noise clock rate.
    • If cleared, %0yyyyyyy (or just yy for V0.0) is a direct write to the VxSRCN DSP register.
  • zz is a direct write to the VxADSR1 DSP register.
  • aa is a direct write to the VxADSR2 DSP register.
  • bb is a direct write to the VxGAIN DSP register.
  • cc is a pitch base multiplier.
  • dd is a fractional pitch base multiplier, defined in 256ths.

Percussion Format

Percussion is stored separately from the instrument format in the prototype version, because its format is nearly identical to an instrument, but it contains an extra byte at the end that defines the note to play. Thus, these bytes are defined as following...
V0.0

yy zz aa bb cc dd

V0.1

%xyyyyyyy zz aa bb cc dd
  • x is a noise clock switch. This is only valid in V0.1.
    • If set, noise is used and %??yyyyy represents the noise clock rate.
    • If cleared, %0yyyyyyy (or just yy for V0.0) is a direct write to the VxSRCN DSP register.
  • zz is a direct write to the VxADSR1 DSP register.
  • aa is a direct write to the VxADSR2 DSP register.
  • bb is a direct write to the VxGAIN DSP register.
  • cc is a pitch base multiplier.
  • dd is the note to play the percussion note at.

Phrase Format

Song entries, stored as little endian pointers, point to a list of phrases for the song to play. This is mostly identical to standard N-SPC, except it doesn't have fast forward commands.

Command ID Description Arguments
$00 $00 End of Song
$00 %0xxxxxxx
$00 $01-$7F
Jump x Times %0xxxxxxx yy yy
$00 %1???????
$00 $82-$FF
Always Jump xx xx
xx xx Play Pattern xx xx

Play Pattern

xx xx
  • xx xx is a little endian pointer to a set of eight pointers to track data, one for each channel.

Pattern Entry Format

xx xx yy yy zz zz aa aa bb bb cc cc dd dd ee ee
  • xx xx is a little endian pointer to a pattern order list for channel 1. If the pointer is zero, there is no track data.
  • yy yy is a little endian pointer to a pattern order list for channel 2. If the pointer is zero, there is no track data.
  • zz zz is a little endian pointer to a pattern order list for channel 3. If the pointer is zero, there is no track data.
  • aa aa is a little endian pointer to a pattern order list for channel 4. If the pointer is zero, there is no track data.
  • bb bb is a little endian pointer to a pattern order list for channel 5. If the pointer is zero, there is no track data.
  • cc cc is a little endian pointer to a pattern order list for channel 6. If the pointer is zero, there is no track data.
  • dd dd is a little endian pointer to a pattern order list for channel 7. If the pointer is zero, there is no track data.
  • ee ee is a little endian pointer to a pattern order list for channel 8. If the pointer is zero, there is no track data.

End of Song (Command $00 $00)

$00 $00

Terminates the song.

Jump x Times (Command $00 $01-$7F)

$00 %0xxxxxxx yy yy
  • %xxxxxxx is the number of times to jump.
  • yy yy is a little endian pointer to a phrase to jump to.

Always Jump (Command $00 $80-$FF)

$00 %1??????? xx xx

Voice Command Format

The IDs are different due to being an earlier version, and some VCMDs may not be defined yet. The ones that are used are listed below.

VCMD ID Description Arguments
$00 Phrase Termination/End of Subroutine
$01-$7F Note Duration xy
$80-$C5 Note
$C6 Tie
$C7-$CF Rest
$D0-$D9 Percussion
$DA Instrument xx
$DB Panning %xyzzzzz
$DC Panning Fade xx yy
$DD Pitch Slide to Note xx yy zz
$DE Vibrato On xx yy zz
$DF Vibrato Off
$E0 Song Volume xx
$E1 Song Volume Fade xx yy zz
$E2 Tempo xx
$E3 Tempo Fade xx yy
$E4 Global Absolute Transposition xx
$E5 Tremolo On xx yy zz
$E6 Tremolo Off
$E7 Volume xx
$E8 Volume Fade xx yy
$E9 Subroutine xx xx yy
$EA Vibrato Fade In xx
$EB Note Pitch Envelope To xx yy zz
$EC Note Pitch Envelope From xx yy zz
$ED Invalid (supposed to be Note Pitch Envelope Off)
$EE Fine Tune xx
$EF Echo Enable Bits and Volume %xxxxxxxx yy zz
$F0 Echo Off
$F1 Echo Parameter Setup xx yy zz
$F2 Echo Volume Fade xx yy zz
$F3-$FF Invalid

TODO use a template for the above table for standard VCMDs

Most of these essentially act identically to the common versions (refer back to the main page for info on those), but two of the VCMDs don't work properly: Note Pitch Envelope Off, which has a zeroed out pointer but the code does exist, and Tremolo On, which has a memory location definition bug for one of the parameters that conflicts with an internal value utilized by the tremolo, causing constant overwriting and making the command not work in general.