-
Notifications
You must be signed in to change notification settings - Fork 801
Sound engine commands (2019)
This site should/will describe all commands that are used by the Sound Engine of Pokemon Crystal (and in the future Pokemon Red). This is the result of revising the Code for the Sound Engine. While I'm working on it the name of the commands and their number of parametes may not match with the macros currently used in Pokecrystal.
It should also be a place to suggest some good names for the commands (which stand in the headline of the commands).
\1: number of the chosen octave (1-8)
db $d8 - (\1)
- usage:
- octave 2
Sets the octave for the following notes
\1: Note length (# frames per 16th note, shouldn't be greater than 16)
\2: Initial Volume of envelope (0-0Fh) (0=No Sound)
\3: Envelope Direction (0=Decrease, 1=Increase)
\4: Number of envelope sweep (n: 0-7) (If zero, stop envelope operation.)
db $d8, (\1), (\2 << 4) | (\3 << 3) | (\4)
- usage:
- notetype $c, $a, $0, $7
- following notes have length $c and start with volume=$a and slowly fade out
- notetype $7, $2, $1, $4
- following notes have length $7 and start with volume=$2 and get louder a bit faster than in the previous example
- notetype $a
- following notes have length $a (channel 4 has no volume envelope setting)
- notetype $c, $a, $0, $7
Sets the note length and (if we're not in channel 4) the volume envelope setting (see the command 'volenvelope') for the following notes.
The note length shouldn't be greater than 16, because it gets multiplied with the note duration (which is set with the note command, i.e. C_, 12) and of the result only the lower 8-Bits are taken into further calculation.
\1: octave (0 - 15)
\2: pitch (0 - 15)
db $d9, (\1 << 4) | (\2)
- usage:
- setabsnote 2, 0
Sets an absolute starting octave and pitch for all notes.
This forces all notes up by the starting pitch and octave.
\1: 8.8 fixed point number (with 8bit fractional part) (higher value = slower tempo)
db $da
dw (\1)
- usage:
- tempo 140
Sets the tempo of all channels to the chosen value.
The audio engine initialise this with $100.
Corresponds to bpm (beats per minute):
You also have to set the note length with the Cmd 'notetype', which corresponds to 'Ticks/Row'.
-
240 beats per minute
3600 frames per minute / (6 tickets per row * 4 row per beat) / 240 bpm = 0.625 frames per tick
0.625 frames per tick * 256 = 160 (this step is to convert to a fixed point value)
240 bpm = tempo 160 -
170 beats per minute
3600 frames per minute / (6 tickets per row * 4 rows per beat) / 170 bpm = 0.882 frames per tick
0.882 frames per tick * 256 = ~226
170 bpm = tempo 226
\1: Wave pattern duty setting (0-3)
db $db, (\1)
- usage:
- dutycycle 2
Sets the Wave pattern duty of the channel in register NRX1 (Bits 6-7).
\1: Initial Volume of envelope (0-0Fh) (0=No Sound)
\2: Envelope Direction (0=Decrease, 1=Increase)
\3: Number of envelope sweep (n: 0-7) (If zero, stop envelope operation.)
db $dc, (\1 << 4) | (\2 << 3) | (\3)
- usage:
- volenvelope $a, $0, $7
- following notes start with volume=$a and slowly fade out
- volenvelope $2, $1, $4
- following notes start with volume=$2 and get louder a bit faster than in the previous example
- volenvelope $a, $0, $0
- following notes have volume=$a without fading
- volenvelope $a, $0, $7
parameter is directly written in hardware register NRX2 of the corresponding channel
FF12 - NR12 - Channel 1 Volume Envelope (R/W)
* Bit 7-4 - Initial Volume of envelope (0-0Fh) (0=No Sound)
* Bit 3 - Envelope Direction (0=Decrease, 1=Increase)
* Bit 2-0 - Number of envelope sweep (n: 0-7) (If zero, stop envelope operation.)
Length of 1 step = n*(1/64) seconds
\1: Sweep Time (0-7)
\2: Sweep Direction (0=Increase, 1=Decrease)
\3: Number of sweep shift (n: 0-7)
db $dd, (\1 << 4) | (\2 << 3) | (\3)
- usage:
Loads Parameter into 'SoundInput'
Sets 3rd Bit in ChannelXNoteFlags
which later loads 'SoundInput' into NR10
FF10 - NR10 - Channel 1 Sweep register (R/W)
* Bit 6-4 - Sweep Time
* Bit 3 - Sweep Increase/Decrease
* 0: Addition (frequency increases)
* 1: Subtraction (frequency decreases)
* Bit 2-0 - Number of sweep shift (n: 0-7)
Sweep Time:
* 000: sweep off - no freq change
* 001: 7.8 ms (1/128Hz)
* 010: 15.6 ms (2/128Hz)
* 011: 23.4 ms (3/128Hz)
* 100: 31.3 ms (4/128Hz)
* 101: 39.1 ms (5/128Hz)
* 110: 46.9 ms (6/128Hz)
* 111: 54.7 ms (7/128Hz)
The change of frequency (NR13,NR14) at each shift is calculated by
the following formula where X(0) is initial freq & X(t-1) is last freq:
X(t) = X(t-1) +/- X(t-1)/2^n
\1: Wave pattern duty setting 1 (0-3)
\2: Wave pattern duty setting 2 (0-3)
\3: Wave pattern duty setting 3 (0-3)
\4: Wave pattern duty setting 4 (0-3)
db $de, (\1) | (\2 << 2) | (\3 << 4) | (\4 << 6)
- usage:
- dutycycle 0, 1, 2, 3
Rotates through 4 Settings of Wave Duty every frame.
Begins with Bits 0-1, then 2-3, 4-5, 6-7.
Only used for cries and sound effects.
FF11 - NR11 - Channel 1 Sound length/Wave pattern duty (R/W)
* Bit 7-6 - Wave Pattern Duty (Read/Write)
Wave Duty:
00: 12.5% ( _-------_-------_------- )
01: 25% ( __------__------__------ )
10: 50% ( ____----____----____---- ) (normal)
11: 75% ( ______--______--______-- )
\1: duration of the pitch
\2: octave
\3: pitch
db $e0, \1, (\2 << 4) | (\3 << 0)
- usage:
- unknownmusic0xe0 0, 1, 2
\1: vibrato delay (in frames)
\2: extent
\3: rate (# frames per cycle)
db $e1, \1, (\2 << 4) | \3
- usage:
Parameter is saved into the channel structure, but never used again.
The command is also never used by any song or sound effect.
\1:
db $e3, (\1)
- usage:
- togglenoise $05
The command is used for channel 4 to set the drumkit and with it the available drumsounds.
If noise sampling is off (the initial state) then it gets turned on, if noise sampling is on it gets turned off and no drumkit is set.
The Cmd is only used once per song in PokeCrystal so it's only used to set the drumkit.
\1:
db $e4, (\1)
- usage:
- panning $f0
The parameter acts like a BitMask for register NR51.
FF25 - NR51 - Selection of Sound output terminal (R/W)
Bit 7 - Output sound 4 to SO2 terminal
Bit 6 - Output sound 3 to SO2 terminal
Bit 5 - Output sound 2 to SO2 terminal
Bit 4 - Output sound 1 to SO2 terminal
Bit 3 - Output sound 4 to SO1 terminal
Bit 2 - Output sound 3 to SO1 terminal
Bit 1 - Output sound 2 to SO1 terminal
Bit 0 - Output sound 1 to SO1 terminal
\1: SO2 output level (volume) (0-7)
\2: SO1 output level (volume) (0-7)
db $e5, (\1 << 4) | (\2)
- usage:
- volume $7, $7 ; set volume of Left and Right to their maximum
parameter is directly written in hardware register NR50
**FF24 - NR50 - Channel control / ON-OFF / Volume (R/W)**
The volume bits specify the "Master Volume" for Left/Right sound output.
* Bit 7 - Output Vin to SO2 terminal (1=Enable)
* Bit 6-4 - SO2 output level (volume) (0-7)
* Bit 3 - Output Vin to SO1 terminal (1=Enable)
* Bit 2-0 - SO1 output level (volume) (0-7)
The Vin signal is received from the game cartridge bus, allowing external hardware
in the cartridge to supply a fifth sound channel, additionally to the gameboys
internal four channels. As far as I know this feature isn't used by any existing games.
\1: 11bit frequency
db $e6
dw (\1)
- usage:
- tone 0
The frequency gets added to the intern NRX3 and NRX4 register of the corresponding channel, so that every note gets shifted by the frequency that is set with this command.
The frequency is calculated with following formula.
Frequency = 131072/(2048-x) Hz
Parameter is saved into the channel structure, but never used again.
The command is also never used by any song or sound effect.
Parameter is saved into the channel structure, but never used again.
The command is also never used by any song or sound effect.
\1: signed 16bit-number (-2^8 - (2^8-1))
db $e9
dw (\1)
- usage:
- addtempo 20
- addtempo -30
Sets global tempo to current channel tempo +- parameter.
\1: 16bit-pointer
db $ee
dw (\1)
- usage:
- unknownmusic0xee Label
The command checks a byte that corresponds to the channel and decides to jump or not, but the byte that gets checked is never set.
\1:
db $ef, (\1)
- usage:
- stereopanning $f0
The command is only executed if stereo is activated in the options and then it acts the same as Cmd $e4.
\1:
db $f0, (\1)
- usage:
- sfxtogglenoise $4
Does the same as Cmd $e3 just for the SFX Channel.
Commands don't do anything.
db $f9
Sets a flag which is never used.
\1: conditionbyte
db $fa, \1
- usage:
- condition conditionbyte
Sets the condition read by Cmd $fb.
\1: condition
\2: address
db $fb, \1, \2
- usage:
- jumpif condition Label
Reads and Compares the condition set by Cmd $fa. If it's equa to the condition in this Cmd the jump is executed.
\1: 16bit-pointer
db $fc
dw (\1)
- usage:
- jumpchannel Label
The engine of the channel jumps to the given adress. MusicAdress of the corresponding channel is set to the paramter.
\1: count (0:infinite)
\2: address
db $fd, \1
dw (\2)
- usage:
- loopchannel 1, Label
\1: address
db $fe
dw (\1)
- usage:
- endchannel
Command ends the music stream.
When this command is encountered with subroutine flag set, we return to caller of the subroutine.