http://wiki.bindingforce.net/api.php?action=feedcontributions&user=Bentglasstube&feedformat=atomBindingForce Wiki - User contributions [en]2024-03-28T21:01:42ZUser contributionsMediaWiki 1.33.1http://wiki.bindingforce.net/index.php?title=Music_Engine_Description&diff=370Music Engine Description2023-08-19T05:08:49Z<p>Bentglasstube: /* Duration LUT */</p>
<hr />
<div>There are two separate music engines in Zelda 2. Both are in bank 6 (along<br />
with the song data). The music engine for the title screen resides at<br />
<code>$8000</code> and the engine for the rest of the game is at<br />
<code>$9000</code>. Each of these engines is called once per frame during the<br />
appropriate part of the game.<br />
<br />
Changes to the music engine should be very easy to make, as there is an<br />
abundance of free space in bank 6.<br />
<br />
== Title Music Engine ==<br />
<br />
The title music engine is different from the engine that plays music<br />
during the rest of the game. In particular, it has a wider range of<br />
notes that can be represented. If you want to look into the actual<br />
code, the title screen music engine main loop is at <code>$8000</code> (vesus<br />
<code>$9000</code> for the game music loop).<br />
<br />
The metadata for the songs is all the same as in the other areas,<br />
although the title music is actually broken up into several songs<br />
itself. These song boundaries control the timing of the title scroll.<br />
<br />
The following songs exist in the title song table:<br />
<br />
# Intro<br />
# Start<br />
# Build up<br />
# Main<br />
# Breakdown<br />
<br />
The start of song 2 triggers the title to scroll into view. The start<br />
of song 4 triggers a countdown until the story scroll begins. After<br />
song 5 finishes, the engine loops back to song 2.<br />
<br />
Within the note data, a special format is used. Rather than encoding<br />
the duration and pitch together in a single byte, the title music has<br />
"pitch" bytes and "duration" bytes. Any byte with the highest bit set<br />
(i.e. anything >= <code>$80</code>) is interpreted as a duration change, which<br />
sets the duration of all future notes. Anything else is a pitch value<br />
which indicates a note of the current duration should be played. The<br />
low nybble of duration values keys into a lookup table at bank 6 <code>$8084</code> <br />
and store the duration byte at <code>$07FF</code>. Values are as follows:<br />
<br />
* <code>$80</code> - 8 ticks (sixteenth note)<br />
* <code>$81</code> - 24 ticks (dotted eighth note)<br />
* <code>$82</code> - 16 ticks (eighth note)<br />
* <code>$83</code> - 32 ticks (quarter note)<br />
* <code>$84</code> - 48 ticks (dotted quarter note)<br />
* <code>$85</code> - 64 ticks (half note)<br />
* <code>$86</code> - 96 ticks (dotted half note)<br />
* <code>$87</code> - 128 ticks (whole note)<br />
* <code>$88</code> - 11 ticks (eighth note triplet, first two)<br />
* <code>$89</code> - 10 ticks (eighth note triplet, third)<br />
* <code>$8A</code> - 80 ticks (half note + eighth note)<br />
<br />
The pitch values are stored in a lookup table at bank 6 from <code>$808F</code> to <code>$810E</code>. Any value from <code>$00</code> to <code>$7F</code> represents an entry in this table.<br />
<code>$46</code> is A4 and every semitone away from that adds or subtracts 2 from<br />
the value. Thus, C5 (three semitones above A4) is <code>$4C</code>. As in the game music engine, the value<br />
<code>$02</code> represents a rest. Unlike the game music engine, <code>$00</code> also represents a rest but the code has special handling for <code>$02</code> so using that is recommended.<br />
<br />
-2- -3- -4- -5- -6- -7-<br />
C : $04 $1C $34 $4C $64 $7C<br />
C# : $06 $1E $36 $4E $66 $7F<br />
D : $08 $20 $38 $50 $68<br />
Eb : $0A $22 $3A $52 $6A<br />
E : $0C $24 $3C $54 $6C<br />
F : $0E $26 $3E $56 $6E<br />
F# : $10 $28 $40 $58 $70<br />
G : $12 $2A $42 $5A $72<br />
G# : $14 $2C $44 $5C $74<br />
A : $16 $2E $46 $5E $76<br />
Bb : $18 $30 $48 $60 $78<br />
B : $1A $32 $4A $62 $7A<br />
<br />
<br />
By way of an example, let's look at the main section of the vanilla<br />
title music. The title metadata starts at bank 6 <code>$84DA</code>:<br />
<br />
08 11 14 16 19 1E 1E 1E<br />
^ Main section<br />
<br />
The main section is the fourth song, starting at <code>$84DA + $16 = $84F0</code>:<br />
<br />
3F 3F 00<br />
<br />
This means there is a single phrase for the main section, which is<br />
repeated twice. The phrase data is at <code>$84DA + $3F = $8519</code>.<br />
<br />
00 3D 86 3A 1A 5F<br />
<br />
From this, we see the melody note data is located at <code>$863D</code>:<br />
<br />
83 Quarter notes<br />
02 Rest<br />
48 C5<br />
82 Eighth notes<br />
46 B4<br />
83 Quarter notes<br />
3E G4<br />
34 D4<br />
84 Dotted quarter notes<br />
2E B3<br />
83 Quarter notes<br />
30 C4<br />
34 D4<br />
3A F4<br />
38 E4<br />
34 D4<br />
30 C4<br />
82 Eighth notes<br />
34 D4<br />
83 Quarter notes<br />
30 C4<br />
85 Half notes<br />
2E B3<br />
82 Eighth notes<br />
02 Rest<br />
00 End of Data<br />
<br />
== Main Music Engine ==<br />
<br />
=== Data Tables ===<br />
<br />
There are several data tables used by the music engine.<br />
<br />
==== Pulse Envelope ====<br />
<br />
This table is used to set the volume of the pulse channels over time. The index<br />
used starts at a certain value and decrements, so the table is in reverse order.<br />
The index is halved before use, so each value lasts two frames.<br />
<br />
{| class="wikitable"<br />
|+ Pulse Envelope <code>$9135</code><br />
|90||91||91||91||92||92||92||92<br />
|-<br />
|93||93||94||94||94||95||95||95<br />
|-<br />
|96||96||96||97||97||97||98||98<br />
|}<br />
<br />
==== Duration LUT ====<br />
<br />
This table is used to determine the duration of a note. The note data is stored<br />
with 5 bits of pitch information and 3 bits of duration, as such:<br />
<br />
D1 D0 P4 P3 P2 P1 P0 D2<br />
<br />
The Get Note Duration routine shifts things around to get the D bits into the<br />
three least significant bits and masks it before use. This value is then added<br />
to the tempo value in <code>$E5</code> which is always a multiple of 8 to index<br />
into the following table:<br />
<br />
{| class="wikitable"<br />
|+Duration LUT <code>$914D</code><br />
|'''00'''||04||0C||08||10||18||20||05||06<br />
|-<br />
|'''08'''||''04''||''0F''||09||12||1B||24||06||06<br />
|-<br />
|'''10'''||05||0F||0A||14||1E||28||07||06<br />
|-<br />
|'''18'''||06||12||0C||18||24||30||08||10<br />
|-<br />
|'''20'''||07||15||0E||1C||2A||38||13||12<br />
|-<br />
|'''28'''||07||15||0E||1C||2A||38||09||0A<br />
|}<br />
<br />
The base value of each row is the third one, which represents an eighth note. The other values are usually related numbers to give these normal note lengths:<br />
<br />
# Sixteenth note&dagger;<br />
# Dotted eighth note&dagger;<br />
# Eighth note<br />
# Quarter note<br />
# Dotted quarter note<br />
# Half note<br />
<br />
The last two columns are used to do various kind of triplets. Since the values in the table are not always divisible by three, triplets need to be made by rounding. However, that would introduce error in the length of the notes, so a second value is used for the final triplet to correct that error. For example, in row <code>$10</code>, one would use <code>$07</code>, <code>$07</code>, <code>$06</code> for eighth note triplets. These lengths add up to 20 which is exactly twice the eighth note length of 10 in that row.<br />
<br />
&dagger; Row <code>$08</code> has weird values for columns 0 and 1 that are best avoided.<br />
<br />
==== Pitch LUT ====<br />
<br />
This table is used to detemine the pitch of a note. The note data is stored as<br />
described above, and the fact that the least significant bit is masked out is<br />
advantageous since the pulse channels can use 11 bits of timer data, so each<br />
entry in this table is actually two bytes wide.<br />
<br />
Rather than show the raw bytes here, it's more useful to show the rough note<br />
that those values represent. If the raw values are interesting to you, check<br />
the ROM for them. It's worth noting that some of the higher notes are several<br />
cents off from the listed note.<br />
<br />
{| class="wikitable"<br />
|+Pitch LUT <code>$918F</code><br />
| || 00|| 02|| 04|| 06|| 08|| 0a|| 0c|| 0e<br />
|-<br />
|00|| C3||---|| E3|| G3||G#3|| A3||A#3|| B3<br />
|-<br />
|10|| C4||C#4|| D4||D#4|| E4|| F4||F#4|| G4<br />
|-<br />
|20||G#4|| A4||A#4|| B4|| C5||C#5|| D5||D#5<br />
|-<br />
|30|| E5|| F5||F#5|| G5|| A5||A#5|| B5||C#3<br />
|-<br />
|40|| D3||D#3|| F3||F#3||G#5|| C6||C#6|| D6<br />
|-<br />
|50||D#6|| E6|| F6||F#6|| G6||G#6|| A6||A#6<br />
|-<br />
|60|| B6|| C7||C#7|| D7||D#7|| E7|| F7||F#7<br />
|-<br />
|70|| G7||G#7|| A7||A#7|| B7|| C8<br />
|}<br />
<br />
Value <code>$02</code> represents a rest.<br />
<br />
Note that although the table goes through <code>$7A</code> values above<br />
<code>$3E</code> aren't usable due to the 5 bit limit for pitch data in<br />
the song data. However, the sound effects routines make use of these<br />
extra notes. For example, the sword beam effect alternates between<br />
playing C7 and F6.<br />
<br />
==== Noise Samples ====<br />
<br />
Several sound effects use the same routine to load "samples" for the noise<br />
channel to play. These values have the noise volume in the high nybble and the<br />
noise period in the low nybble.<br />
<br />
$90E8 - Sword slash<br />
$9123 - Enemy hurt<br />
$912C - Crumble block<br />
<br />
=== Variables ===<br />
<br />
This is just a dump of RAM addresses used by the music engine and a short<br />
description of what they are.<br />
<br />
$00E0 - Current phrase note data address (low byte)<br />
$00E1 - Current phrase note data address (high byte)<br />
$00E2 - Song offset, converted from song id to be an index instead of a bit field<br />
$00E3 - Current phrase index<br />
$00E4 - Drums loop start<br />
$00E5 - Tempo<br />
$00E6 - Pulse 1 low bits (used for vibrato effect)<br />
$00E7 - Pulse 2 low bits (used for vibrato effect)<br />
$00E8 - Pitch storage, temporary<br />
$00E9 - Play sound effect<br />
$00EA - Disable music<br />
$00EB - Request new song<br />
$00EC - Play sound effect<br />
$00ED - Play sound effect<br />
$00EE - Play sound effect<br />
$00EF - Play sound effect<br />
<br />
$0707 - Current world<br />
$075F - Queued song, loaded after screen transitions<br />
$07DA - Ganon Laugh sample<br />
$07DB - Song to resume after fanfare<br />
$07DF - ??? Likely sound effect flag for pulse 1 channel override<br />
<br />
$07E0 - ??? Likely sound effect flag for noise channel<br />
$07E2 - Pulse 2 envelope index<br />
$07E3 - Pulse 1 envelope index<br />
$07E4 - Drums current note duration<br />
$07E5 - Bass current note duration<br />
$07E6 - Harmony current note duration<br />
$07E7 - Melody current note duration<br />
$07E8 - Drums next note index<br />
$07E9 - Bass next note index<br />
$07EA - Harmony next note index<br />
$07EB - Melody next note index<br />
<br />
$07EC - Ganon Laugh counter<br />
$07ED - Sound FX counter (E9)<br />
$07EE - Sound FX counter (E9)<br />
$07F5 - Sound FX counter (ED)<br />
<br />
$07FA - Current SFX (E9)<br />
$07FB - Current song<br />
$07FD - Current SFX (ED)<br />
$07FE - ??? Likely sound effect flag for pulse 2 channel override<br />
$07FF - Current SFX (EF)<br />
<br />
=== Routines ===<br />
<br />
This is a non-exhaustive list of the routines in bank 6 involving the playing of<br />
music and sound effects. Each routine also lists its address so you can search<br />
in a disassembly for the actual code for that routine if these descriptions<br />
aren't clear.<br />
<br />
==== Main Music Loop <code>$9000</code> ====<br />
<br />
Checks that the music disable flag is off, then runs several SFX routines.<br />
After the SFX routines, the main music routine runs. After all this, various<br />
music related memory locations are cleared.<br />
<br />
==== Configure Pulse1 Channel <code>$9031</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4000</code> and <code>$4001</code><br />
respectively.<br />
<br />
==== Configure Pulse2 Channel <code>$9038</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4004</code> and <code>$4005</code><br />
respectively.<br />
<br />
==== Play Note Pulse1 <code>$9042</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 1 channel.<br />
<br />
==== Play Note <code>$9044</code> ====<br />
<br />
Called by the various play note routines. Takes a pitch index in register a and<br />
uses register x as a channel selector. For the pulse channels, this routine<br />
also saves the lower 8 bits of the APU timer register to <code>$E6</code> or <code>$E7</code> which<br />
are used for a vibrato effect.<br />
<br />
==== Play Note Pulse2 <code>$9067</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 2 channel.<br />
<br />
==== Play Note Triangle <code>$906B</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the triangle channel.<br />
<br />
==== Get Note Duration <code>$906F</code> ====<br />
<br />
Takes note data in register a and looks up the duration. The original note<br />
data is saved in register x and the result of the duration lookup is put in<br />
register a. The duration lookup is offset by the tempo stored in <code>$E5</code>.<br />
<br />
==== Vibrato Pulse1 <code>$9089</code> ====<br />
<br />
Applies a vibrato effect on the pulse 1 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato Pulse2 <code>$9097</code> ====<br />
<br />
Applies a vibrato effect on the pulse 2 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato <code>$909E</code> ====<br />
<br />
Takes the duration of the note remaining in register a, the low bits of the APU<br />
timer in register y, and the channel to use in register x. This is called by<br />
the other vibrato routines after setting x appropriately.<br />
<br />
Uses the <code>$04</code> bit of the duration to either add or subtract 2 from the low<br />
timer bits. Only the low bits are used because writing to the high bits resets<br />
the phase of the channel which can cause clicks. None of the notes from the<br />
pitch LUT are close enough to the boundary for the change to require the high<br />
bits to change anyway, so this works out fine.<br />
<br />
==== Play E9 SFX <code>$920B</code> ====<br />
<br />
Plays the sound effect requested in <code>$E9</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EF SFX <code>$92F4</code> ====<br />
<br />
Plays the sound effect requested in <code>$EF</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EE SFX <code>$9408</code> ====<br />
<br />
Plays the sound effect requested in <code>$EE</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Noise <code>$959D</code> ====<br />
<br />
Configures the APU noise registers to make a noise burst. Takes configuration<br />
for registers <code>$400F</code>, <code>$400E</code>, and <code>$400C</code> in registers y, x, and a.<br />
<br />
==== Crumble Bridge SFX <code>$956C</code> ====<br />
<br />
Starts playing the sound effect for a crumble bridge crumbling. This uses both<br />
the noise and the triangle channels so it sets flags to disable the music on<br />
those channels. Continues with SFX Noise Decay.<br />
<br />
==== SFX Noise Decay <code>$9587</code> ====<br />
<br />
Counts down the timer in <code>$07F5</code> and turns off the noise when it reaches 0.<br />
Also clears the flag for the ED sound effect in <code>$07FD</code>.<br />
<br />
==== Play ED SFX <code>$95A7</code> ====<br />
<br />
Plays the sound effect request in <code>$ED</code> or continues the sound effect saved in<br />
<code>$07FD</code>. Existing sound effects which are higher than the current sound effect<br />
will be ignored. If the same sound effect is requested that is already playing,<br />
it will restart the sound effect except for <code>$80</code> which gives priority to<br />
continuing. When the sound is continued instead of newly played, the decay<br />
routine will be called instead.<br />
<br />
; <code>$02</code><br />
: Crumble Bridge<br />
; <code>$04</code> and <code>$10</code><br />
: Crumble Block / Enemy Hurt<br />
; <code>$20</code> and <code>$80</code><br />
: Sword Strike<br />
; <code>$40</code><br />
: Very short noise burst, probably unused. Doesn't store the effect, and doesn't have an associated decay.<br />
<br />
==== Crumble Block / Enemy Hurt SFX <code>$95E6</code> ====<br />
<br />
Starts playing the sound of a block breaking or an enemy getting hurt.<br />
<br />
==== Crumble Block / Enemy Hurt SFX Decay <code>$95EE</code> ====<br />
<br />
Looks up noise register values based on the timer and the sound effect value.<br />
Crumble Block samples are at <code>$912C</code> while Enemy Hurt is at <code>$9123</code>. Continues<br />
on to Play Noise Samples.<br />
<br />
==== Play Noise Samples <code>$9612</code> ====<br />
<br />
Takes a sample value in register a. The low four bits of this are used to set<br />
the noise period via APU register <code>$400E</code>. The high four bits are used to set<br />
the noise volume via APU register <code>$400C</code>.<br />
<br />
Continues on the SFX Noise Decay process.<br />
<br />
==== Sword Strike SFX <code>$9604</code> ====<br />
<br />
Starts playing the sound of swinging your sword. This looks up samples based on<br />
the duration left at <code>$90E8</code> and plays them via Play Noise Samples.<br />
<br />
==== Play EC SFX <code>$990B</code> ====<br />
<br />
Plays the sound effect requested in <code>$EC</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Music <code>$9B18</code> ====<br />
<br />
Plays the music for the game.<br />
<br />
Runs Load Song if a new song is requested in <code>$EB</code>. Otherwise, runs Play Notes<br />
if the current song is set in <code>$07FB</code>. If neither of these is true, do nothing.<br />
<br />
==== Next Song <code>$9B24</code> ====<br />
<br />
Checks if the previous song should loop. If not, calls Mute All and returns.<br />
<br />
If the previous song was <code>$01</code> (the "intro" to the main theme), sets the next<br />
song to <code>$02</code> (the main theme loop).<br />
<br />
If the previous song was <code>$10</code> (the item get / level up fanfare), sets the<br />
current song from <code>$07DB</code>. Otherwise, leaves the current song the same as the<br />
previous song.<br />
<br />
Proceeds to Load Song.<br />
<br />
==== Mute All <code>$9B3B</code> ====<br />
<br />
Clears the current song at <code>$07FB</code> and sets the APU registers to mute the volume<br />
on both pulse channels, the triangle channel, and the noise channel.<br />
<br />
==== Load Song <code>$9B61</code> ====<br />
<br />
Takes a song id in register a and preps some variables for that song.<br />
<br />
If the song is <code>$10</code> (item get / level up fanfare) then it first saves the<br />
previous song to <code>$07FB</code> if it is less than <code>$10</code> so that the previous music<br />
will resume after the fanfare.<br />
<br />
Sets the phrase counter at <code>$E3</code> to 0 and the song offset at <code>$E2</code> based on the<br />
song id. Song ids are a bit field, and the song offset is the position of the<br />
lowest bit in the song id for indexing into the song table.<br />
<br />
Proceeds to Load Song Data.<br />
<br />
==== Load Song Data <code>$9B80</code> ====<br />
<br />
Loads the music variables based on the current world and current song offset.<br />
<br />
There are four blocks of code that are basically the same, for each of the four<br />
different music tables. Each one just uses a different position for the tables<br />
to load.<br />
<br />
Based on the current world in <code>$0707</code> it loads data from these offsets:<br />
<br />
<code>$00</code><br />
: Overworld music - <code>$9B87</code><br />
<code>$01</code> or <code>$02</code><br />
: Town music - <code>$9BC6</code><br />
<code>$03</code> or <code>$04</code><br />
: Palace music - <code>$9C05</code><br />
<code>$05</code> or higher<br />
: Great Palace music - <code>$9C42</code><br />
<br />
First, uses the song offset in <code>$E2</code> to index into the song table at the base<br />
offset given above.<br />
<br />
The phrase counter at <code>$E3</code> is added to that and used as in index again to<br />
retrieve the current phrase offset. If the current phrase offset is <code>$00</code> that<br />
means the song is over and the process goes back to the Next Song routine.<br />
<br />
Otherwise, the following structure is read at the base offset above + phrase<br />
offset just calculated.<br />
<br />
* <code>$E5</code> Tempo<br />
* <code>$E0</code> Note Data Low<br />
* <code>$E1</code> Note Data High<br />
* <code>$07E9</code> Bass Note Pointer<br />
* <code>$07EA</code> Harmony Note Pointer<br />
* <code>$07E8</code> Drum Note Pointer<br />
<br />
After this, the drum loop start point at <code>$E4</code> is also set to the same value as<br />
the drum note pointer. The melody note pointer at <code>$07EB</code> is set to <code>$00</code>, and<br />
all the durations (melody at <code>$07E7</code>, harmony at <code>$07E6</code>, bass at <code>$07E5</code>, and<br />
drums at <code>$07E4</code>) are set to <code>$01</code>.<br />
<br />
Proceeds to Play Notes.<br />
<br />
==== Play Notes ====<br />
<br />
This routine is broken into four major and similar sections: one each for<br />
melody, harmony, bass, and drums. The general process is as follows:<br />
<br />
decrement duration<br />
if duration == 0 {<br />
load next note<br />
increment note pointer<br />
set duration for note<br />
if no overriding sound effect {<br />
play note on appropriate channel<br />
}<br />
}<br />
<br />
Some channels have unique processing at different points in this. For example,<br />
the melody note data is null terminated, so if the loaded note in <code>$00</code> then the<br />
routine will jump to Load Song Data instead to go to the next phrase. If the<br />
drums channel gets a <code>$00</code> note it will reset the drums note pointer to the<br />
drums loop start and repeat the phrase. The bass and harmony channels don't<br />
have this looping behavior. This means that if the bass or harmony channels<br />
aren't long enough, the engine will happily just play whatever data comes next<br />
in the ROM.<br />
<br />
The melody is played on pulse 2 channel, the harmony on pulse 1 (which gets<br />
subverted by sound effects that need just one pulse channel), the bass on the<br />
triangle channel, and the drums on the noise channel.<br />
<br />
For the pulse channels, after the note is played, the envelope counter for that<br />
channel (<code>$07E2</code> for pulse 1, <code>$07E3</code> for pulse 2) is set. Normally the<br />
envelope is set to <code>$2F</code> but song <code>$40</code> (crystal fanfare and final boss music)<br />
sets it to <code>$18</code> instead. The envelope is not set if no note was played because<br />
the pitch index was <code>$02</code> which indicates a rest.<br />
<br />
Also for the pulse channels, after the above pseudocode, the vibrato and<br />
enveloping happens as long as there is no overriding sound effect. The envelope<br />
works by checking the envelope counter set previously and decrementing it. The<br />
counter value is halved and used to look up the envelope value in the LUT at<br />
<code>$9135</code>. These values are written directly to APU register <code>$4000</code> or <code>$4004</code><br />
depending on the channel.<br />
<br />
The bass channel has one special handling as well. The APU register <code>$4008</code> is<br />
set differently based on the current song id. For song <code>$10</code> (item get / level<br />
up fanfare) the register is set to <code>$60</code> but all other songs use <code>$1f</code>.<br />
<br />
The noise channel is not affect at all by the pitch. Any pitch value that is<br />
non zero will play a burst of noise.</div>Bentglasstubehttp://wiki.bindingforce.net/index.php?title=Music_Engine_Description&diff=369Music Engine Description2023-08-18T04:06:16Z<p>Bentglasstube: /* Title Music Engine */</p>
<hr />
<div>There are two separate music engines in Zelda 2. Both are in bank 6 (along<br />
with the song data). The music engine for the title screen resides at<br />
<code>$8000</code> and the engine for the rest of the game is at<br />
<code>$9000</code>. Each of these engines is called once per frame during the<br />
appropriate part of the game.<br />
<br />
Changes to the music engine should be very easy to make, as there is an<br />
abundance of free space in bank 6.<br />
<br />
== Title Music Engine ==<br />
<br />
The title music engine is different from the engine that plays music<br />
during the rest of the game. In particular, it has a wider range of<br />
notes that can be represented. If you want to look into the actual<br />
code, the title screen music engine main loop is at <code>$8000</code> (vesus<br />
<code>$9000</code> for the game music loop).<br />
<br />
The metadata for the songs is all the same as in the other areas,<br />
although the title music is actually broken up into several songs<br />
itself. These song boundaries control the timing of the title scroll.<br />
<br />
The following songs exist in the title song table:<br />
<br />
# Intro<br />
# Start<br />
# Build up<br />
# Main<br />
# Breakdown<br />
<br />
The start of song 2 triggers the title to scroll into view. The start<br />
of song 4 triggers a countdown until the story scroll begins. After<br />
song 5 finishes, the engine loops back to song 2.<br />
<br />
Within the note data, a special format is used. Rather than encoding<br />
the duration and pitch together in a single byte, the title music has<br />
"pitch" bytes and "duration" bytes. Any byte with the highest bit set<br />
(i.e. anything >= <code>$80</code>) is interpreted as a duration change, which<br />
sets the duration of all future notes. Anything else is a pitch value<br />
which indicates a note of the current duration should be played. The<br />
low nybble of duration values keys into a lookup table at bank 6 <code>$8084</code> <br />
and store the duration byte at <code>$07FF</code>. Values are as follows:<br />
<br />
* <code>$80</code> - 8 ticks (sixteenth note)<br />
* <code>$81</code> - 24 ticks (dotted eighth note)<br />
* <code>$82</code> - 16 ticks (eighth note)<br />
* <code>$83</code> - 32 ticks (quarter note)<br />
* <code>$84</code> - 48 ticks (dotted quarter note)<br />
* <code>$85</code> - 64 ticks (half note)<br />
* <code>$86</code> - 96 ticks (dotted half note)<br />
* <code>$87</code> - 128 ticks (whole note)<br />
* <code>$88</code> - 11 ticks (eighth note triplet, first two)<br />
* <code>$89</code> - 10 ticks (eighth note triplet, third)<br />
* <code>$8A</code> - 80 ticks (half note + eighth note)<br />
<br />
The pitch values are stored in a lookup table at bank 6 from <code>$808F</code> to <code>$810E</code>. Any value from <code>$00</code> to <code>$7F</code> represents an entry in this table.<br />
<code>$46</code> is A4 and every semitone away from that adds or subtracts 2 from<br />
the value. Thus, C5 (three semitones above A4) is <code>$4C</code>. As in the game music engine, the value<br />
<code>$02</code> represents a rest. Unlike the game music engine, <code>$00</code> also represents a rest but the code has special handling for <code>$02</code> so using that is recommended.<br />
<br />
-2- -3- -4- -5- -6- -7-<br />
C : $04 $1C $34 $4C $64 $7C<br />
C# : $06 $1E $36 $4E $66 $7F<br />
D : $08 $20 $38 $50 $68<br />
Eb : $0A $22 $3A $52 $6A<br />
E : $0C $24 $3C $54 $6C<br />
F : $0E $26 $3E $56 $6E<br />
F# : $10 $28 $40 $58 $70<br />
G : $12 $2A $42 $5A $72<br />
G# : $14 $2C $44 $5C $74<br />
A : $16 $2E $46 $5E $76<br />
Bb : $18 $30 $48 $60 $78<br />
B : $1A $32 $4A $62 $7A<br />
<br />
<br />
By way of an example, let's look at the main section of the vanilla<br />
title music. The title metadata starts at bank 6 <code>$84DA</code>:<br />
<br />
08 11 14 16 19 1E 1E 1E<br />
^ Main section<br />
<br />
The main section is the fourth song, starting at <code>$84DA + $16 = $84F0</code>:<br />
<br />
3F 3F 00<br />
<br />
This means there is a single phrase for the main section, which is<br />
repeated twice. The phrase data is at <code>$84DA + $3F = $8519</code>.<br />
<br />
00 3D 86 3A 1A 5F<br />
<br />
From this, we see the melody note data is located at <code>$863D</code>:<br />
<br />
83 Quarter notes<br />
02 Rest<br />
48 C5<br />
82 Eighth notes<br />
46 B4<br />
83 Quarter notes<br />
3E G4<br />
34 D4<br />
84 Dotted quarter notes<br />
2E B3<br />
83 Quarter notes<br />
30 C4<br />
34 D4<br />
3A F4<br />
38 E4<br />
34 D4<br />
30 C4<br />
82 Eighth notes<br />
34 D4<br />
83 Quarter notes<br />
30 C4<br />
85 Half notes<br />
2E B3<br />
82 Eighth notes<br />
02 Rest<br />
00 End of Data<br />
<br />
== Main Music Engine ==<br />
<br />
=== Data Tables ===<br />
<br />
There are several data tables used by the music engine.<br />
<br />
==== Pulse Envelope ====<br />
<br />
This table is used to set the volume of the pulse channels over time. The index<br />
used starts at a certain value and decrements, so the table is in reverse order.<br />
The index is halved before use, so each value lasts two frames.<br />
<br />
{| class="wikitable"<br />
|+ Pulse Envelope <code>$9135</code><br />
|90||91||91||91||92||92||92||92<br />
|-<br />
|93||93||94||94||94||95||95||95<br />
|-<br />
|96||96||96||97||97||97||98||98<br />
|}<br />
<br />
==== Duration LUT ====<br />
<br />
This table is used to determine the duration of a note. The note data is stored<br />
with 5 bits of pitch information and 3 bits of duration, as such:<br />
<br />
D1 D0 P4 P3 P2 P1 P0 D2<br />
<br />
The Get Note Duration routine shifts things around to get the D bits into the<br />
three least significant bits and masks it before use. This value is then added<br />
to the tempo value in <code>$E5</code> which is always a multiple of 8 to index<br />
into the following table:<br />
<br />
{| class="wikitable"<br />
|+Duration LUT <code>$914D</code><br />
|'''00'''||04||0C||08||10||18||20||05||06<br />
|-<br />
|'''08'''||04||0F||09||12||1B||24||06||06<br />
|-<br />
|'''10'''||05||0F||0A||14||1E||28||07||06<br />
|-<br />
|'''18'''||06||12||0C||18||24||30||08||10<br />
|-<br />
|'''20'''||07||15||0E||1C||2A||38||13||12<br />
|-<br />
|'''28'''||07||15||0E||1C||2A||38||XX||XX<br />
|}<br />
<br />
The last two values in each row seem a bit strange, as they are not nice<br />
multiples of the first entry which is usually thought of as the length of an<br />
eighth note. They are usually used to make triplets which don't divide evenly by slightly shortening or lengthening the third triplet. The last row doesn't include these two values because they are nonsensical and actually belong to the next LUT anyway. That row is used for the credits music which presumably avoids those last two values.<br />
<br />
==== Pitch LUT ====<br />
<br />
This table is used to detemine the pitch of a note. The note data is stored as<br />
described above, and the fact that the least significant bit is masked out is<br />
advantageous since the pulse channels can use 11 bits of timer data, so each<br />
entry in this table is actually two bytes wide.<br />
<br />
Rather than show the raw bytes here, it's more useful to show the rough note<br />
that those values represent. If the raw values are interesting to you, check<br />
the ROM for them. It's worth noting that some of the higher notes are several<br />
cents off from the listed note.<br />
<br />
{| class="wikitable"<br />
|+Pitch LUT <code>$918F</code><br />
| || 00|| 02|| 04|| 06|| 08|| 0a|| 0c|| 0e<br />
|-<br />
|00|| C3||---|| E3|| G3||G#3|| A3||A#3|| B3<br />
|-<br />
|10|| C4||C#4|| D4||D#4|| E4|| F4||F#4|| G4<br />
|-<br />
|20||G#4|| A4||A#4|| B4|| C5||C#5|| D5||D#5<br />
|-<br />
|30|| E5|| F5||F#5|| G5|| A5||A#5|| B5||C#3<br />
|-<br />
|40|| D3||D#3|| F3||F#3||G#5|| C6||C#6|| D6<br />
|-<br />
|50||D#6|| E6|| F6||F#6|| G6||G#6|| A6||A#6<br />
|-<br />
|60|| B6|| C7||C#7|| D7||D#7|| E7|| F7||F#7<br />
|-<br />
|70|| G7||G#7|| A7||A#7|| B7|| C8<br />
|}<br />
<br />
Value <code>$02</code> represents a rest.<br />
<br />
Note that although the table goes through <code>$7A</code> values above<br />
<code>$3E</code> aren't usable due to the 5 bit limit for pitch data in<br />
the song data. However, the sound effects routines make use of these<br />
extra notes. For example, the sword beam effect alternates between<br />
playing C7 and F6.<br />
<br />
==== Noise Samples ====<br />
<br />
Several sound effects use the same routine to load "samples" for the noise<br />
channel to play. These values have the noise volume in the high nybble and the<br />
noise period in the low nybble.<br />
<br />
$90E8 - Sword slash<br />
$9123 - Enemy hurt<br />
$912C - Crumble block<br />
<br />
=== Variables ===<br />
<br />
This is just a dump of RAM addresses used by the music engine and a short<br />
description of what they are.<br />
<br />
$00E0 - Current phrase note data address (low byte)<br />
$00E1 - Current phrase note data address (high byte)<br />
$00E2 - Song offset, converted from song id to be an index instead of a bit field<br />
$00E3 - Current phrase index<br />
$00E4 - Drums loop start<br />
$00E5 - Tempo<br />
$00E6 - Pulse 1 low bits (used for vibrato effect)<br />
$00E7 - Pulse 2 low bits (used for vibrato effect)<br />
$00E8 - Pitch storage, temporary<br />
$00E9 - Play sound effect<br />
$00EA - Disable music<br />
$00EB - Request new song<br />
$00EC - Play sound effect<br />
$00ED - Play sound effect<br />
$00EE - Play sound effect<br />
$00EF - Play sound effect<br />
<br />
$0707 - Current world<br />
$075F - Queued song, loaded after screen transitions<br />
$07DA - Ganon Laugh sample<br />
$07DB - Song to resume after fanfare<br />
$07DF - ??? Likely sound effect flag for pulse 1 channel override<br />
<br />
$07E0 - ??? Likely sound effect flag for noise channel<br />
$07E2 - Pulse 2 envelope index<br />
$07E3 - Pulse 1 envelope index<br />
$07E4 - Drums current note duration<br />
$07E5 - Bass current note duration<br />
$07E6 - Harmony current note duration<br />
$07E7 - Melody current note duration<br />
$07E8 - Drums next note index<br />
$07E9 - Bass next note index<br />
$07EA - Harmony next note index<br />
$07EB - Melody next note index<br />
<br />
$07EC - Ganon Laugh counter<br />
$07ED - Sound FX counter (E9)<br />
$07EE - Sound FX counter (E9)<br />
$07F5 - Sound FX counter (ED)<br />
<br />
$07FA - Current SFX (E9)<br />
$07FB - Current song<br />
$07FD - Current SFX (ED)<br />
$07FE - ??? Likely sound effect flag for pulse 2 channel override<br />
$07FF - Current SFX (EF)<br />
<br />
=== Routines ===<br />
<br />
This is a non-exhaustive list of the routines in bank 6 involving the playing of<br />
music and sound effects. Each routine also lists its address so you can search<br />
in a disassembly for the actual code for that routine if these descriptions<br />
aren't clear.<br />
<br />
==== Main Music Loop <code>$9000</code> ====<br />
<br />
Checks that the music disable flag is off, then runs several SFX routines.<br />
After the SFX routines, the main music routine runs. After all this, various<br />
music related memory locations are cleared.<br />
<br />
==== Configure Pulse1 Channel <code>$9031</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4000</code> and <code>$4001</code><br />
respectively.<br />
<br />
==== Configure Pulse2 Channel <code>$9038</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4004</code> and <code>$4005</code><br />
respectively.<br />
<br />
==== Play Note Pulse1 <code>$9042</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 1 channel.<br />
<br />
==== Play Note <code>$9044</code> ====<br />
<br />
Called by the various play note routines. Takes a pitch index in register a and<br />
uses register x as a channel selector. For the pulse channels, this routine<br />
also saves the lower 8 bits of the APU timer register to <code>$E6</code> or <code>$E7</code> which<br />
are used for a vibrato effect.<br />
<br />
==== Play Note Pulse2 <code>$9067</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 2 channel.<br />
<br />
==== Play Note Triangle <code>$906B</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the triangle channel.<br />
<br />
==== Get Note Duration <code>$906F</code> ====<br />
<br />
Takes note data in register a and looks up the duration. The original note<br />
data is saved in register x and the result of the duration lookup is put in<br />
register a. The duration lookup is offset by the tempo stored in <code>$E5</code>.<br />
<br />
==== Vibrato Pulse1 <code>$9089</code> ====<br />
<br />
Applies a vibrato effect on the pulse 1 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato Pulse2 <code>$9097</code> ====<br />
<br />
Applies a vibrato effect on the pulse 2 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato <code>$909E</code> ====<br />
<br />
Takes the duration of the note remaining in register a, the low bits of the APU<br />
timer in register y, and the channel to use in register x. This is called by<br />
the other vibrato routines after setting x appropriately.<br />
<br />
Uses the <code>$04</code> bit of the duration to either add or subtract 2 from the low<br />
timer bits. Only the low bits are used because writing to the high bits resets<br />
the phase of the channel which can cause clicks. None of the notes from the<br />
pitch LUT are close enough to the boundary for the change to require the high<br />
bits to change anyway, so this works out fine.<br />
<br />
==== Play E9 SFX <code>$920B</code> ====<br />
<br />
Plays the sound effect requested in <code>$E9</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EF SFX <code>$92F4</code> ====<br />
<br />
Plays the sound effect requested in <code>$EF</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EE SFX <code>$9408</code> ====<br />
<br />
Plays the sound effect requested in <code>$EE</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Noise <code>$959D</code> ====<br />
<br />
Configures the APU noise registers to make a noise burst. Takes configuration<br />
for registers <code>$400F</code>, <code>$400E</code>, and <code>$400C</code> in registers y, x, and a.<br />
<br />
==== Crumble Bridge SFX <code>$956C</code> ====<br />
<br />
Starts playing the sound effect for a crumble bridge crumbling. This uses both<br />
the noise and the triangle channels so it sets flags to disable the music on<br />
those channels. Continues with SFX Noise Decay.<br />
<br />
==== SFX Noise Decay <code>$9587</code> ====<br />
<br />
Counts down the timer in <code>$07F5</code> and turns off the noise when it reaches 0.<br />
Also clears the flag for the ED sound effect in <code>$07FD</code>.<br />
<br />
==== Play ED SFX <code>$95A7</code> ====<br />
<br />
Plays the sound effect request in <code>$ED</code> or continues the sound effect saved in<br />
<code>$07FD</code>. Existing sound effects which are higher than the current sound effect<br />
will be ignored. If the same sound effect is requested that is already playing,<br />
it will restart the sound effect except for <code>$80</code> which gives priority to<br />
continuing. When the sound is continued instead of newly played, the decay<br />
routine will be called instead.<br />
<br />
; <code>$02</code><br />
: Crumble Bridge<br />
; <code>$04</code> and <code>$10</code><br />
: Crumble Block / Enemy Hurt<br />
; <code>$20</code> and <code>$80</code><br />
: Sword Strike<br />
; <code>$40</code><br />
: Very short noise burst, probably unused. Doesn't store the effect, and doesn't have an associated decay.<br />
<br />
==== Crumble Block / Enemy Hurt SFX <code>$95E6</code> ====<br />
<br />
Starts playing the sound of a block breaking or an enemy getting hurt.<br />
<br />
==== Crumble Block / Enemy Hurt SFX Decay <code>$95EE</code> ====<br />
<br />
Looks up noise register values based on the timer and the sound effect value.<br />
Crumble Block samples are at <code>$912C</code> while Enemy Hurt is at <code>$9123</code>. Continues<br />
on to Play Noise Samples.<br />
<br />
==== Play Noise Samples <code>$9612</code> ====<br />
<br />
Takes a sample value in register a. The low four bits of this are used to set<br />
the noise period via APU register <code>$400E</code>. The high four bits are used to set<br />
the noise volume via APU register <code>$400C</code>.<br />
<br />
Continues on the SFX Noise Decay process.<br />
<br />
==== Sword Strike SFX <code>$9604</code> ====<br />
<br />
Starts playing the sound of swinging your sword. This looks up samples based on<br />
the duration left at <code>$90E8</code> and plays them via Play Noise Samples.<br />
<br />
==== Play EC SFX <code>$990B</code> ====<br />
<br />
Plays the sound effect requested in <code>$EC</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Music <code>$9B18</code> ====<br />
<br />
Plays the music for the game.<br />
<br />
Runs Load Song if a new song is requested in <code>$EB</code>. Otherwise, runs Play Notes<br />
if the current song is set in <code>$07FB</code>. If neither of these is true, do nothing.<br />
<br />
==== Next Song <code>$9B24</code> ====<br />
<br />
Checks if the previous song should loop. If not, calls Mute All and returns.<br />
<br />
If the previous song was <code>$01</code> (the "intro" to the main theme), sets the next<br />
song to <code>$02</code> (the main theme loop).<br />
<br />
If the previous song was <code>$10</code> (the item get / level up fanfare), sets the<br />
current song from <code>$07DB</code>. Otherwise, leaves the current song the same as the<br />
previous song.<br />
<br />
Proceeds to Load Song.<br />
<br />
==== Mute All <code>$9B3B</code> ====<br />
<br />
Clears the current song at <code>$07FB</code> and sets the APU registers to mute the volume<br />
on both pulse channels, the triangle channel, and the noise channel.<br />
<br />
==== Load Song <code>$9B61</code> ====<br />
<br />
Takes a song id in register a and preps some variables for that song.<br />
<br />
If the song is <code>$10</code> (item get / level up fanfare) then it first saves the<br />
previous song to <code>$07FB</code> if it is less than <code>$10</code> so that the previous music<br />
will resume after the fanfare.<br />
<br />
Sets the phrase counter at <code>$E3</code> to 0 and the song offset at <code>$E2</code> based on the<br />
song id. Song ids are a bit field, and the song offset is the position of the<br />
lowest bit in the song id for indexing into the song table.<br />
<br />
Proceeds to Load Song Data.<br />
<br />
==== Load Song Data <code>$9B80</code> ====<br />
<br />
Loads the music variables based on the current world and current song offset.<br />
<br />
There are four blocks of code that are basically the same, for each of the four<br />
different music tables. Each one just uses a different position for the tables<br />
to load.<br />
<br />
Based on the current world in <code>$0707</code> it loads data from these offsets:<br />
<br />
<code>$00</code><br />
: Overworld music - <code>$9B87</code><br />
<code>$01</code> or <code>$02</code><br />
: Town music - <code>$9BC6</code><br />
<code>$03</code> or <code>$04</code><br />
: Palace music - <code>$9C05</code><br />
<code>$05</code> or higher<br />
: Great Palace music - <code>$9C42</code><br />
<br />
First, uses the song offset in <code>$E2</code> to index into the song table at the base<br />
offset given above.<br />
<br />
The phrase counter at <code>$E3</code> is added to that and used as in index again to<br />
retrieve the current phrase offset. If the current phrase offset is <code>$00</code> that<br />
means the song is over and the process goes back to the Next Song routine.<br />
<br />
Otherwise, the following structure is read at the base offset above + phrase<br />
offset just calculated.<br />
<br />
* <code>$E5</code> Tempo<br />
* <code>$E0</code> Note Data Low<br />
* <code>$E1</code> Note Data High<br />
* <code>$07E9</code> Bass Note Pointer<br />
* <code>$07EA</code> Harmony Note Pointer<br />
* <code>$07E8</code> Drum Note Pointer<br />
<br />
After this, the drum loop start point at <code>$E4</code> is also set to the same value as<br />
the drum note pointer. The melody note pointer at <code>$07EB</code> is set to <code>$00</code>, and<br />
all the durations (melody at <code>$07E7</code>, harmony at <code>$07E6</code>, bass at <code>$07E5</code>, and<br />
drums at <code>$07E4</code>) are set to <code>$01</code>.<br />
<br />
Proceeds to Play Notes.<br />
<br />
==== Play Notes ====<br />
<br />
This routine is broken into four major and similar sections: one each for<br />
melody, harmony, bass, and drums. The general process is as follows:<br />
<br />
decrement duration<br />
if duration == 0 {<br />
load next note<br />
increment note pointer<br />
set duration for note<br />
if no overriding sound effect {<br />
play note on appropriate channel<br />
}<br />
}<br />
<br />
Some channels have unique processing at different points in this. For example,<br />
the melody note data is null terminated, so if the loaded note in <code>$00</code> then the<br />
routine will jump to Load Song Data instead to go to the next phrase. If the<br />
drums channel gets a <code>$00</code> note it will reset the drums note pointer to the<br />
drums loop start and repeat the phrase. The bass and harmony channels don't<br />
have this looping behavior. This means that if the bass or harmony channels<br />
aren't long enough, the engine will happily just play whatever data comes next<br />
in the ROM.<br />
<br />
The melody is played on pulse 2 channel, the harmony on pulse 1 (which gets<br />
subverted by sound effects that need just one pulse channel), the bass on the<br />
triangle channel, and the drums on the noise channel.<br />
<br />
For the pulse channels, after the note is played, the envelope counter for that<br />
channel (<code>$07E2</code> for pulse 1, <code>$07E3</code> for pulse 2) is set. Normally the<br />
envelope is set to <code>$2F</code> but song <code>$40</code> (crystal fanfare and final boss music)<br />
sets it to <code>$18</code> instead. The envelope is not set if no note was played because<br />
the pitch index was <code>$02</code> which indicates a rest.<br />
<br />
Also for the pulse channels, after the above pseudocode, the vibrato and<br />
enveloping happens as long as there is no overriding sound effect. The envelope<br />
works by checking the envelope counter set previously and decrementing it. The<br />
counter value is halved and used to look up the envelope value in the LUT at<br />
<code>$9135</code>. These values are written directly to APU register <code>$4000</code> or <code>$4004</code><br />
depending on the channel.<br />
<br />
The bass channel has one special handling as well. The APU register <code>$4008</code> is<br />
set differently based on the current song id. For song <code>$10</code> (item get / level<br />
up fanfare) the register is set to <code>$60</code> but all other songs use <code>$1f</code>.<br />
<br />
The noise channel is not affect at all by the pitch. Any pitch value that is<br />
non zero will play a burst of noise.</div>Bentglasstubehttp://wiki.bindingforce.net/index.php?title=Music_Engine_Description&diff=368Music Engine Description2023-08-18T03:29:08Z<p>Bentglasstube: /* Title Music Engine */</p>
<hr />
<div>There are two separate music engines in Zelda 2. Both are in bank 6 (along<br />
with the song data). The music engine for the title screen resides at<br />
<code>$8000</code> and the engine for the rest of the game is at<br />
<code>$9000</code>. Each of these engines is called once per frame during the<br />
appropriate part of the game.<br />
<br />
Changes to the music engine should be very easy to make, as there is an<br />
abundance of free space in bank 6.<br />
<br />
== Title Music Engine ==<br />
<br />
The title music engine is different from the engine that plays music<br />
during the rest of the game. In particular, it has a wider range of<br />
notes that can be represented. If you want to look into the actual<br />
code, the title screen music engine main loop is at <code>$8000</code> (vesus<br />
<code>$9000</code> for the game music loop).<br />
<br />
The metadata for the songs is all the same as in the other areas,<br />
although the title music is actually broken up into several songs<br />
itself. These song boundaries control the timing of the title scroll.<br />
<br />
The following songs exist in the title song table:<br />
<br />
# Intro<br />
# Start<br />
# Build up<br />
# Main<br />
# Breakdown<br />
<br />
The start of song 2 triggers the title to scroll into view. The start<br />
of song 4 triggers a countdown until the story scroll begins. After<br />
song 5 finishes, the engine loops back to song 2.<br />
<br />
Within the note data, a special format is used. Rather than encoding<br />
the duration and pitch together in a single byte, the title music has<br />
"pitch" bytes and "duration" bytes. Any byte with the highest bit set<br />
(i.e. anything >= <code>$80</code>) is interpreted as a duration change, which<br />
sets the duration of all future notes. Anything else is a pitch value<br />
which indicates a note of the current duration should be played. The<br />
low nybble of duration values keys into a lookup table at bank 6 <code>$8084</code> <br />
and store the duration byte at <code>$07FF</code>. Values are as follows:<br />
<br />
* <code>$80</code> - 8 ticks (sixteenth note)<br />
* <code>$81</code> - 24 ticks (dotted eighth note)<br />
* <code>$82</code> - 16 ticks (eighth note)<br />
* <code>$83</code> - 32 ticks (quarter note)<br />
* <code>$84</code> - 48 ticks (dotted quarter note)<br />
* <code>$85</code> - 64 ticks (half note)<br />
* <code>$86</code> - 96 ticks (dotted half note)<br />
* <code>$87</code> - 128 ticks (whole note)<br />
* <code>$88</code> - 11 ticks (eighth note triplet, first two)<br />
* <code>$89</code> - 10 ticks (eighth note triplet, third)<br />
* <code>$8A</code> - 80 ticks (half note + eighth note)<br />
<br />
The pitch values are stored in a lookup table at bank 6 from <code>$808F</code> to <code>$810E</code>. Any value from <code>$00</code> to <code>$7F</code> represents an entry in this table.<br />
<code>$46</code> is A4 and every semitone away from that adds or subtracts 2 from<br />
the value. Thus, C5 (three semitones above A4) is <code>$4C</code>. As in the game music engine, the value<br />
<code>$02</code> represents a rest. Unlike the game music engine, <code>$00</code> also represents a rest but the code has special handling for <code>$02</code> so using that is recommended.<br />
<br />
-2- -3- -4- -5- -6- -7-<br />
C : $04 $1C $34 $4C $64 $7C<br />
C# : $06 $1E $36 $4E $66 $7F<br />
D : $08 $20 $38 $50 $68<br />
Eb : $0A $22 $3A $52 $6A<br />
E : $0C $24 $3C $54 $6C<br />
F : $0E $26 $3E $56 $6E<br />
F# : $10 $28 $40 $58 $70<br />
G : $12 $2A $42 $5A $72<br />
G# : $14 $2C $44 $5C $74<br />
A : $16 $2E $46 $5E $76<br />
Bb : $18 $30 $48 $60 $78<br />
B : $1A $32 $4A $62 $7A<br />
<br />
<br />
By way of an example, let's look at the main section of the vanilla<br />
title music. The title metadata starts at bank 6 <code>$84DA</code>:<br />
<br />
08 11 14 16 19 1E 1E 1E<br />
^ Main section<br />
<br />
The main section is the fourth song, starting at <code>$84DA + $16 = $84F0</code>:<br />
<br />
3F 3F 00<br />
<br />
This means there is a single phrase for the main section, which is<br />
repeated twice. The phrase data is at <code>$84DA + $3F = $8519</code>.<br />
<br />
00 3D 86 3A 1A 5F<br />
<br />
From this, we see the melody note data is located at <code>$863D</code>:<br />
<br />
83 Quarter notes<br />
02 Rest<br />
48 C5<br />
82 Eighth note<br />
46 B4<br />
83 Quarter notes<br />
3E G4<br />
34 D4<br />
84 Dotted quarter notes<br />
2E B3<br />
83 Quarter notes<br />
30 C4<br />
34 D4<br />
3A F4<br />
38 E4<br />
34 D4<br />
30 C4<br />
82 Eighth notes<br />
34 D4<br />
83 Quarter notes<br />
30 C4<br />
85 Half notes<br />
2E B3<br />
82 Quarter notes<br />
02 Rest<br />
00 End of Data<br />
<br />
== Main Music Engine ==<br />
<br />
=== Data Tables ===<br />
<br />
There are several data tables used by the music engine.<br />
<br />
==== Pulse Envelope ====<br />
<br />
This table is used to set the volume of the pulse channels over time. The index<br />
used starts at a certain value and decrements, so the table is in reverse order.<br />
The index is halved before use, so each value lasts two frames.<br />
<br />
{| class="wikitable"<br />
|+ Pulse Envelope <code>$9135</code><br />
|90||91||91||91||92||92||92||92<br />
|-<br />
|93||93||94||94||94||95||95||95<br />
|-<br />
|96||96||96||97||97||97||98||98<br />
|}<br />
<br />
==== Duration LUT ====<br />
<br />
This table is used to determine the duration of a note. The note data is stored<br />
with 5 bits of pitch information and 3 bits of duration, as such:<br />
<br />
D1 D0 P4 P3 P2 P1 P0 D2<br />
<br />
The Get Note Duration routine shifts things around to get the D bits into the<br />
three least significant bits and masks it before use. This value is then added<br />
to the tempo value in <code>$E5</code> which is always a multiple of 8 to index<br />
into the following table:<br />
<br />
{| class="wikitable"<br />
|+Duration LUT <code>$914D</code><br />
|'''00'''||04||0C||08||10||18||20||05||06<br />
|-<br />
|'''08'''||04||0F||09||12||1B||24||06||06<br />
|-<br />
|'''10'''||05||0F||0A||14||1E||28||07||06<br />
|-<br />
|'''18'''||06||12||0C||18||24||30||08||10<br />
|-<br />
|'''20'''||07||15||0E||1C||2A||38||13||12<br />
|-<br />
|'''28'''||07||15||0E||1C||2A||38||XX||XX<br />
|}<br />
<br />
The last two values in each row seem a bit strange, as they are not nice<br />
multiples of the first entry which is usually thought of as the length of an<br />
eighth note. They are usually used to make triplets which don't divide evenly by slightly shortening or lengthening the third triplet. The last row doesn't include these two values because they are nonsensical and actually belong to the next LUT anyway. That row is used for the credits music which presumably avoids those last two values.<br />
<br />
==== Pitch LUT ====<br />
<br />
This table is used to detemine the pitch of a note. The note data is stored as<br />
described above, and the fact that the least significant bit is masked out is<br />
advantageous since the pulse channels can use 11 bits of timer data, so each<br />
entry in this table is actually two bytes wide.<br />
<br />
Rather than show the raw bytes here, it's more useful to show the rough note<br />
that those values represent. If the raw values are interesting to you, check<br />
the ROM for them. It's worth noting that some of the higher notes are several<br />
cents off from the listed note.<br />
<br />
{| class="wikitable"<br />
|+Pitch LUT <code>$918F</code><br />
| || 00|| 02|| 04|| 06|| 08|| 0a|| 0c|| 0e<br />
|-<br />
|00|| C3||---|| E3|| G3||G#3|| A3||A#3|| B3<br />
|-<br />
|10|| C4||C#4|| D4||D#4|| E4|| F4||F#4|| G4<br />
|-<br />
|20||G#4|| A4||A#4|| B4|| C5||C#5|| D5||D#5<br />
|-<br />
|30|| E5|| F5||F#5|| G5|| A5||A#5|| B5||C#3<br />
|-<br />
|40|| D3||D#3|| F3||F#3||G#5|| C6||C#6|| D6<br />
|-<br />
|50||D#6|| E6|| F6||F#6|| G6||G#6|| A6||A#6<br />
|-<br />
|60|| B6|| C7||C#7|| D7||D#7|| E7|| F7||F#7<br />
|-<br />
|70|| G7||G#7|| A7||A#7|| B7|| C8<br />
|}<br />
<br />
Value <code>$02</code> represents a rest.<br />
<br />
Note that although the table goes through <code>$7A</code> values above<br />
<code>$3E</code> aren't usable due to the 5 bit limit for pitch data in<br />
the song data. However, the sound effects routines make use of these<br />
extra notes. For example, the sword beam effect alternates between<br />
playing C7 and F6.<br />
<br />
==== Noise Samples ====<br />
<br />
Several sound effects use the same routine to load "samples" for the noise<br />
channel to play. These values have the noise volume in the high nybble and the<br />
noise period in the low nybble.<br />
<br />
$90E8 - Sword slash<br />
$9123 - Enemy hurt<br />
$912C - Crumble block<br />
<br />
=== Variables ===<br />
<br />
This is just a dump of RAM addresses used by the music engine and a short<br />
description of what they are.<br />
<br />
$00E0 - Current phrase note data address (low byte)<br />
$00E1 - Current phrase note data address (high byte)<br />
$00E2 - Song offset, converted from song id to be an index instead of a bit field<br />
$00E3 - Current phrase index<br />
$00E4 - Drums loop start<br />
$00E5 - Tempo<br />
$00E6 - Pulse 1 low bits (used for vibrato effect)<br />
$00E7 - Pulse 2 low bits (used for vibrato effect)<br />
$00E8 - Pitch storage, temporary<br />
$00E9 - Play sound effect<br />
$00EA - Disable music<br />
$00EB - Request new song<br />
$00EC - Play sound effect<br />
$00ED - Play sound effect<br />
$00EE - Play sound effect<br />
$00EF - Play sound effect<br />
<br />
$0707 - Current world<br />
$075F - Queued song, loaded after screen transitions<br />
$07DA - Ganon Laugh sample<br />
$07DB - Song to resume after fanfare<br />
$07DF - ??? Likely sound effect flag for pulse 1 channel override<br />
<br />
$07E0 - ??? Likely sound effect flag for noise channel<br />
$07E2 - Pulse 2 envelope index<br />
$07E3 - Pulse 1 envelope index<br />
$07E4 - Drums current note duration<br />
$07E5 - Bass current note duration<br />
$07E6 - Harmony current note duration<br />
$07E7 - Melody current note duration<br />
$07E8 - Drums next note index<br />
$07E9 - Bass next note index<br />
$07EA - Harmony next note index<br />
$07EB - Melody next note index<br />
<br />
$07EC - Ganon Laugh counter<br />
$07ED - Sound FX counter (E9)<br />
$07EE - Sound FX counter (E9)<br />
$07F5 - Sound FX counter (ED)<br />
<br />
$07FA - Current SFX (E9)<br />
$07FB - Current song<br />
$07FD - Current SFX (ED)<br />
$07FE - ??? Likely sound effect flag for pulse 2 channel override<br />
$07FF - Current SFX (EF)<br />
<br />
=== Routines ===<br />
<br />
This is a non-exhaustive list of the routines in bank 6 involving the playing of<br />
music and sound effects. Each routine also lists its address so you can search<br />
in a disassembly for the actual code for that routine if these descriptions<br />
aren't clear.<br />
<br />
==== Main Music Loop <code>$9000</code> ====<br />
<br />
Checks that the music disable flag is off, then runs several SFX routines.<br />
After the SFX routines, the main music routine runs. After all this, various<br />
music related memory locations are cleared.<br />
<br />
==== Configure Pulse1 Channel <code>$9031</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4000</code> and <code>$4001</code><br />
respectively.<br />
<br />
==== Configure Pulse2 Channel <code>$9038</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4004</code> and <code>$4005</code><br />
respectively.<br />
<br />
==== Play Note Pulse1 <code>$9042</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 1 channel.<br />
<br />
==== Play Note <code>$9044</code> ====<br />
<br />
Called by the various play note routines. Takes a pitch index in register a and<br />
uses register x as a channel selector. For the pulse channels, this routine<br />
also saves the lower 8 bits of the APU timer register to <code>$E6</code> or <code>$E7</code> which<br />
are used for a vibrato effect.<br />
<br />
==== Play Note Pulse2 <code>$9067</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 2 channel.<br />
<br />
==== Play Note Triangle <code>$906B</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the triangle channel.<br />
<br />
==== Get Note Duration <code>$906F</code> ====<br />
<br />
Takes note data in register a and looks up the duration. The original note<br />
data is saved in register x and the result of the duration lookup is put in<br />
register a. The duration lookup is offset by the tempo stored in <code>$E5</code>.<br />
<br />
==== Vibrato Pulse1 <code>$9089</code> ====<br />
<br />
Applies a vibrato effect on the pulse 1 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato Pulse2 <code>$9097</code> ====<br />
<br />
Applies a vibrato effect on the pulse 2 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato <code>$909E</code> ====<br />
<br />
Takes the duration of the note remaining in register a, the low bits of the APU<br />
timer in register y, and the channel to use in register x. This is called by<br />
the other vibrato routines after setting x appropriately.<br />
<br />
Uses the <code>$04</code> bit of the duration to either add or subtract 2 from the low<br />
timer bits. Only the low bits are used because writing to the high bits resets<br />
the phase of the channel which can cause clicks. None of the notes from the<br />
pitch LUT are close enough to the boundary for the change to require the high<br />
bits to change anyway, so this works out fine.<br />
<br />
==== Play E9 SFX <code>$920B</code> ====<br />
<br />
Plays the sound effect requested in <code>$E9</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EF SFX <code>$92F4</code> ====<br />
<br />
Plays the sound effect requested in <code>$EF</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EE SFX <code>$9408</code> ====<br />
<br />
Plays the sound effect requested in <code>$EE</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Noise <code>$959D</code> ====<br />
<br />
Configures the APU noise registers to make a noise burst. Takes configuration<br />
for registers <code>$400F</code>, <code>$400E</code>, and <code>$400C</code> in registers y, x, and a.<br />
<br />
==== Crumble Bridge SFX <code>$956C</code> ====<br />
<br />
Starts playing the sound effect for a crumble bridge crumbling. This uses both<br />
the noise and the triangle channels so it sets flags to disable the music on<br />
those channels. Continues with SFX Noise Decay.<br />
<br />
==== SFX Noise Decay <code>$9587</code> ====<br />
<br />
Counts down the timer in <code>$07F5</code> and turns off the noise when it reaches 0.<br />
Also clears the flag for the ED sound effect in <code>$07FD</code>.<br />
<br />
==== Play ED SFX <code>$95A7</code> ====<br />
<br />
Plays the sound effect request in <code>$ED</code> or continues the sound effect saved in<br />
<code>$07FD</code>. Existing sound effects which are higher than the current sound effect<br />
will be ignored. If the same sound effect is requested that is already playing,<br />
it will restart the sound effect except for <code>$80</code> which gives priority to<br />
continuing. When the sound is continued instead of newly played, the decay<br />
routine will be called instead.<br />
<br />
; <code>$02</code><br />
: Crumble Bridge<br />
; <code>$04</code> and <code>$10</code><br />
: Crumble Block / Enemy Hurt<br />
; <code>$20</code> and <code>$80</code><br />
: Sword Strike<br />
; <code>$40</code><br />
: Very short noise burst, probably unused. Doesn't store the effect, and doesn't have an associated decay.<br />
<br />
==== Crumble Block / Enemy Hurt SFX <code>$95E6</code> ====<br />
<br />
Starts playing the sound of a block breaking or an enemy getting hurt.<br />
<br />
==== Crumble Block / Enemy Hurt SFX Decay <code>$95EE</code> ====<br />
<br />
Looks up noise register values based on the timer and the sound effect value.<br />
Crumble Block samples are at <code>$912C</code> while Enemy Hurt is at <code>$9123</code>. Continues<br />
on to Play Noise Samples.<br />
<br />
==== Play Noise Samples <code>$9612</code> ====<br />
<br />
Takes a sample value in register a. The low four bits of this are used to set<br />
the noise period via APU register <code>$400E</code>. The high four bits are used to set<br />
the noise volume via APU register <code>$400C</code>.<br />
<br />
Continues on the SFX Noise Decay process.<br />
<br />
==== Sword Strike SFX <code>$9604</code> ====<br />
<br />
Starts playing the sound of swinging your sword. This looks up samples based on<br />
the duration left at <code>$90E8</code> and plays them via Play Noise Samples.<br />
<br />
==== Play EC SFX <code>$990B</code> ====<br />
<br />
Plays the sound effect requested in <code>$EC</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Music <code>$9B18</code> ====<br />
<br />
Plays the music for the game.<br />
<br />
Runs Load Song if a new song is requested in <code>$EB</code>. Otherwise, runs Play Notes<br />
if the current song is set in <code>$07FB</code>. If neither of these is true, do nothing.<br />
<br />
==== Next Song <code>$9B24</code> ====<br />
<br />
Checks if the previous song should loop. If not, calls Mute All and returns.<br />
<br />
If the previous song was <code>$01</code> (the "intro" to the main theme), sets the next<br />
song to <code>$02</code> (the main theme loop).<br />
<br />
If the previous song was <code>$10</code> (the item get / level up fanfare), sets the<br />
current song from <code>$07DB</code>. Otherwise, leaves the current song the same as the<br />
previous song.<br />
<br />
Proceeds to Load Song.<br />
<br />
==== Mute All <code>$9B3B</code> ====<br />
<br />
Clears the current song at <code>$07FB</code> and sets the APU registers to mute the volume<br />
on both pulse channels, the triangle channel, and the noise channel.<br />
<br />
==== Load Song <code>$9B61</code> ====<br />
<br />
Takes a song id in register a and preps some variables for that song.<br />
<br />
If the song is <code>$10</code> (item get / level up fanfare) then it first saves the<br />
previous song to <code>$07FB</code> if it is less than <code>$10</code> so that the previous music<br />
will resume after the fanfare.<br />
<br />
Sets the phrase counter at <code>$E3</code> to 0 and the song offset at <code>$E2</code> based on the<br />
song id. Song ids are a bit field, and the song offset is the position of the<br />
lowest bit in the song id for indexing into the song table.<br />
<br />
Proceeds to Load Song Data.<br />
<br />
==== Load Song Data <code>$9B80</code> ====<br />
<br />
Loads the music variables based on the current world and current song offset.<br />
<br />
There are four blocks of code that are basically the same, for each of the four<br />
different music tables. Each one just uses a different position for the tables<br />
to load.<br />
<br />
Based on the current world in <code>$0707</code> it loads data from these offsets:<br />
<br />
<code>$00</code><br />
: Overworld music - <code>$9B87</code><br />
<code>$01</code> or <code>$02</code><br />
: Town music - <code>$9BC6</code><br />
<code>$03</code> or <code>$04</code><br />
: Palace music - <code>$9C05</code><br />
<code>$05</code> or higher<br />
: Great Palace music - <code>$9C42</code><br />
<br />
First, uses the song offset in <code>$E2</code> to index into the song table at the base<br />
offset given above.<br />
<br />
The phrase counter at <code>$E3</code> is added to that and used as in index again to<br />
retrieve the current phrase offset. If the current phrase offset is <code>$00</code> that<br />
means the song is over and the process goes back to the Next Song routine.<br />
<br />
Otherwise, the following structure is read at the base offset above + phrase<br />
offset just calculated.<br />
<br />
* <code>$E5</code> Tempo<br />
* <code>$E0</code> Note Data Low<br />
* <code>$E1</code> Note Data High<br />
* <code>$07E9</code> Bass Note Pointer<br />
* <code>$07EA</code> Harmony Note Pointer<br />
* <code>$07E8</code> Drum Note Pointer<br />
<br />
After this, the drum loop start point at <code>$E4</code> is also set to the same value as<br />
the drum note pointer. The melody note pointer at <code>$07EB</code> is set to <code>$00</code>, and<br />
all the durations (melody at <code>$07E7</code>, harmony at <code>$07E6</code>, bass at <code>$07E5</code>, and<br />
drums at <code>$07E4</code>) are set to <code>$01</code>.<br />
<br />
Proceeds to Play Notes.<br />
<br />
==== Play Notes ====<br />
<br />
This routine is broken into four major and similar sections: one each for<br />
melody, harmony, bass, and drums. The general process is as follows:<br />
<br />
decrement duration<br />
if duration == 0 {<br />
load next note<br />
increment note pointer<br />
set duration for note<br />
if no overriding sound effect {<br />
play note on appropriate channel<br />
}<br />
}<br />
<br />
Some channels have unique processing at different points in this. For example,<br />
the melody note data is null terminated, so if the loaded note in <code>$00</code> then the<br />
routine will jump to Load Song Data instead to go to the next phrase. If the<br />
drums channel gets a <code>$00</code> note it will reset the drums note pointer to the<br />
drums loop start and repeat the phrase. The bass and harmony channels don't<br />
have this looping behavior. This means that if the bass or harmony channels<br />
aren't long enough, the engine will happily just play whatever data comes next<br />
in the ROM.<br />
<br />
The melody is played on pulse 2 channel, the harmony on pulse 1 (which gets<br />
subverted by sound effects that need just one pulse channel), the bass on the<br />
triangle channel, and the drums on the noise channel.<br />
<br />
For the pulse channels, after the note is played, the envelope counter for that<br />
channel (<code>$07E2</code> for pulse 1, <code>$07E3</code> for pulse 2) is set. Normally the<br />
envelope is set to <code>$2F</code> but song <code>$40</code> (crystal fanfare and final boss music)<br />
sets it to <code>$18</code> instead. The envelope is not set if no note was played because<br />
the pitch index was <code>$02</code> which indicates a rest.<br />
<br />
Also for the pulse channels, after the above pseudocode, the vibrato and<br />
enveloping happens as long as there is no overriding sound effect. The envelope<br />
works by checking the envelope counter set previously and decrementing it. The<br />
counter value is halved and used to look up the envelope value in the LUT at<br />
<code>$9135</code>. These values are written directly to APU register <code>$4000</code> or <code>$4004</code><br />
depending on the channel.<br />
<br />
The bass channel has one special handling as well. The APU register <code>$4008</code> is<br />
set differently based on the current song id. For song <code>$10</code> (item get / level<br />
up fanfare) the register is set to <code>$60</code> but all other songs use <code>$1f</code>.<br />
<br />
The noise channel is not affect at all by the pitch. Any pitch value that is<br />
non zero will play a burst of noise.</div>Bentglasstubehttp://wiki.bindingforce.net/index.php?title=Music_Engine_Description&diff=367Music Engine Description2023-08-16T22:10:49Z<p>Bentglasstube: /* Title Music Engine */</p>
<hr />
<div>There are two separate music engines in Zelda 2. Both are in bank 6 (along<br />
with the song data). The music engine for the title screen resides at<br />
<code>$8000</code> and the engine for the rest of the game is at<br />
<code>$9000</code>. Each of these engines is called once per frame during the<br />
appropriate part of the game.<br />
<br />
Changes to the music engine should be very easy to make, as there is an<br />
abundance of free space in bank 6.<br />
<br />
== Title Music Engine ==<br />
<br />
The title music engine is different from the engine that plays music<br />
during the rest of the game. In particular, it has a wider range of<br />
notes that can be represented. If you want to look into the actual<br />
code, the title screen music engine main loop is at <code>$8000</code> (vesus<br />
<code>$9000</code> for the game music loop).<br />
<br />
The metadata for the songs is all the same as in the other areas,<br />
although the title music is actually broken up into several songs<br />
itself. These song boundaries control the timing of the title scroll.<br />
<br />
The following songs exist in the title song table:<br />
<br />
# Intro<br />
# Start<br />
# Build up<br />
# Main<br />
# Breakdown<br />
<br />
The start of song 2 triggers the title to scroll into view. The start<br />
of song 4 triggers a countdown until the story scroll begins. After<br />
song 5 finishes, the engine loops back to song 2.<br />
<br />
Within the note data, a special format is used. Rather than encoding<br />
the duration and pitch together in a single byte, the title music has<br />
"pitch" bytes and "duration" bytes. Any byte with the highest bit set<br />
(i.e. anything >= <code>$80</code>) is interpreted as a duration change, which<br />
sets the duration of all future notes. Anything else is a pitch value<br />
which indicates a note of the current duration should be played. The<br />
low nybble of duration values keys into a lookup table at bank 6 <code>$8084</code> <br />
and store the duration byte at <code>$07FF</code>. Values are as follows:<br />
<br />
* <code>$80</code> - 8 ticks (sixteenth note)<br />
* <code>$81</code> - 24 ticks (dotted eighth note)<br />
* <code>$82</code> - 16 ticks (eighth note)<br />
* <code>$83</code> - 32 ticks (quarter note)<br />
* <code>$84</code> - 48 ticks (dotted quarter note)<br />
* <code>$85</code> - 64 ticks (half note)<br />
* <code>$86</code> - 96 ticks (dotted half note)<br />
* <code>$87</code> - 128 ticks (whole note)<br />
* <code>$88</code> - 11 ticks (eighth note triplet, first two)<br />
* <code>$89</code> - 10 ticks (eighth note triplet, third)<br />
* <code>$8A</code> - 80 ticks (half note + eighth note)<br />
<br />
The pitch values are stored in a lookup table at bank 6 from <code>$808F</code> to <code>$810E</code>. Any value from <code>$00</code> to <code>$7F</code> represents an entry in this table.<br />
<code>$42</code> is A4 and every semitone away from that adds or subtracts 2 from<br />
the value. Thus, C5 (three semitones above A4) is <code>$48</code>. As in the game music engine, the value<br />
<code>$02</code> represents a rest. Unlike the game music engine, <code>$00</code> also represents a rest.<br />
<br />
-2- -3- -4- -5- -6- -7-<br />
C : $18 $30 $48 $60 $78<br />
C# : $1A $32 $4A $62 $7A<br />
D : $04 $1C $34 $4C $64<br />
Eb : $06 $1E $36 $4E $66<br />
E : $08 $20 $38 $50 $68<br />
F : $0A $22 $3A $52 $6A<br />
F# : $0C $24 $3C $54 $6C<br />
G : $0E $26 $3E $56 $6E<br />
G# : $10 $28 $40 $58 $70<br />
A : $12 $2A $42 $5A $72<br />
Bb : $14 $2C $44 $5C $74<br />
B : $16 $2E $46 $5E $76<br />
<br />
<br />
By way of an example, let's look at the main section of the vanilla<br />
title music. The title metadata starts at bank 6 <code>$84DA</code>:<br />
<br />
08 11 14 16 19 1E 1E 1E<br />
^ Main section<br />
<br />
The main section is the fourth song, starting at <code>$84DA + $16 = $84F0</code>:<br />
<br />
3F 3F 00<br />
<br />
This means there is a single phrase for the main section, which is<br />
repeated twice. The phrase data is at <code>$84DA + $3F = $8519</code>.<br />
<br />
00 3D 86 3A 1A 5F<br />
<br />
From this, we see the melody note data is located at <code>$863D</code>:<br />
<br />
83 Quarter notes<br />
02 Rest<br />
48 C5<br />
82 Eighth note<br />
46 B4<br />
83 Quarter notes<br />
3E G4<br />
34 D4<br />
84 Dotted quarter notes<br />
2E B3<br />
83 Quarter notes<br />
30 C4<br />
34 D4<br />
3A F4<br />
38 E4<br />
34 D4<br />
30 C4<br />
82 Eighth notes<br />
34 D4<br />
83 Quarter notes<br />
30 C4<br />
85 Half notes<br />
2E B3<br />
82 Quarter notes<br />
02 Rest<br />
00 End of Data<br />
<br />
== Main Music Engine ==<br />
<br />
=== Data Tables ===<br />
<br />
There are several data tables used by the music engine.<br />
<br />
==== Pulse Envelope ====<br />
<br />
This table is used to set the volume of the pulse channels over time. The index<br />
used starts at a certain value and decrements, so the table is in reverse order.<br />
The index is halved before use, so each value lasts two frames.<br />
<br />
{| class="wikitable"<br />
|+ Pulse Envelope <code>$9135</code><br />
|90||91||91||91||92||92||92||92<br />
|-<br />
|93||93||94||94||94||95||95||95<br />
|-<br />
|96||96||96||97||97||97||98||98<br />
|}<br />
<br />
==== Duration LUT ====<br />
<br />
This table is used to determine the duration of a note. The note data is stored<br />
with 5 bits of pitch information and 3 bits of duration, as such:<br />
<br />
D1 D0 P4 P3 P2 P1 P0 D2<br />
<br />
The Get Note Duration routine shifts things around to get the D bits into the<br />
three least significant bits and masks it before use. This value is then added<br />
to the tempo value in <code>$E5</code> which is always a multiple of 8 to index<br />
into the following table:<br />
<br />
{| class="wikitable"<br />
|+Duration LUT <code>$914D</code><br />
|'''00'''||04||0C||08||10||18||20||05||06<br />
|-<br />
|'''08'''||04||0F||09||12||1B||24||06||06<br />
|-<br />
|'''10'''||05||0F||0A||14||1E||28||07||06<br />
|-<br />
|'''18'''||06||12||0C||18||24||30||08||10<br />
|-<br />
|'''20'''||07||15||0E||1C||2A||38||13||12<br />
|-<br />
|'''28'''||07||15||0E||1C||2A||38||XX||XX<br />
|}<br />
<br />
The last two values in each row seem a bit strange, as they are not nice<br />
multiples of the first entry which is usually thought of as the length of an<br />
eighth note. They are usually used to make triplets which don't divide evenly by slightly shortening or lengthening the third triplet. The last row doesn't include these two values because they are nonsensical and actually belong to the next LUT anyway. That row is used for the credits music which presumably avoids those last two values.<br />
<br />
==== Pitch LUT ====<br />
<br />
This table is used to detemine the pitch of a note. The note data is stored as<br />
described above, and the fact that the least significant bit is masked out is<br />
advantageous since the pulse channels can use 11 bits of timer data, so each<br />
entry in this table is actually two bytes wide.<br />
<br />
Rather than show the raw bytes here, it's more useful to show the rough note<br />
that those values represent. If the raw values are interesting to you, check<br />
the ROM for them. It's worth noting that some of the higher notes are several<br />
cents off from the listed note.<br />
<br />
{| class="wikitable"<br />
|+Pitch LUT <code>$918F</code><br />
| || 00|| 02|| 04|| 06|| 08|| 0a|| 0c|| 0e<br />
|-<br />
|00|| C3||---|| E3|| G3||G#3|| A3||A#3|| B3<br />
|-<br />
|10|| C4||C#4|| D4||D#4|| E4|| F4||F#4|| G4<br />
|-<br />
|20||G#4|| A4||A#4|| B4|| C5||C#5|| D5||D#5<br />
|-<br />
|30|| E5|| F5||F#5|| G5|| A5||A#5|| B5||C#3<br />
|-<br />
|40|| D3||D#3|| F3||F#3||G#5|| C6||C#6|| D6<br />
|-<br />
|50||D#6|| E6|| F6||F#6|| G6||G#6|| A6||A#6<br />
|-<br />
|60|| B6|| C7||C#7|| D7||D#7|| E7|| F7||F#7<br />
|-<br />
|70|| G7||G#7|| A7||A#7|| B7|| C8<br />
|}<br />
<br />
Value <code>$02</code> represents a rest.<br />
<br />
Note that although the table goes through <code>$7A</code> values above<br />
<code>$3E</code> aren't usable due to the 5 bit limit for pitch data in<br />
the song data. However, the sound effects routines make use of these<br />
extra notes. For example, the sword beam effect alternates between<br />
playing C7 and F6.<br />
<br />
==== Noise Samples ====<br />
<br />
Several sound effects use the same routine to load "samples" for the noise<br />
channel to play. These values have the noise volume in the high nybble and the<br />
noise period in the low nybble.<br />
<br />
$90E8 - Sword slash<br />
$9123 - Enemy hurt<br />
$912C - Crumble block<br />
<br />
=== Variables ===<br />
<br />
This is just a dump of RAM addresses used by the music engine and a short<br />
description of what they are.<br />
<br />
$00E0 - Current phrase note data address (low byte)<br />
$00E1 - Current phrase note data address (high byte)<br />
$00E2 - Song offset, converted from song id to be an index instead of a bit field<br />
$00E3 - Current phrase index<br />
$00E4 - Drums loop start<br />
$00E5 - Tempo<br />
$00E6 - Pulse 1 low bits (used for vibrato effect)<br />
$00E7 - Pulse 2 low bits (used for vibrato effect)<br />
$00E8 - Pitch storage, temporary<br />
$00E9 - Play sound effect<br />
$00EA - Disable music<br />
$00EB - Request new song<br />
$00EC - Play sound effect<br />
$00ED - Play sound effect<br />
$00EE - Play sound effect<br />
$00EF - Play sound effect<br />
<br />
$0707 - Current world<br />
$075F - Queued song, loaded after screen transitions<br />
$07DA - Ganon Laugh sample<br />
$07DB - Song to resume after fanfare<br />
$07DF - ??? Likely sound effect flag for pulse 1 channel override<br />
<br />
$07E0 - ??? Likely sound effect flag for noise channel<br />
$07E2 - Pulse 2 envelope index<br />
$07E3 - Pulse 1 envelope index<br />
$07E4 - Drums current note duration<br />
$07E5 - Bass current note duration<br />
$07E6 - Harmony current note duration<br />
$07E7 - Melody current note duration<br />
$07E8 - Drums next note index<br />
$07E9 - Bass next note index<br />
$07EA - Harmony next note index<br />
$07EB - Melody next note index<br />
<br />
$07EC - Ganon Laugh counter<br />
$07ED - Sound FX counter (E9)<br />
$07EE - Sound FX counter (E9)<br />
$07F5 - Sound FX counter (ED)<br />
<br />
$07FA - Current SFX (E9)<br />
$07FB - Current song<br />
$07FD - Current SFX (ED)<br />
$07FE - ??? Likely sound effect flag for pulse 2 channel override<br />
$07FF - Current SFX (EF)<br />
<br />
=== Routines ===<br />
<br />
This is a non-exhaustive list of the routines in bank 6 involving the playing of<br />
music and sound effects. Each routine also lists its address so you can search<br />
in a disassembly for the actual code for that routine if these descriptions<br />
aren't clear.<br />
<br />
==== Main Music Loop <code>$9000</code> ====<br />
<br />
Checks that the music disable flag is off, then runs several SFX routines.<br />
After the SFX routines, the main music routine runs. After all this, various<br />
music related memory locations are cleared.<br />
<br />
==== Configure Pulse1 Channel <code>$9031</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4000</code> and <code>$4001</code><br />
respectively.<br />
<br />
==== Configure Pulse2 Channel <code>$9038</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4004</code> and <code>$4005</code><br />
respectively.<br />
<br />
==== Play Note Pulse1 <code>$9042</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 1 channel.<br />
<br />
==== Play Note <code>$9044</code> ====<br />
<br />
Called by the various play note routines. Takes a pitch index in register a and<br />
uses register x as a channel selector. For the pulse channels, this routine<br />
also saves the lower 8 bits of the APU timer register to <code>$E6</code> or <code>$E7</code> which<br />
are used for a vibrato effect.<br />
<br />
==== Play Note Pulse2 <code>$9067</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 2 channel.<br />
<br />
==== Play Note Triangle <code>$906B</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the triangle channel.<br />
<br />
==== Get Note Duration <code>$906F</code> ====<br />
<br />
Takes note data in register a and looks up the duration. The original note<br />
data is saved in register x and the result of the duration lookup is put in<br />
register a. The duration lookup is offset by the tempo stored in <code>$E5</code>.<br />
<br />
==== Vibrato Pulse1 <code>$9089</code> ====<br />
<br />
Applies a vibrato effect on the pulse 1 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato Pulse2 <code>$9097</code> ====<br />
<br />
Applies a vibrato effect on the pulse 2 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato <code>$909E</code> ====<br />
<br />
Takes the duration of the note remaining in register a, the low bits of the APU<br />
timer in register y, and the channel to use in register x. This is called by<br />
the other vibrato routines after setting x appropriately.<br />
<br />
Uses the <code>$04</code> bit of the duration to either add or subtract 2 from the low<br />
timer bits. Only the low bits are used because writing to the high bits resets<br />
the phase of the channel which can cause clicks. None of the notes from the<br />
pitch LUT are close enough to the boundary for the change to require the high<br />
bits to change anyway, so this works out fine.<br />
<br />
==== Play E9 SFX <code>$920B</code> ====<br />
<br />
Plays the sound effect requested in <code>$E9</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EF SFX <code>$92F4</code> ====<br />
<br />
Plays the sound effect requested in <code>$EF</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EE SFX <code>$9408</code> ====<br />
<br />
Plays the sound effect requested in <code>$EE</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Noise <code>$959D</code> ====<br />
<br />
Configures the APU noise registers to make a noise burst. Takes configuration<br />
for registers <code>$400F</code>, <code>$400E</code>, and <code>$400C</code> in registers y, x, and a.<br />
<br />
==== Crumble Bridge SFX <code>$956C</code> ====<br />
<br />
Starts playing the sound effect for a crumble bridge crumbling. This uses both<br />
the noise and the triangle channels so it sets flags to disable the music on<br />
those channels. Continues with SFX Noise Decay.<br />
<br />
==== SFX Noise Decay <code>$9587</code> ====<br />
<br />
Counts down the timer in <code>$07F5</code> and turns off the noise when it reaches 0.<br />
Also clears the flag for the ED sound effect in <code>$07FD</code>.<br />
<br />
==== Play ED SFX <code>$95A7</code> ====<br />
<br />
Plays the sound effect request in <code>$ED</code> or continues the sound effect saved in<br />
<code>$07FD</code>. Existing sound effects which are higher than the current sound effect<br />
will be ignored. If the same sound effect is requested that is already playing,<br />
it will restart the sound effect except for <code>$80</code> which gives priority to<br />
continuing. When the sound is continued instead of newly played, the decay<br />
routine will be called instead.<br />
<br />
; <code>$02</code><br />
: Crumble Bridge<br />
; <code>$04</code> and <code>$10</code><br />
: Crumble Block / Enemy Hurt<br />
; <code>$20</code> and <code>$80</code><br />
: Sword Strike<br />
; <code>$40</code><br />
: Very short noise burst, probably unused. Doesn't store the effect, and doesn't have an associated decay.<br />
<br />
==== Crumble Block / Enemy Hurt SFX <code>$95E6</code> ====<br />
<br />
Starts playing the sound of a block breaking or an enemy getting hurt.<br />
<br />
==== Crumble Block / Enemy Hurt SFX Decay <code>$95EE</code> ====<br />
<br />
Looks up noise register values based on the timer and the sound effect value.<br />
Crumble Block samples are at <code>$912C</code> while Enemy Hurt is at <code>$9123</code>. Continues<br />
on to Play Noise Samples.<br />
<br />
==== Play Noise Samples <code>$9612</code> ====<br />
<br />
Takes a sample value in register a. The low four bits of this are used to set<br />
the noise period via APU register <code>$400E</code>. The high four bits are used to set<br />
the noise volume via APU register <code>$400C</code>.<br />
<br />
Continues on the SFX Noise Decay process.<br />
<br />
==== Sword Strike SFX <code>$9604</code> ====<br />
<br />
Starts playing the sound of swinging your sword. This looks up samples based on<br />
the duration left at <code>$90E8</code> and plays them via Play Noise Samples.<br />
<br />
==== Play EC SFX <code>$990B</code> ====<br />
<br />
Plays the sound effect requested in <code>$EC</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Music <code>$9B18</code> ====<br />
<br />
Plays the music for the game.<br />
<br />
Runs Load Song if a new song is requested in <code>$EB</code>. Otherwise, runs Play Notes<br />
if the current song is set in <code>$07FB</code>. If neither of these is true, do nothing.<br />
<br />
==== Next Song <code>$9B24</code> ====<br />
<br />
Checks if the previous song should loop. If not, calls Mute All and returns.<br />
<br />
If the previous song was <code>$01</code> (the "intro" to the main theme), sets the next<br />
song to <code>$02</code> (the main theme loop).<br />
<br />
If the previous song was <code>$10</code> (the item get / level up fanfare), sets the<br />
current song from <code>$07DB</code>. Otherwise, leaves the current song the same as the<br />
previous song.<br />
<br />
Proceeds to Load Song.<br />
<br />
==== Mute All <code>$9B3B</code> ====<br />
<br />
Clears the current song at <code>$07FB</code> and sets the APU registers to mute the volume<br />
on both pulse channels, the triangle channel, and the noise channel.<br />
<br />
==== Load Song <code>$9B61</code> ====<br />
<br />
Takes a song id in register a and preps some variables for that song.<br />
<br />
If the song is <code>$10</code> (item get / level up fanfare) then it first saves the<br />
previous song to <code>$07FB</code> if it is less than <code>$10</code> so that the previous music<br />
will resume after the fanfare.<br />
<br />
Sets the phrase counter at <code>$E3</code> to 0 and the song offset at <code>$E2</code> based on the<br />
song id. Song ids are a bit field, and the song offset is the position of the<br />
lowest bit in the song id for indexing into the song table.<br />
<br />
Proceeds to Load Song Data.<br />
<br />
==== Load Song Data <code>$9B80</code> ====<br />
<br />
Loads the music variables based on the current world and current song offset.<br />
<br />
There are four blocks of code that are basically the same, for each of the four<br />
different music tables. Each one just uses a different position for the tables<br />
to load.<br />
<br />
Based on the current world in <code>$0707</code> it loads data from these offsets:<br />
<br />
<code>$00</code><br />
: Overworld music - <code>$9B87</code><br />
<code>$01</code> or <code>$02</code><br />
: Town music - <code>$9BC6</code><br />
<code>$03</code> or <code>$04</code><br />
: Palace music - <code>$9C05</code><br />
<code>$05</code> or higher<br />
: Great Palace music - <code>$9C42</code><br />
<br />
First, uses the song offset in <code>$E2</code> to index into the song table at the base<br />
offset given above.<br />
<br />
The phrase counter at <code>$E3</code> is added to that and used as in index again to<br />
retrieve the current phrase offset. If the current phrase offset is <code>$00</code> that<br />
means the song is over and the process goes back to the Next Song routine.<br />
<br />
Otherwise, the following structure is read at the base offset above + phrase<br />
offset just calculated.<br />
<br />
* <code>$E5</code> Tempo<br />
* <code>$E0</code> Note Data Low<br />
* <code>$E1</code> Note Data High<br />
* <code>$07E9</code> Bass Note Pointer<br />
* <code>$07EA</code> Harmony Note Pointer<br />
* <code>$07E8</code> Drum Note Pointer<br />
<br />
After this, the drum loop start point at <code>$E4</code> is also set to the same value as<br />
the drum note pointer. The melody note pointer at <code>$07EB</code> is set to <code>$00</code>, and<br />
all the durations (melody at <code>$07E7</code>, harmony at <code>$07E6</code>, bass at <code>$07E5</code>, and<br />
drums at <code>$07E4</code>) are set to <code>$01</code>.<br />
<br />
Proceeds to Play Notes.<br />
<br />
==== Play Notes ====<br />
<br />
This routine is broken into four major and similar sections: one each for<br />
melody, harmony, bass, and drums. The general process is as follows:<br />
<br />
decrement duration<br />
if duration == 0 {<br />
load next note<br />
increment note pointer<br />
set duration for note<br />
if no overriding sound effect {<br />
play note on appropriate channel<br />
}<br />
}<br />
<br />
Some channels have unique processing at different points in this. For example,<br />
the melody note data is null terminated, so if the loaded note in <code>$00</code> then the<br />
routine will jump to Load Song Data instead to go to the next phrase. If the<br />
drums channel gets a <code>$00</code> note it will reset the drums note pointer to the<br />
drums loop start and repeat the phrase. The bass and harmony channels don't<br />
have this looping behavior. This means that if the bass or harmony channels<br />
aren't long enough, the engine will happily just play whatever data comes next<br />
in the ROM.<br />
<br />
The melody is played on pulse 2 channel, the harmony on pulse 1 (which gets<br />
subverted by sound effects that need just one pulse channel), the bass on the<br />
triangle channel, and the drums on the noise channel.<br />
<br />
For the pulse channels, after the note is played, the envelope counter for that<br />
channel (<code>$07E2</code> for pulse 1, <code>$07E3</code> for pulse 2) is set. Normally the<br />
envelope is set to <code>$2F</code> but song <code>$40</code> (crystal fanfare and final boss music)<br />
sets it to <code>$18</code> instead. The envelope is not set if no note was played because<br />
the pitch index was <code>$02</code> which indicates a rest.<br />
<br />
Also for the pulse channels, after the above pseudocode, the vibrato and<br />
enveloping happens as long as there is no overriding sound effect. The envelope<br />
works by checking the envelope counter set previously and decrementing it. The<br />
counter value is halved and used to look up the envelope value in the LUT at<br />
<code>$9135</code>. These values are written directly to APU register <code>$4000</code> or <code>$4004</code><br />
depending on the channel.<br />
<br />
The bass channel has one special handling as well. The APU register <code>$4008</code> is<br />
set differently based on the current song id. For song <code>$10</code> (item get / level<br />
up fanfare) the register is set to <code>$60</code> but all other songs use <code>$1f</code>.<br />
<br />
The noise channel is not affect at all by the pitch. Any pitch value that is<br />
non zero will play a burst of noise.</div>Bentglasstubehttp://wiki.bindingforce.net/index.php?title=Music_Engine_Description&diff=366Music Engine Description2023-08-16T22:08:17Z<p>Bentglasstube: /* Title Music Engine */</p>
<hr />
<div>There are two separate music engines in Zelda 2. Both are in bank 6 (along<br />
with the song data). The music engine for the title screen resides at<br />
<code>$8000</code> and the engine for the rest of the game is at<br />
<code>$9000</code>. Each of these engines is called once per frame during the<br />
appropriate part of the game.<br />
<br />
Changes to the music engine should be very easy to make, as there is an<br />
abundance of free space in bank 6.<br />
<br />
== Title Music Engine ==<br />
<br />
The title music engine is different from the engine that plays music<br />
during the rest of the game. In particular, it has a wider range of<br />
notes that can be represented. If you want to look into the actual<br />
code, the title screen music engine main loop is at <code>$8000</code> (vesus<br />
<code>$9000</code> for the game music loop).<br />
<br />
The metadata for the songs is all the same as in the other areas,<br />
although the title music is actually broken up into several songs<br />
itself. These song boundaries control the timing of the title scroll.<br />
<br />
The following songs exist in the title song table:<br />
<br />
# Intro<br />
# Start<br />
# Build up<br />
# Main<br />
# Breakdown<br />
<br />
The start of song 2 triggers the title to scroll into view. The start<br />
of song 4 triggers a countdown until the story scroll begins. After<br />
song 5 finishes, the engine loops back to song 2.<br />
<br />
Within the note data, a special format is used. Rather than encoding<br />
the duration and pitch together in a single byte, the title music has<br />
"pitch" bytes and "duration" bytes. Any byte with the highest bit set<br />
(i.e. anything >= <code>$80</code>) is interpreted as a duration change, which<br />
sets the duration of all future notes. Anything else is a pitch value<br />
which indicates a note of the current duration should be played. The<br />
low nybble of duration values keys into a lookup table at bank 6 <code>$8084</code> <br />
and store the duration byte at <code>$07FF</code>. Values are as follows:<br />
<br />
* <code>$80</code> - 8 ticks (sixteenth note)<br />
* <code>$81</code> - 24 ticks (dotted eighth note)<br />
* <code>$82</code> - 16 ticks (eighth note)<br />
* <code>$83</code> - 32 ticks (quarter note)<br />
* <code>$84</code> - 48 ticks (dotted quarter note)<br />
* <code>$85</code> - 64 ticks (half note)<br />
* <code>$86</code> - 96 ticks (dotted half note)<br />
* <code>$87</code> - 128 ticks (whole note)<br />
* <code>$88</code> - 11 ticks (eighth note triplet, first two)<br />
* <code>$89</code> - 10 ticks (eighth note triplet, third)<br />
* <code>$8A</code> - 80 ticks (half note + eighth note)<br />
<br />
The pitch values are stored in a lookup table at bank 6 from <code>$808F</code> to <code>$810F</code>. Any value from <code>$00</code> to <code>$7F</code> represents an entry in this table.<br />
<code>$42</code> is A4 and every semitone away from that adds or subtracts 2 from<br />
the value. Thus, C5 (three semitones above A4) is <code>$48</code>. As in the game music engine, the value<br />
<code>$02</code> represents a rest. Unlike the game music engine, <code>$00</code> also represents a rest.<br />
<br />
-2- -3- -4- -5- -6- -7-<br />
C : $18 $30 $48 $60 $78<br />
C# : $1A $32 $4A $62 $7A<br />
D : $04 $1C $34 $4C $64<br />
Eb : $06 $1E $36 $4E $66<br />
E : $08 $20 $38 $50 $68<br />
F : $0A $22 $3A $52 $6A<br />
F# : $0C $24 $3C $54 $6C<br />
G : $0E $26 $3E $56 $6E<br />
G# : $10 $28 $40 $58 $70<br />
A : $12 $2A $42 $5A $72<br />
Bb : $14 $2C $44 $5C $74<br />
B : $16 $2E $46 $5E $76<br />
<br />
<br />
By way of an example, let's look at the main section of the vanilla<br />
title music. The title metadata starts at bank 6 <code>$84DA</code>:<br />
<br />
08 11 14 16 19 1E 1E 1E<br />
^ Main section<br />
<br />
The main section is the fourth song, starting at <code>$84DA + $16 = $84F0</code>:<br />
<br />
3F 3F 00<br />
<br />
This means there is a single phrase for the main section, which is<br />
repeated twice. The phrase data is at <code>$84DA + $3F = $8519</code>.<br />
<br />
00 3D 86 3A 1A 5F<br />
<br />
From this, we see the melody note data is located at <code>$863D</code>:<br />
<br />
83 Quarter notes<br />
02 Rest<br />
48 C5<br />
82 Eighth note<br />
46 B4<br />
83 Quarter notes<br />
3E G4<br />
34 D4<br />
84 Dotted quarter notes<br />
2E B3<br />
83 Quarter notes<br />
30 C4<br />
34 D4<br />
3A F4<br />
38 E4<br />
34 D4<br />
30 C4<br />
82 Eighth notes<br />
34 D4<br />
83 Quarter notes<br />
30 C4<br />
85 Half notes<br />
2E B3<br />
82 Quarter notes<br />
02 Rest<br />
00 End of Data<br />
<br />
== Main Music Engine ==<br />
<br />
=== Data Tables ===<br />
<br />
There are several data tables used by the music engine.<br />
<br />
==== Pulse Envelope ====<br />
<br />
This table is used to set the volume of the pulse channels over time. The index<br />
used starts at a certain value and decrements, so the table is in reverse order.<br />
The index is halved before use, so each value lasts two frames.<br />
<br />
{| class="wikitable"<br />
|+ Pulse Envelope <code>$9135</code><br />
|90||91||91||91||92||92||92||92<br />
|-<br />
|93||93||94||94||94||95||95||95<br />
|-<br />
|96||96||96||97||97||97||98||98<br />
|}<br />
<br />
==== Duration LUT ====<br />
<br />
This table is used to determine the duration of a note. The note data is stored<br />
with 5 bits of pitch information and 3 bits of duration, as such:<br />
<br />
D1 D0 P4 P3 P2 P1 P0 D2<br />
<br />
The Get Note Duration routine shifts things around to get the D bits into the<br />
three least significant bits and masks it before use. This value is then added<br />
to the tempo value in <code>$E5</code> which is always a multiple of 8 to index<br />
into the following table:<br />
<br />
{| class="wikitable"<br />
|+Duration LUT <code>$914D</code><br />
|'''00'''||04||0C||08||10||18||20||05||06<br />
|-<br />
|'''08'''||04||0F||09||12||1B||24||06||06<br />
|-<br />
|'''10'''||05||0F||0A||14||1E||28||07||06<br />
|-<br />
|'''18'''||06||12||0C||18||24||30||08||10<br />
|-<br />
|'''20'''||07||15||0E||1C||2A||38||13||12<br />
|-<br />
|'''28'''||07||15||0E||1C||2A||38||XX||XX<br />
|}<br />
<br />
The last two values in each row seem a bit strange, as they are not nice<br />
multiples of the first entry which is usually thought of as the length of an<br />
eighth note. They are usually used to make triplets which don't divide evenly by slightly shortening or lengthening the third triplet. The last row doesn't include these two values because they are nonsensical and actually belong to the next LUT anyway. That row is used for the credits music which presumably avoids those last two values.<br />
<br />
==== Pitch LUT ====<br />
<br />
This table is used to detemine the pitch of a note. The note data is stored as<br />
described above, and the fact that the least significant bit is masked out is<br />
advantageous since the pulse channels can use 11 bits of timer data, so each<br />
entry in this table is actually two bytes wide.<br />
<br />
Rather than show the raw bytes here, it's more useful to show the rough note<br />
that those values represent. If the raw values are interesting to you, check<br />
the ROM for them. It's worth noting that some of the higher notes are several<br />
cents off from the listed note.<br />
<br />
{| class="wikitable"<br />
|+Pitch LUT <code>$918F</code><br />
| || 00|| 02|| 04|| 06|| 08|| 0a|| 0c|| 0e<br />
|-<br />
|00|| C3||---|| E3|| G3||G#3|| A3||A#3|| B3<br />
|-<br />
|10|| C4||C#4|| D4||D#4|| E4|| F4||F#4|| G4<br />
|-<br />
|20||G#4|| A4||A#4|| B4|| C5||C#5|| D5||D#5<br />
|-<br />
|30|| E5|| F5||F#5|| G5|| A5||A#5|| B5||C#3<br />
|-<br />
|40|| D3||D#3|| F3||F#3||G#5|| C6||C#6|| D6<br />
|-<br />
|50||D#6|| E6|| F6||F#6|| G6||G#6|| A6||A#6<br />
|-<br />
|60|| B6|| C7||C#7|| D7||D#7|| E7|| F7||F#7<br />
|-<br />
|70|| G7||G#7|| A7||A#7|| B7|| C8<br />
|}<br />
<br />
Value <code>$02</code> represents a rest.<br />
<br />
Note that although the table goes through <code>$7A</code> values above<br />
<code>$3E</code> aren't usable due to the 5 bit limit for pitch data in<br />
the song data. However, the sound effects routines make use of these<br />
extra notes. For example, the sword beam effect alternates between<br />
playing C7 and F6.<br />
<br />
==== Noise Samples ====<br />
<br />
Several sound effects use the same routine to load "samples" for the noise<br />
channel to play. These values have the noise volume in the high nybble and the<br />
noise period in the low nybble.<br />
<br />
$90E8 - Sword slash<br />
$9123 - Enemy hurt<br />
$912C - Crumble block<br />
<br />
=== Variables ===<br />
<br />
This is just a dump of RAM addresses used by the music engine and a short<br />
description of what they are.<br />
<br />
$00E0 - Current phrase note data address (low byte)<br />
$00E1 - Current phrase note data address (high byte)<br />
$00E2 - Song offset, converted from song id to be an index instead of a bit field<br />
$00E3 - Current phrase index<br />
$00E4 - Drums loop start<br />
$00E5 - Tempo<br />
$00E6 - Pulse 1 low bits (used for vibrato effect)<br />
$00E7 - Pulse 2 low bits (used for vibrato effect)<br />
$00E8 - Pitch storage, temporary<br />
$00E9 - Play sound effect<br />
$00EA - Disable music<br />
$00EB - Request new song<br />
$00EC - Play sound effect<br />
$00ED - Play sound effect<br />
$00EE - Play sound effect<br />
$00EF - Play sound effect<br />
<br />
$0707 - Current world<br />
$075F - Queued song, loaded after screen transitions<br />
$07DA - Ganon Laugh sample<br />
$07DB - Song to resume after fanfare<br />
$07DF - ??? Likely sound effect flag for pulse 1 channel override<br />
<br />
$07E0 - ??? Likely sound effect flag for noise channel<br />
$07E2 - Pulse 2 envelope index<br />
$07E3 - Pulse 1 envelope index<br />
$07E4 - Drums current note duration<br />
$07E5 - Bass current note duration<br />
$07E6 - Harmony current note duration<br />
$07E7 - Melody current note duration<br />
$07E8 - Drums next note index<br />
$07E9 - Bass next note index<br />
$07EA - Harmony next note index<br />
$07EB - Melody next note index<br />
<br />
$07EC - Ganon Laugh counter<br />
$07ED - Sound FX counter (E9)<br />
$07EE - Sound FX counter (E9)<br />
$07F5 - Sound FX counter (ED)<br />
<br />
$07FA - Current SFX (E9)<br />
$07FB - Current song<br />
$07FD - Current SFX (ED)<br />
$07FE - ??? Likely sound effect flag for pulse 2 channel override<br />
$07FF - Current SFX (EF)<br />
<br />
=== Routines ===<br />
<br />
This is a non-exhaustive list of the routines in bank 6 involving the playing of<br />
music and sound effects. Each routine also lists its address so you can search<br />
in a disassembly for the actual code for that routine if these descriptions<br />
aren't clear.<br />
<br />
==== Main Music Loop <code>$9000</code> ====<br />
<br />
Checks that the music disable flag is off, then runs several SFX routines.<br />
After the SFX routines, the main music routine runs. After all this, various<br />
music related memory locations are cleared.<br />
<br />
==== Configure Pulse1 Channel <code>$9031</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4000</code> and <code>$4001</code><br />
respectively.<br />
<br />
==== Configure Pulse2 Channel <code>$9038</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4004</code> and <code>$4005</code><br />
respectively.<br />
<br />
==== Play Note Pulse1 <code>$9042</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 1 channel.<br />
<br />
==== Play Note <code>$9044</code> ====<br />
<br />
Called by the various play note routines. Takes a pitch index in register a and<br />
uses register x as a channel selector. For the pulse channels, this routine<br />
also saves the lower 8 bits of the APU timer register to <code>$E6</code> or <code>$E7</code> which<br />
are used for a vibrato effect.<br />
<br />
==== Play Note Pulse2 <code>$9067</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 2 channel.<br />
<br />
==== Play Note Triangle <code>$906B</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the triangle channel.<br />
<br />
==== Get Note Duration <code>$906F</code> ====<br />
<br />
Takes note data in register a and looks up the duration. The original note<br />
data is saved in register x and the result of the duration lookup is put in<br />
register a. The duration lookup is offset by the tempo stored in <code>$E5</code>.<br />
<br />
==== Vibrato Pulse1 <code>$9089</code> ====<br />
<br />
Applies a vibrato effect on the pulse 1 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato Pulse2 <code>$9097</code> ====<br />
<br />
Applies a vibrato effect on the pulse 2 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato <code>$909E</code> ====<br />
<br />
Takes the duration of the note remaining in register a, the low bits of the APU<br />
timer in register y, and the channel to use in register x. This is called by<br />
the other vibrato routines after setting x appropriately.<br />
<br />
Uses the <code>$04</code> bit of the duration to either add or subtract 2 from the low<br />
timer bits. Only the low bits are used because writing to the high bits resets<br />
the phase of the channel which can cause clicks. None of the notes from the<br />
pitch LUT are close enough to the boundary for the change to require the high<br />
bits to change anyway, so this works out fine.<br />
<br />
==== Play E9 SFX <code>$920B</code> ====<br />
<br />
Plays the sound effect requested in <code>$E9</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EF SFX <code>$92F4</code> ====<br />
<br />
Plays the sound effect requested in <code>$EF</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EE SFX <code>$9408</code> ====<br />
<br />
Plays the sound effect requested in <code>$EE</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Noise <code>$959D</code> ====<br />
<br />
Configures the APU noise registers to make a noise burst. Takes configuration<br />
for registers <code>$400F</code>, <code>$400E</code>, and <code>$400C</code> in registers y, x, and a.<br />
<br />
==== Crumble Bridge SFX <code>$956C</code> ====<br />
<br />
Starts playing the sound effect for a crumble bridge crumbling. This uses both<br />
the noise and the triangle channels so it sets flags to disable the music on<br />
those channels. Continues with SFX Noise Decay.<br />
<br />
==== SFX Noise Decay <code>$9587</code> ====<br />
<br />
Counts down the timer in <code>$07F5</code> and turns off the noise when it reaches 0.<br />
Also clears the flag for the ED sound effect in <code>$07FD</code>.<br />
<br />
==== Play ED SFX <code>$95A7</code> ====<br />
<br />
Plays the sound effect request in <code>$ED</code> or continues the sound effect saved in<br />
<code>$07FD</code>. Existing sound effects which are higher than the current sound effect<br />
will be ignored. If the same sound effect is requested that is already playing,<br />
it will restart the sound effect except for <code>$80</code> which gives priority to<br />
continuing. When the sound is continued instead of newly played, the decay<br />
routine will be called instead.<br />
<br />
; <code>$02</code><br />
: Crumble Bridge<br />
; <code>$04</code> and <code>$10</code><br />
: Crumble Block / Enemy Hurt<br />
; <code>$20</code> and <code>$80</code><br />
: Sword Strike<br />
; <code>$40</code><br />
: Very short noise burst, probably unused. Doesn't store the effect, and doesn't have an associated decay.<br />
<br />
==== Crumble Block / Enemy Hurt SFX <code>$95E6</code> ====<br />
<br />
Starts playing the sound of a block breaking or an enemy getting hurt.<br />
<br />
==== Crumble Block / Enemy Hurt SFX Decay <code>$95EE</code> ====<br />
<br />
Looks up noise register values based on the timer and the sound effect value.<br />
Crumble Block samples are at <code>$912C</code> while Enemy Hurt is at <code>$9123</code>. Continues<br />
on to Play Noise Samples.<br />
<br />
==== Play Noise Samples <code>$9612</code> ====<br />
<br />
Takes a sample value in register a. The low four bits of this are used to set<br />
the noise period via APU register <code>$400E</code>. The high four bits are used to set<br />
the noise volume via APU register <code>$400C</code>.<br />
<br />
Continues on the SFX Noise Decay process.<br />
<br />
==== Sword Strike SFX <code>$9604</code> ====<br />
<br />
Starts playing the sound of swinging your sword. This looks up samples based on<br />
the duration left at <code>$90E8</code> and plays them via Play Noise Samples.<br />
<br />
==== Play EC SFX <code>$990B</code> ====<br />
<br />
Plays the sound effect requested in <code>$EC</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Music <code>$9B18</code> ====<br />
<br />
Plays the music for the game.<br />
<br />
Runs Load Song if a new song is requested in <code>$EB</code>. Otherwise, runs Play Notes<br />
if the current song is set in <code>$07FB</code>. If neither of these is true, do nothing.<br />
<br />
==== Next Song <code>$9B24</code> ====<br />
<br />
Checks if the previous song should loop. If not, calls Mute All and returns.<br />
<br />
If the previous song was <code>$01</code> (the "intro" to the main theme), sets the next<br />
song to <code>$02</code> (the main theme loop).<br />
<br />
If the previous song was <code>$10</code> (the item get / level up fanfare), sets the<br />
current song from <code>$07DB</code>. Otherwise, leaves the current song the same as the<br />
previous song.<br />
<br />
Proceeds to Load Song.<br />
<br />
==== Mute All <code>$9B3B</code> ====<br />
<br />
Clears the current song at <code>$07FB</code> and sets the APU registers to mute the volume<br />
on both pulse channels, the triangle channel, and the noise channel.<br />
<br />
==== Load Song <code>$9B61</code> ====<br />
<br />
Takes a song id in register a and preps some variables for that song.<br />
<br />
If the song is <code>$10</code> (item get / level up fanfare) then it first saves the<br />
previous song to <code>$07FB</code> if it is less than <code>$10</code> so that the previous music<br />
will resume after the fanfare.<br />
<br />
Sets the phrase counter at <code>$E3</code> to 0 and the song offset at <code>$E2</code> based on the<br />
song id. Song ids are a bit field, and the song offset is the position of the<br />
lowest bit in the song id for indexing into the song table.<br />
<br />
Proceeds to Load Song Data.<br />
<br />
==== Load Song Data <code>$9B80</code> ====<br />
<br />
Loads the music variables based on the current world and current song offset.<br />
<br />
There are four blocks of code that are basically the same, for each of the four<br />
different music tables. Each one just uses a different position for the tables<br />
to load.<br />
<br />
Based on the current world in <code>$0707</code> it loads data from these offsets:<br />
<br />
<code>$00</code><br />
: Overworld music - <code>$9B87</code><br />
<code>$01</code> or <code>$02</code><br />
: Town music - <code>$9BC6</code><br />
<code>$03</code> or <code>$04</code><br />
: Palace music - <code>$9C05</code><br />
<code>$05</code> or higher<br />
: Great Palace music - <code>$9C42</code><br />
<br />
First, uses the song offset in <code>$E2</code> to index into the song table at the base<br />
offset given above.<br />
<br />
The phrase counter at <code>$E3</code> is added to that and used as in index again to<br />
retrieve the current phrase offset. If the current phrase offset is <code>$00</code> that<br />
means the song is over and the process goes back to the Next Song routine.<br />
<br />
Otherwise, the following structure is read at the base offset above + phrase<br />
offset just calculated.<br />
<br />
* <code>$E5</code> Tempo<br />
* <code>$E0</code> Note Data Low<br />
* <code>$E1</code> Note Data High<br />
* <code>$07E9</code> Bass Note Pointer<br />
* <code>$07EA</code> Harmony Note Pointer<br />
* <code>$07E8</code> Drum Note Pointer<br />
<br />
After this, the drum loop start point at <code>$E4</code> is also set to the same value as<br />
the drum note pointer. The melody note pointer at <code>$07EB</code> is set to <code>$00</code>, and<br />
all the durations (melody at <code>$07E7</code>, harmony at <code>$07E6</code>, bass at <code>$07E5</code>, and<br />
drums at <code>$07E4</code>) are set to <code>$01</code>.<br />
<br />
Proceeds to Play Notes.<br />
<br />
==== Play Notes ====<br />
<br />
This routine is broken into four major and similar sections: one each for<br />
melody, harmony, bass, and drums. The general process is as follows:<br />
<br />
decrement duration<br />
if duration == 0 {<br />
load next note<br />
increment note pointer<br />
set duration for note<br />
if no overriding sound effect {<br />
play note on appropriate channel<br />
}<br />
}<br />
<br />
Some channels have unique processing at different points in this. For example,<br />
the melody note data is null terminated, so if the loaded note in <code>$00</code> then the<br />
routine will jump to Load Song Data instead to go to the next phrase. If the<br />
drums channel gets a <code>$00</code> note it will reset the drums note pointer to the<br />
drums loop start and repeat the phrase. The bass and harmony channels don't<br />
have this looping behavior. This means that if the bass or harmony channels<br />
aren't long enough, the engine will happily just play whatever data comes next<br />
in the ROM.<br />
<br />
The melody is played on pulse 2 channel, the harmony on pulse 1 (which gets<br />
subverted by sound effects that need just one pulse channel), the bass on the<br />
triangle channel, and the drums on the noise channel.<br />
<br />
For the pulse channels, after the note is played, the envelope counter for that<br />
channel (<code>$07E2</code> for pulse 1, <code>$07E3</code> for pulse 2) is set. Normally the<br />
envelope is set to <code>$2F</code> but song <code>$40</code> (crystal fanfare and final boss music)<br />
sets it to <code>$18</code> instead. The envelope is not set if no note was played because<br />
the pitch index was <code>$02</code> which indicates a rest.<br />
<br />
Also for the pulse channels, after the above pseudocode, the vibrato and<br />
enveloping happens as long as there is no overriding sound effect. The envelope<br />
works by checking the envelope counter set previously and decrementing it. The<br />
counter value is halved and used to look up the envelope value in the LUT at<br />
<code>$9135</code>. These values are written directly to APU register <code>$4000</code> or <code>$4004</code><br />
depending on the channel.<br />
<br />
The bass channel has one special handling as well. The APU register <code>$4008</code> is<br />
set differently based on the current song id. For song <code>$10</code> (item get / level<br />
up fanfare) the register is set to <code>$60</code> but all other songs use <code>$1f</code>.<br />
<br />
The noise channel is not affect at all by the pitch. Any pitch value that is<br />
non zero will play a burst of noise.</div>Bentglasstubehttp://wiki.bindingforce.net/index.php?title=Music_Engine_Description&diff=365Music Engine Description2023-08-15T04:08:17Z<p>Bentglasstube: /* Title Music Engine */</p>
<hr />
<div>There are two separate music engines in Zelda 2. Both are in bank 6 (along<br />
with the song data). The music engine for the title screen resides at<br />
<code>$8000</code> and the engine for the rest of the game is at<br />
<code>$9000</code>. Each of these engines is called once per frame during the<br />
appropriate part of the game.<br />
<br />
Changes to the music engine should be very easy to make, as there is an<br />
abundance of free space in bank 6.<br />
<br />
== Title Music Engine ==<br />
<br />
The title music engine is different from the engine that plays music<br />
during the rest of the game. In particular, it has a wider range of<br />
notes that can be represented. If you want to look into the actual<br />
code, the title screen music engine main loop is at <code>$8000</code> (vesus<br />
<code>$9000</code> for the game music loop).<br />
<br />
The metadata for the songs is all the same as in the other areas,<br />
although the title music is actually broken up into several songs<br />
itself. These song boundaries control the timing of the title scroll.<br />
<br />
The following songs exist in the title song table:<br />
<br />
# Intro<br />
# Start<br />
# Build up<br />
# Main<br />
# Breakdown<br />
<br />
The start of song 2 triggers the title to scroll into view. The start<br />
of song 4 triggers a countdown until the story scroll begins. After<br />
song 5 finishes, the engine loops back to song 2.<br />
<br />
Within the note data, a special format is used. Rather than encoding<br />
the duration and pitch together in a single byte, the title music has<br />
"pitch" bytes and "duration" bytes. Any byte with the highest bit set<br />
(i.e. anything >= <code>$80</code>) is interpreted as a duration change, which<br />
sets the duration of all future notes. Anything else is a pitch value<br />
which indicates a note of the current duration should be played. The<br />
low nibble of duration values keys into a lookup table at bank 6 <code>$8084</code> <br />
and store the duration byte at <code>$07FF</code>. Value durations are as follows:<br />
<br />
* <code>$80</code> - 8 ticks (sixteenth note)<br />
* <code>$81</code> - 24 ticks (dotted eighth note)<br />
* <code>$82</code> - 16 ticks (eighth note)<br />
* <code>$83</code> - 32 ticks (quarter note)<br />
* <code>$84</code> - 48 ticks (dotted quarter note)<br />
* <code>$85</code> - 64 ticks (half note)<br />
* <code>$86</code> - 96 ticks (dotted half note)<br />
* <code>$87</code> - 128 ticks (whole note)<br />
* <code>$88</code> - 11 ticks (eighth note triplet, first two)<br />
* <code>$89</code> - 10 ticks (eighth note triplet, third)<br />
* <code>$8A</code> - 80 ticks (half note + eighth note)<br />
* <code>$8B</code> - 256 ticks (two whole notes)<br />
* <code>$8F</code> - 6 ticks (dotted 32nd note)<br />
<br />
Note: <code>$8C</code>, <code>$8D</code> and <code>$8E</code> are duplicates, so these could be used for<br />
custom durations if desired.<br />
<br />
The pitch values are much more straightforward. As far as I can tell,<br />
<code>$42</code> is A4 and every semitone away from that adds or subtracts 2 from<br />
the value. Thus, C5 (three semitones above A4) is <code>$48</code>. As in the game music engine, the value<br />
<code>$02</code> represents a rest.<br />
<br />
-2- -3- -4- -5- -6- -7-<br />
C : $18 $30 $48 $60 $78<br />
C# : $1A $32 $4A $62 $7A<br />
D : $04 $1C $34 $4C $64<br />
Eb : $06 $1E $36 $4E $66<br />
E : $08 $20 $38 $50 $68<br />
F : $0A $22 $3A $52 $6A<br />
F# : $0C $24 $3C $54 $6C<br />
G : $0E $26 $3E $56 $6E<br />
G# : $10 $28 $40 $58 $70<br />
A : $12 $2A $42 $5A $72<br />
Bb : $14 $2C $44 $5C $74<br />
B : $16 $2E $46 $5E $76<br />
<br />
<br />
By way of an example, let's look at the main section of the vanilla<br />
title music. The title metadata starts at bank 6 <code>$84DA</code>:<br />
<br />
08 11 14 16 19 1E 1E 1E<br />
^ Main section<br />
<br />
The main section is the fourth song, starting at <code>$84DA + $16 = $84F0</code>:<br />
<br />
3F 3F 00<br />
<br />
This means there is a single phrase for the main section, which is<br />
repeated twice. The phrase data is at <code>$84DA + $3F = $8519</code>.<br />
<br />
00 3D 86 3A 1A 5F<br />
<br />
From this, we see the melody note data is located at <code>$863D</code>:<br />
<br />
83 Quarter notes<br />
02 Rest<br />
48 C5<br />
82 Eighth note<br />
46 B4<br />
83 Quarter notes<br />
3E G4<br />
34 D4<br />
84 Dotted quarter notes<br />
2E B3<br />
83 Quarter notes<br />
30 C4<br />
34 D4<br />
3A F4<br />
38 E4<br />
34 D4<br />
30 C4<br />
82 Eighth notes<br />
34 D4<br />
83 Quarter notes<br />
30 C4<br />
85 Half notes<br />
2E B3<br />
82 Quarter notes<br />
02 Rest<br />
00 End of Data<br />
<br />
== Main Music Engine ==<br />
<br />
=== Data Tables ===<br />
<br />
There are several data tables used by the music engine.<br />
<br />
==== Pulse Envelope ====<br />
<br />
This table is used to set the volume of the pulse channels over time. The index<br />
used starts at a certain value and decrements, so the table is in reverse order.<br />
The index is halved before use, so each value lasts two frames.<br />
<br />
{| class="wikitable"<br />
|+ Pulse Envelope <code>$9135</code><br />
|90||91||91||91||92||92||92||92<br />
|-<br />
|93||93||94||94||94||95||95||95<br />
|-<br />
|96||96||96||97||97||97||98||98<br />
|}<br />
<br />
==== Duration LUT ====<br />
<br />
This table is used to determine the duration of a note. The note data is stored<br />
with 5 bits of pitch information and 3 bits of duration, as such:<br />
<br />
D1 D0 P4 P3 P2 P1 P0 D2<br />
<br />
The Get Note Duration routine shifts things around to get the D bits into the<br />
three least significant bits and masks it before use. This value is then added<br />
to the tempo value in <code>$E5</code> which is always a multiple of 8 to index<br />
into the following table:<br />
<br />
{| class="wikitable"<br />
|+Duration LUT <code>$914D</code><br />
|'''00'''||04||0C||08||10||18||20||05||06<br />
|-<br />
|'''08'''||04||0F||09||12||1B||24||06||06<br />
|-<br />
|'''10'''||05||0F||0A||14||1E||28||07||06<br />
|-<br />
|'''18'''||06||12||0C||18||24||30||08||10<br />
|-<br />
|'''20'''||07||15||0E||1C||2A||38||13||12<br />
|-<br />
|'''28'''||07||15||0E||1C||2A||38||XX||XX<br />
|}<br />
<br />
The last two values in each row seem a bit strange, as they are not nice<br />
multiples of the first entry which is usually thought of as the length of an<br />
eighth note. They are usually used to make triplets which don't divide evenly by slightly shortening or lengthening the third triplet. The last row doesn't include these two values because they are nonsensical and actually belong to the next LUT anyway. That row is used for the credits music which presumably avoids those last two values.<br />
<br />
==== Pitch LUT ====<br />
<br />
This table is used to detemine the pitch of a note. The note data is stored as<br />
described above, and the fact that the least significant bit is masked out is<br />
advantageous since the pulse channels can use 11 bits of timer data, so each<br />
entry in this table is actually two bytes wide.<br />
<br />
Rather than show the raw bytes here, it's more useful to show the rough note<br />
that those values represent. If the raw values are interesting to you, check<br />
the ROM for them. It's worth noting that some of the higher notes are several<br />
cents off from the listed note.<br />
<br />
{| class="wikitable"<br />
|+Pitch LUT <code>$918F</code><br />
| || 00|| 02|| 04|| 06|| 08|| 0a|| 0c|| 0e<br />
|-<br />
|00|| C3||---|| E3|| G3||G#3|| A3||A#3|| B3<br />
|-<br />
|10|| C4||C#4|| D4||D#4|| E4|| F4||F#4|| G4<br />
|-<br />
|20||G#4|| A4||A#4|| B4|| C5||C#5|| D5||D#5<br />
|-<br />
|30|| E5|| F5||F#5|| G5|| A5||A#5|| B5||C#3<br />
|-<br />
|40|| D3||D#3|| F3||F#3||G#5|| C6||C#6|| D6<br />
|-<br />
|50||D#6|| E6|| F6||F#6|| G6||G#6|| A6||A#6<br />
|-<br />
|60|| B6|| C7||C#7|| D7||D#7|| E7|| F7||F#7<br />
|-<br />
|70|| G7||G#7|| A7||A#7|| B7|| C8<br />
|}<br />
<br />
Value <code>$02</code> represents a rest.<br />
<br />
Note that although the table goes through <code>$7A</code> values above<br />
<code>$3E</code> aren't usable due to the 5 bit limit for pitch data in<br />
the song data. However, the sound effects routines make use of these<br />
extra notes. For example, the sword beam effect alternates between<br />
playing C7 and F6.<br />
<br />
==== Noise Samples ====<br />
<br />
Several sound effects use the same routine to load "samples" for the noise<br />
channel to play. These values have the noise volume in the high nybble and the<br />
noise period in the low nybble.<br />
<br />
$90E8 - Sword slash<br />
$9123 - Enemy hurt<br />
$912C - Crumble block<br />
<br />
=== Variables ===<br />
<br />
This is just a dump of RAM addresses used by the music engine and a short<br />
description of what they are.<br />
<br />
$00E0 - Current phrase note data address (low byte)<br />
$00E1 - Current phrase note data address (high byte)<br />
$00E2 - Song offset, converted from song id to be an index instead of a bit field<br />
$00E3 - Current phrase index<br />
$00E4 - Drums loop start<br />
$00E5 - Tempo<br />
$00E6 - Pulse 1 low bits (used for vibrato effect)<br />
$00E7 - Pulse 2 low bits (used for vibrato effect)<br />
$00E8 - Pitch storage, temporary<br />
$00E9 - Play sound effect<br />
$00EA - Disable music<br />
$00EB - Request new song<br />
$00EC - Play sound effect<br />
$00ED - Play sound effect<br />
$00EE - Play sound effect<br />
$00EF - Play sound effect<br />
<br />
$0707 - Current world<br />
$075F - Queued song, loaded after screen transitions<br />
$07DA - Ganon Laugh sample<br />
$07DB - Song to resume after fanfare<br />
$07DF - ??? Likely sound effect flag for pulse 1 channel override<br />
<br />
$07E0 - ??? Likely sound effect flag for noise channel<br />
$07E2 - Pulse 2 envelope index<br />
$07E3 - Pulse 1 envelope index<br />
$07E4 - Drums current note duration<br />
$07E5 - Bass current note duration<br />
$07E6 - Harmony current note duration<br />
$07E7 - Melody current note duration<br />
$07E8 - Drums next note index<br />
$07E9 - Bass next note index<br />
$07EA - Harmony next note index<br />
$07EB - Melody next note index<br />
<br />
$07EC - Ganon Laugh counter<br />
$07ED - Sound FX counter (E9)<br />
$07EE - Sound FX counter (E9)<br />
$07F5 - Sound FX counter (ED)<br />
<br />
$07FA - Current SFX (E9)<br />
$07FB - Current song<br />
$07FD - Current SFX (ED)<br />
$07FE - ??? Likely sound effect flag for pulse 2 channel override<br />
$07FF - Current SFX (EF)<br />
<br />
=== Routines ===<br />
<br />
This is a non-exhaustive list of the routines in bank 6 involving the playing of<br />
music and sound effects. Each routine also lists its address so you can search<br />
in a disassembly for the actual code for that routine if these descriptions<br />
aren't clear.<br />
<br />
==== Main Music Loop <code>$9000</code> ====<br />
<br />
Checks that the music disable flag is off, then runs several SFX routines.<br />
After the SFX routines, the main music routine runs. After all this, various<br />
music related memory locations are cleared.<br />
<br />
==== Configure Pulse1 Channel <code>$9031</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4000</code> and <code>$4001</code><br />
respectively.<br />
<br />
==== Configure Pulse2 Channel <code>$9038</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4004</code> and <code>$4005</code><br />
respectively.<br />
<br />
==== Play Note Pulse1 <code>$9042</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 1 channel.<br />
<br />
==== Play Note <code>$9044</code> ====<br />
<br />
Called by the various play note routines. Takes a pitch index in register a and<br />
uses register x as a channel selector. For the pulse channels, this routine<br />
also saves the lower 8 bits of the APU timer register to <code>$E6</code> or <code>$E7</code> which<br />
are used for a vibrato effect.<br />
<br />
==== Play Note Pulse2 <code>$9067</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 2 channel.<br />
<br />
==== Play Note Triangle <code>$906B</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the triangle channel.<br />
<br />
==== Get Note Duration <code>$906F</code> ====<br />
<br />
Takes note data in register a and looks up the duration. The original note<br />
data is saved in register x and the result of the duration lookup is put in<br />
register a. The duration lookup is offset by the tempo stored in <code>$E5</code>.<br />
<br />
==== Vibrato Pulse1 <code>$9089</code> ====<br />
<br />
Applies a vibrato effect on the pulse 1 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato Pulse2 <code>$9097</code> ====<br />
<br />
Applies a vibrato effect on the pulse 2 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato <code>$909E</code> ====<br />
<br />
Takes the duration of the note remaining in register a, the low bits of the APU<br />
timer in register y, and the channel to use in register x. This is called by<br />
the other vibrato routines after setting x appropriately.<br />
<br />
Uses the <code>$04</code> bit of the duration to either add or subtract 2 from the low<br />
timer bits. Only the low bits are used because writing to the high bits resets<br />
the phase of the channel which can cause clicks. None of the notes from the<br />
pitch LUT are close enough to the boundary for the change to require the high<br />
bits to change anyway, so this works out fine.<br />
<br />
==== Play E9 SFX <code>$920B</code> ====<br />
<br />
Plays the sound effect requested in <code>$E9</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EF SFX <code>$92F4</code> ====<br />
<br />
Plays the sound effect requested in <code>$EF</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EE SFX <code>$9408</code> ====<br />
<br />
Plays the sound effect requested in <code>$EE</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Noise <code>$959D</code> ====<br />
<br />
Configures the APU noise registers to make a noise burst. Takes configuration<br />
for registers <code>$400F</code>, <code>$400E</code>, and <code>$400C</code> in registers y, x, and a.<br />
<br />
==== Crumble Bridge SFX <code>$956C</code> ====<br />
<br />
Starts playing the sound effect for a crumble bridge crumbling. This uses both<br />
the noise and the triangle channels so it sets flags to disable the music on<br />
those channels. Continues with SFX Noise Decay.<br />
<br />
==== SFX Noise Decay <code>$9587</code> ====<br />
<br />
Counts down the timer in <code>$07F5</code> and turns off the noise when it reaches 0.<br />
Also clears the flag for the ED sound effect in <code>$07FD</code>.<br />
<br />
==== Play ED SFX <code>$95A7</code> ====<br />
<br />
Plays the sound effect request in <code>$ED</code> or continues the sound effect saved in<br />
<code>$07FD</code>. Existing sound effects which are higher than the current sound effect<br />
will be ignored. If the same sound effect is requested that is already playing,<br />
it will restart the sound effect except for <code>$80</code> which gives priority to<br />
continuing. When the sound is continued instead of newly played, the decay<br />
routine will be called instead.<br />
<br />
; <code>$02</code><br />
: Crumble Bridge<br />
; <code>$04</code> and <code>$10</code><br />
: Crumble Block / Enemy Hurt<br />
; <code>$20</code> and <code>$80</code><br />
: Sword Strike<br />
; <code>$40</code><br />
: Very short noise burst, probably unused. Doesn't store the effect, and doesn't have an associated decay.<br />
<br />
==== Crumble Block / Enemy Hurt SFX <code>$95E6</code> ====<br />
<br />
Starts playing the sound of a block breaking or an enemy getting hurt.<br />
<br />
==== Crumble Block / Enemy Hurt SFX Decay <code>$95EE</code> ====<br />
<br />
Looks up noise register values based on the timer and the sound effect value.<br />
Crumble Block samples are at <code>$912C</code> while Enemy Hurt is at <code>$9123</code>. Continues<br />
on to Play Noise Samples.<br />
<br />
==== Play Noise Samples <code>$9612</code> ====<br />
<br />
Takes a sample value in register a. The low four bits of this are used to set<br />
the noise period via APU register <code>$400E</code>. The high four bits are used to set<br />
the noise volume via APU register <code>$400C</code>.<br />
<br />
Continues on the SFX Noise Decay process.<br />
<br />
==== Sword Strike SFX <code>$9604</code> ====<br />
<br />
Starts playing the sound of swinging your sword. This looks up samples based on<br />
the duration left at <code>$90E8</code> and plays them via Play Noise Samples.<br />
<br />
==== Play EC SFX <code>$990B</code> ====<br />
<br />
Plays the sound effect requested in <code>$EC</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Music <code>$9B18</code> ====<br />
<br />
Plays the music for the game.<br />
<br />
Runs Load Song if a new song is requested in <code>$EB</code>. Otherwise, runs Play Notes<br />
if the current song is set in <code>$07FB</code>. If neither of these is true, do nothing.<br />
<br />
==== Next Song <code>$9B24</code> ====<br />
<br />
Checks if the previous song should loop. If not, calls Mute All and returns.<br />
<br />
If the previous song was <code>$01</code> (the "intro" to the main theme), sets the next<br />
song to <code>$02</code> (the main theme loop).<br />
<br />
If the previous song was <code>$10</code> (the item get / level up fanfare), sets the<br />
current song from <code>$07DB</code>. Otherwise, leaves the current song the same as the<br />
previous song.<br />
<br />
Proceeds to Load Song.<br />
<br />
==== Mute All <code>$9B3B</code> ====<br />
<br />
Clears the current song at <code>$07FB</code> and sets the APU registers to mute the volume<br />
on both pulse channels, the triangle channel, and the noise channel.<br />
<br />
==== Load Song <code>$9B61</code> ====<br />
<br />
Takes a song id in register a and preps some variables for that song.<br />
<br />
If the song is <code>$10</code> (item get / level up fanfare) then it first saves the<br />
previous song to <code>$07FB</code> if it is less than <code>$10</code> so that the previous music<br />
will resume after the fanfare.<br />
<br />
Sets the phrase counter at <code>$E3</code> to 0 and the song offset at <code>$E2</code> based on the<br />
song id. Song ids are a bit field, and the song offset is the position of the<br />
lowest bit in the song id for indexing into the song table.<br />
<br />
Proceeds to Load Song Data.<br />
<br />
==== Load Song Data <code>$9B80</code> ====<br />
<br />
Loads the music variables based on the current world and current song offset.<br />
<br />
There are four blocks of code that are basically the same, for each of the four<br />
different music tables. Each one just uses a different position for the tables<br />
to load.<br />
<br />
Based on the current world in <code>$0707</code> it loads data from these offsets:<br />
<br />
<code>$00</code><br />
: Overworld music - <code>$9B87</code><br />
<code>$01</code> or <code>$02</code><br />
: Town music - <code>$9BC6</code><br />
<code>$03</code> or <code>$04</code><br />
: Palace music - <code>$9C05</code><br />
<code>$05</code> or higher<br />
: Great Palace music - <code>$9C42</code><br />
<br />
First, uses the song offset in <code>$E2</code> to index into the song table at the base<br />
offset given above.<br />
<br />
The phrase counter at <code>$E3</code> is added to that and used as in index again to<br />
retrieve the current phrase offset. If the current phrase offset is <code>$00</code> that<br />
means the song is over and the process goes back to the Next Song routine.<br />
<br />
Otherwise, the following structure is read at the base offset above + phrase<br />
offset just calculated.<br />
<br />
* <code>$E5</code> Tempo<br />
* <code>$E0</code> Note Data Low<br />
* <code>$E1</code> Note Data High<br />
* <code>$07E9</code> Bass Note Pointer<br />
* <code>$07EA</code> Harmony Note Pointer<br />
* <code>$07E8</code> Drum Note Pointer<br />
<br />
After this, the drum loop start point at <code>$E4</code> is also set to the same value as<br />
the drum note pointer. The melody note pointer at <code>$07EB</code> is set to <code>$00</code>, and<br />
all the durations (melody at <code>$07E7</code>, harmony at <code>$07E6</code>, bass at <code>$07E5</code>, and<br />
drums at <code>$07E4</code>) are set to <code>$01</code>.<br />
<br />
Proceeds to Play Notes.<br />
<br />
==== Play Notes ====<br />
<br />
This routine is broken into four major and similar sections: one each for<br />
melody, harmony, bass, and drums. The general process is as follows:<br />
<br />
decrement duration<br />
if duration == 0 {<br />
load next note<br />
increment note pointer<br />
set duration for note<br />
if no overriding sound effect {<br />
play note on appropriate channel<br />
}<br />
}<br />
<br />
Some channels have unique processing at different points in this. For example,<br />
the melody note data is null terminated, so if the loaded note in <code>$00</code> then the<br />
routine will jump to Load Song Data instead to go to the next phrase. If the<br />
drums channel gets a <code>$00</code> note it will reset the drums note pointer to the<br />
drums loop start and repeat the phrase. The bass and harmony channels don't<br />
have this looping behavior. This means that if the bass or harmony channels<br />
aren't long enough, the engine will happily just play whatever data comes next<br />
in the ROM.<br />
<br />
The melody is played on pulse 2 channel, the harmony on pulse 1 (which gets<br />
subverted by sound effects that need just one pulse channel), the bass on the<br />
triangle channel, and the drums on the noise channel.<br />
<br />
For the pulse channels, after the note is played, the envelope counter for that<br />
channel (<code>$07E2</code> for pulse 1, <code>$07E3</code> for pulse 2) is set. Normally the<br />
envelope is set to <code>$2F</code> but song <code>$40</code> (crystal fanfare and final boss music)<br />
sets it to <code>$18</code> instead. The envelope is not set if no note was played because<br />
the pitch index was <code>$02</code> which indicates a rest.<br />
<br />
Also for the pulse channels, after the above pseudocode, the vibrato and<br />
enveloping happens as long as there is no overriding sound effect. The envelope<br />
works by checking the envelope counter set previously and decrementing it. The<br />
counter value is halved and used to look up the envelope value in the LUT at<br />
<code>$9135</code>. These values are written directly to APU register <code>$4000</code> or <code>$4004</code><br />
depending on the channel.<br />
<br />
The bass channel has one special handling as well. The APU register <code>$4008</code> is<br />
set differently based on the current song id. For song <code>$10</code> (item get / level<br />
up fanfare) the register is set to <code>$60</code> but all other songs use <code>$1f</code>.<br />
<br />
The noise channel is not affect at all by the pitch. Any pitch value that is<br />
non zero will play a burst of noise.</div>Bentglasstubehttp://wiki.bindingforce.net/index.php?title=Music_Engine_Description&diff=364Music Engine Description2023-08-15T04:05:21Z<p>Bentglasstube: /* Title Music Engine */</p>
<hr />
<div>There are two separate music engines in Zelda 2. Both are in bank 6 (along<br />
with the song data). The music engine for the title screen resides at<br />
<code>$8000</code> and the engine for the rest of the game is at<br />
<code>$9000</code>. Each of these engines is called once per frame during the<br />
appropriate part of the game.<br />
<br />
Changes to the music engine should be very easy to make, as there is an<br />
abundance of free space in bank 6.<br />
<br />
== Title Music Engine ==<br />
<br />
The title music engine is different from the engine that plays music<br />
during the rest of the game. In particular, it has a wider range of<br />
notes that can be represented. If you want to look into the actual<br />
code, the title screen music engine main loop is at <code>$8000</code> (vesus<br />
<code>$9000</code> for the game music loop).<br />
<br />
The metadata for the songs is all the same as in the other areas,<br />
although the title music is actually broken up into several songs<br />
itself. These song boundaries control the timing of the title scroll.<br />
<br />
The following songs exist in the title song table:<br />
<br />
# Intro<br />
# Start<br />
# Build up<br />
# Main<br />
# Breakdown<br />
<br />
The start of song 2 triggers the title to scroll into view. The start<br />
of song 4 triggers a countdown until the story scroll begins. After<br />
song 5 finishes, the engine loops back to song 2.<br />
<br />
Within the note data, a special format is used. Rather than encoding<br />
the duration and pitch together in a single byte, the title music has<br />
"pitch" bytes and "duration" bytes. Any byte with the highest bit set<br />
(i.e. anything >= <code>$80</code>) is interpreted as a duration change, which<br />
sets the duration of all future notes. Anything else is a pitch value<br />
which indicates a note of the current duration should be played. The<br />
low nibble of duration values keys into a lookup table at bank 6 <code>$8084</code> <br />
and store the duration byte at <code>$07FF</code>. Value durations are as follows:<br />
<br />
* <code>$80</code> - 8 ticks (sixteenth note)<br />
* <code>$81</code> - 24 ticks (dotted eighth note)<br />
* <code>$82</code> - 16 ticks (eighth note)<br />
* <code>$83</code> - 32 ticks (quarter note)<br />
* <code>$84</code> - 48 ticks (dotted quarter note)<br />
* <code>$85</code> - 64 ticks (half note)<br />
* <code>$86</code> - 96 ticks (dotted half note)<br />
* <code>$87</code> - 128 ticks (whole note)<br />
* <code>$88</code> - 11 ticks (eighth note triplet, first two)<br />
* <code>$89</code> - 10 ticks (eighth note triplet, third)<br />
* <code>$8A</code> - 80 ticks (half note + eighth note)<br />
* <code>$8B</code> - 256 ticks (two whole notes)<br />
* <code>$8F</code> - 6 ticks (dotted 32nd note)<br />
<br />
Note: <code>$8C</code>, <code>$8D</code> and <code>$8E</code> are duplicates, so these could be used for<br />
custom durations if desired.<br />
<br />
The pitch values are much more straightforward. As far as I can tell,<br />
<code>$42</code> is A4 and every semitone away from that adds or subtracts 2 from<br />
the value. Thus, C5 (three semitones above A4) is <code>$48</code>. As in the game music engine, the value<br />
<code>$02</code> represents a rest.<br />
<br />
-2- -3- -4- -5- -6- -7-<br />
C : $18 $30 $48 $60 $78<br />
C# : $1A $32 $4A $62 $7A<br />
D : $04 $1C $34 $4C $64<br />
Eb : $06 $1E $36 $4E $66<br />
E : $08 $20 $38 $50 $68<br />
F : $0A $22 $3A $52 $6A<br />
F# : $0C $24 $3C $54 $6C<br />
G : $0E $26 $3E $56 $6E<br />
G# : $10 $28 $40 $58 $70<br />
A : $12 $2A $42 $5A $72<br />
Bb : $14 $2C $44 $5C $74<br />
B : $16 $2E $46 $5E $76<br />
<br />
<br />
By way of an example, let's look at the main section of the vanilla<br />
title music. The title metadata starts at bank 6 <code>$84DA</code>:<br />
<br />
08 11 14 16 19 1E 1E 1E<br />
^ Main section<br />
<br />
The main section is the fourth song, starting at <code>$84DA + $16 = $84F0</code>:<br />
<br />
3F 3F 00<br />
<br />
This means there is a single phrase for the main section, which is<br />
repeated twice. The phrase data is at <code>$84DA + $3F = $8519</code>.<br />
<br />
00 3D 86 3A 1A 5F<br />
<br />
From this, we see the melody note data is located at <code>$863D</code>:<br />
<br />
83 Quarter notes<br />
02 Rest<br />
48 Ab4<br />
82 Eighth note<br />
46 G4<br />
83 Quarter notes<br />
3E Eb4<br />
34 Bb3<br />
84 Dotted quarter notes<br />
2E G3<br />
83 Quarter notes<br />
30 Ab3<br />
34 Bb3<br />
3A Db4<br />
38 C4<br />
34 Bb3<br />
30 Ab3<br />
82 Eighth notes<br />
34 Bb3<br />
83 Quarter notes<br />
30 Ab3<br />
85 Half notes<br />
2E G3<br />
82 Quarter notes<br />
02 Rest<br />
00 End of Data<br />
<br />
== Main Music Engine ==<br />
<br />
=== Data Tables ===<br />
<br />
There are several data tables used by the music engine.<br />
<br />
==== Pulse Envelope ====<br />
<br />
This table is used to set the volume of the pulse channels over time. The index<br />
used starts at a certain value and decrements, so the table is in reverse order.<br />
The index is halved before use, so each value lasts two frames.<br />
<br />
{| class="wikitable"<br />
|+ Pulse Envelope <code>$9135</code><br />
|90||91||91||91||92||92||92||92<br />
|-<br />
|93||93||94||94||94||95||95||95<br />
|-<br />
|96||96||96||97||97||97||98||98<br />
|}<br />
<br />
==== Duration LUT ====<br />
<br />
This table is used to determine the duration of a note. The note data is stored<br />
with 5 bits of pitch information and 3 bits of duration, as such:<br />
<br />
D1 D0 P4 P3 P2 P1 P0 D2<br />
<br />
The Get Note Duration routine shifts things around to get the D bits into the<br />
three least significant bits and masks it before use. This value is then added<br />
to the tempo value in <code>$E5</code> which is always a multiple of 8 to index<br />
into the following table:<br />
<br />
{| class="wikitable"<br />
|+Duration LUT <code>$914D</code><br />
|'''00'''||04||0C||08||10||18||20||05||06<br />
|-<br />
|'''08'''||04||0F||09||12||1B||24||06||06<br />
|-<br />
|'''10'''||05||0F||0A||14||1E||28||07||06<br />
|-<br />
|'''18'''||06||12||0C||18||24||30||08||10<br />
|-<br />
|'''20'''||07||15||0E||1C||2A||38||13||12<br />
|-<br />
|'''28'''||07||15||0E||1C||2A||38||XX||XX<br />
|}<br />
<br />
The last two values in each row seem a bit strange, as they are not nice<br />
multiples of the first entry which is usually thought of as the length of an<br />
eighth note. They are usually used to make triplets which don't divide evenly by slightly shortening or lengthening the third triplet. The last row doesn't include these two values because they are nonsensical and actually belong to the next LUT anyway. That row is used for the credits music which presumably avoids those last two values.<br />
<br />
==== Pitch LUT ====<br />
<br />
This table is used to detemine the pitch of a note. The note data is stored as<br />
described above, and the fact that the least significant bit is masked out is<br />
advantageous since the pulse channels can use 11 bits of timer data, so each<br />
entry in this table is actually two bytes wide.<br />
<br />
Rather than show the raw bytes here, it's more useful to show the rough note<br />
that those values represent. If the raw values are interesting to you, check<br />
the ROM for them. It's worth noting that some of the higher notes are several<br />
cents off from the listed note.<br />
<br />
{| class="wikitable"<br />
|+Pitch LUT <code>$918F</code><br />
| || 00|| 02|| 04|| 06|| 08|| 0a|| 0c|| 0e<br />
|-<br />
|00|| C3||---|| E3|| G3||G#3|| A3||A#3|| B3<br />
|-<br />
|10|| C4||C#4|| D4||D#4|| E4|| F4||F#4|| G4<br />
|-<br />
|20||G#4|| A4||A#4|| B4|| C5||C#5|| D5||D#5<br />
|-<br />
|30|| E5|| F5||F#5|| G5|| A5||A#5|| B5||C#3<br />
|-<br />
|40|| D3||D#3|| F3||F#3||G#5|| C6||C#6|| D6<br />
|-<br />
|50||D#6|| E6|| F6||F#6|| G6||G#6|| A6||A#6<br />
|-<br />
|60|| B6|| C7||C#7|| D7||D#7|| E7|| F7||F#7<br />
|-<br />
|70|| G7||G#7|| A7||A#7|| B7|| C8<br />
|}<br />
<br />
Value <code>$02</code> represents a rest.<br />
<br />
Note that although the table goes through <code>$7A</code> values above<br />
<code>$3E</code> aren't usable due to the 5 bit limit for pitch data in<br />
the song data. However, the sound effects routines make use of these<br />
extra notes. For example, the sword beam effect alternates between<br />
playing C7 and F6.<br />
<br />
==== Noise Samples ====<br />
<br />
Several sound effects use the same routine to load "samples" for the noise<br />
channel to play. These values have the noise volume in the high nybble and the<br />
noise period in the low nybble.<br />
<br />
$90E8 - Sword slash<br />
$9123 - Enemy hurt<br />
$912C - Crumble block<br />
<br />
=== Variables ===<br />
<br />
This is just a dump of RAM addresses used by the music engine and a short<br />
description of what they are.<br />
<br />
$00E0 - Current phrase note data address (low byte)<br />
$00E1 - Current phrase note data address (high byte)<br />
$00E2 - Song offset, converted from song id to be an index instead of a bit field<br />
$00E3 - Current phrase index<br />
$00E4 - Drums loop start<br />
$00E5 - Tempo<br />
$00E6 - Pulse 1 low bits (used for vibrato effect)<br />
$00E7 - Pulse 2 low bits (used for vibrato effect)<br />
$00E8 - Pitch storage, temporary<br />
$00E9 - Play sound effect<br />
$00EA - Disable music<br />
$00EB - Request new song<br />
$00EC - Play sound effect<br />
$00ED - Play sound effect<br />
$00EE - Play sound effect<br />
$00EF - Play sound effect<br />
<br />
$0707 - Current world<br />
$075F - Queued song, loaded after screen transitions<br />
$07DA - Ganon Laugh sample<br />
$07DB - Song to resume after fanfare<br />
$07DF - ??? Likely sound effect flag for pulse 1 channel override<br />
<br />
$07E0 - ??? Likely sound effect flag for noise channel<br />
$07E2 - Pulse 2 envelope index<br />
$07E3 - Pulse 1 envelope index<br />
$07E4 - Drums current note duration<br />
$07E5 - Bass current note duration<br />
$07E6 - Harmony current note duration<br />
$07E7 - Melody current note duration<br />
$07E8 - Drums next note index<br />
$07E9 - Bass next note index<br />
$07EA - Harmony next note index<br />
$07EB - Melody next note index<br />
<br />
$07EC - Ganon Laugh counter<br />
$07ED - Sound FX counter (E9)<br />
$07EE - Sound FX counter (E9)<br />
$07F5 - Sound FX counter (ED)<br />
<br />
$07FA - Current SFX (E9)<br />
$07FB - Current song<br />
$07FD - Current SFX (ED)<br />
$07FE - ??? Likely sound effect flag for pulse 2 channel override<br />
$07FF - Current SFX (EF)<br />
<br />
=== Routines ===<br />
<br />
This is a non-exhaustive list of the routines in bank 6 involving the playing of<br />
music and sound effects. Each routine also lists its address so you can search<br />
in a disassembly for the actual code for that routine if these descriptions<br />
aren't clear.<br />
<br />
==== Main Music Loop <code>$9000</code> ====<br />
<br />
Checks that the music disable flag is off, then runs several SFX routines.<br />
After the SFX routines, the main music routine runs. After all this, various<br />
music related memory locations are cleared.<br />
<br />
==== Configure Pulse1 Channel <code>$9031</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4000</code> and <code>$4001</code><br />
respectively.<br />
<br />
==== Configure Pulse2 Channel <code>$9038</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4004</code> and <code>$4005</code><br />
respectively.<br />
<br />
==== Play Note Pulse1 <code>$9042</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 1 channel.<br />
<br />
==== Play Note <code>$9044</code> ====<br />
<br />
Called by the various play note routines. Takes a pitch index in register a and<br />
uses register x as a channel selector. For the pulse channels, this routine<br />
also saves the lower 8 bits of the APU timer register to <code>$E6</code> or <code>$E7</code> which<br />
are used for a vibrato effect.<br />
<br />
==== Play Note Pulse2 <code>$9067</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 2 channel.<br />
<br />
==== Play Note Triangle <code>$906B</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the triangle channel.<br />
<br />
==== Get Note Duration <code>$906F</code> ====<br />
<br />
Takes note data in register a and looks up the duration. The original note<br />
data is saved in register x and the result of the duration lookup is put in<br />
register a. The duration lookup is offset by the tempo stored in <code>$E5</code>.<br />
<br />
==== Vibrato Pulse1 <code>$9089</code> ====<br />
<br />
Applies a vibrato effect on the pulse 1 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato Pulse2 <code>$9097</code> ====<br />
<br />
Applies a vibrato effect on the pulse 2 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato <code>$909E</code> ====<br />
<br />
Takes the duration of the note remaining in register a, the low bits of the APU<br />
timer in register y, and the channel to use in register x. This is called by<br />
the other vibrato routines after setting x appropriately.<br />
<br />
Uses the <code>$04</code> bit of the duration to either add or subtract 2 from the low<br />
timer bits. Only the low bits are used because writing to the high bits resets<br />
the phase of the channel which can cause clicks. None of the notes from the<br />
pitch LUT are close enough to the boundary for the change to require the high<br />
bits to change anyway, so this works out fine.<br />
<br />
==== Play E9 SFX <code>$920B</code> ====<br />
<br />
Plays the sound effect requested in <code>$E9</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EF SFX <code>$92F4</code> ====<br />
<br />
Plays the sound effect requested in <code>$EF</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EE SFX <code>$9408</code> ====<br />
<br />
Plays the sound effect requested in <code>$EE</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Noise <code>$959D</code> ====<br />
<br />
Configures the APU noise registers to make a noise burst. Takes configuration<br />
for registers <code>$400F</code>, <code>$400E</code>, and <code>$400C</code> in registers y, x, and a.<br />
<br />
==== Crumble Bridge SFX <code>$956C</code> ====<br />
<br />
Starts playing the sound effect for a crumble bridge crumbling. This uses both<br />
the noise and the triangle channels so it sets flags to disable the music on<br />
those channels. Continues with SFX Noise Decay.<br />
<br />
==== SFX Noise Decay <code>$9587</code> ====<br />
<br />
Counts down the timer in <code>$07F5</code> and turns off the noise when it reaches 0.<br />
Also clears the flag for the ED sound effect in <code>$07FD</code>.<br />
<br />
==== Play ED SFX <code>$95A7</code> ====<br />
<br />
Plays the sound effect request in <code>$ED</code> or continues the sound effect saved in<br />
<code>$07FD</code>. Existing sound effects which are higher than the current sound effect<br />
will be ignored. If the same sound effect is requested that is already playing,<br />
it will restart the sound effect except for <code>$80</code> which gives priority to<br />
continuing. When the sound is continued instead of newly played, the decay<br />
routine will be called instead.<br />
<br />
; <code>$02</code><br />
: Crumble Bridge<br />
; <code>$04</code> and <code>$10</code><br />
: Crumble Block / Enemy Hurt<br />
; <code>$20</code> and <code>$80</code><br />
: Sword Strike<br />
; <code>$40</code><br />
: Very short noise burst, probably unused. Doesn't store the effect, and doesn't have an associated decay.<br />
<br />
==== Crumble Block / Enemy Hurt SFX <code>$95E6</code> ====<br />
<br />
Starts playing the sound of a block breaking or an enemy getting hurt.<br />
<br />
==== Crumble Block / Enemy Hurt SFX Decay <code>$95EE</code> ====<br />
<br />
Looks up noise register values based on the timer and the sound effect value.<br />
Crumble Block samples are at <code>$912C</code> while Enemy Hurt is at <code>$9123</code>. Continues<br />
on to Play Noise Samples.<br />
<br />
==== Play Noise Samples <code>$9612</code> ====<br />
<br />
Takes a sample value in register a. The low four bits of this are used to set<br />
the noise period via APU register <code>$400E</code>. The high four bits are used to set<br />
the noise volume via APU register <code>$400C</code>.<br />
<br />
Continues on the SFX Noise Decay process.<br />
<br />
==== Sword Strike SFX <code>$9604</code> ====<br />
<br />
Starts playing the sound of swinging your sword. This looks up samples based on<br />
the duration left at <code>$90E8</code> and plays them via Play Noise Samples.<br />
<br />
==== Play EC SFX <code>$990B</code> ====<br />
<br />
Plays the sound effect requested in <code>$EC</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Music <code>$9B18</code> ====<br />
<br />
Plays the music for the game.<br />
<br />
Runs Load Song if a new song is requested in <code>$EB</code>. Otherwise, runs Play Notes<br />
if the current song is set in <code>$07FB</code>. If neither of these is true, do nothing.<br />
<br />
==== Next Song <code>$9B24</code> ====<br />
<br />
Checks if the previous song should loop. If not, calls Mute All and returns.<br />
<br />
If the previous song was <code>$01</code> (the "intro" to the main theme), sets the next<br />
song to <code>$02</code> (the main theme loop).<br />
<br />
If the previous song was <code>$10</code> (the item get / level up fanfare), sets the<br />
current song from <code>$07DB</code>. Otherwise, leaves the current song the same as the<br />
previous song.<br />
<br />
Proceeds to Load Song.<br />
<br />
==== Mute All <code>$9B3B</code> ====<br />
<br />
Clears the current song at <code>$07FB</code> and sets the APU registers to mute the volume<br />
on both pulse channels, the triangle channel, and the noise channel.<br />
<br />
==== Load Song <code>$9B61</code> ====<br />
<br />
Takes a song id in register a and preps some variables for that song.<br />
<br />
If the song is <code>$10</code> (item get / level up fanfare) then it first saves the<br />
previous song to <code>$07FB</code> if it is less than <code>$10</code> so that the previous music<br />
will resume after the fanfare.<br />
<br />
Sets the phrase counter at <code>$E3</code> to 0 and the song offset at <code>$E2</code> based on the<br />
song id. Song ids are a bit field, and the song offset is the position of the<br />
lowest bit in the song id for indexing into the song table.<br />
<br />
Proceeds to Load Song Data.<br />
<br />
==== Load Song Data <code>$9B80</code> ====<br />
<br />
Loads the music variables based on the current world and current song offset.<br />
<br />
There are four blocks of code that are basically the same, for each of the four<br />
different music tables. Each one just uses a different position for the tables<br />
to load.<br />
<br />
Based on the current world in <code>$0707</code> it loads data from these offsets:<br />
<br />
<code>$00</code><br />
: Overworld music - <code>$9B87</code><br />
<code>$01</code> or <code>$02</code><br />
: Town music - <code>$9BC6</code><br />
<code>$03</code> or <code>$04</code><br />
: Palace music - <code>$9C05</code><br />
<code>$05</code> or higher<br />
: Great Palace music - <code>$9C42</code><br />
<br />
First, uses the song offset in <code>$E2</code> to index into the song table at the base<br />
offset given above.<br />
<br />
The phrase counter at <code>$E3</code> is added to that and used as in index again to<br />
retrieve the current phrase offset. If the current phrase offset is <code>$00</code> that<br />
means the song is over and the process goes back to the Next Song routine.<br />
<br />
Otherwise, the following structure is read at the base offset above + phrase<br />
offset just calculated.<br />
<br />
* <code>$E5</code> Tempo<br />
* <code>$E0</code> Note Data Low<br />
* <code>$E1</code> Note Data High<br />
* <code>$07E9</code> Bass Note Pointer<br />
* <code>$07EA</code> Harmony Note Pointer<br />
* <code>$07E8</code> Drum Note Pointer<br />
<br />
After this, the drum loop start point at <code>$E4</code> is also set to the same value as<br />
the drum note pointer. The melody note pointer at <code>$07EB</code> is set to <code>$00</code>, and<br />
all the durations (melody at <code>$07E7</code>, harmony at <code>$07E6</code>, bass at <code>$07E5</code>, and<br />
drums at <code>$07E4</code>) are set to <code>$01</code>.<br />
<br />
Proceeds to Play Notes.<br />
<br />
==== Play Notes ====<br />
<br />
This routine is broken into four major and similar sections: one each for<br />
melody, harmony, bass, and drums. The general process is as follows:<br />
<br />
decrement duration<br />
if duration == 0 {<br />
load next note<br />
increment note pointer<br />
set duration for note<br />
if no overriding sound effect {<br />
play note on appropriate channel<br />
}<br />
}<br />
<br />
Some channels have unique processing at different points in this. For example,<br />
the melody note data is null terminated, so if the loaded note in <code>$00</code> then the<br />
routine will jump to Load Song Data instead to go to the next phrase. If the<br />
drums channel gets a <code>$00</code> note it will reset the drums note pointer to the<br />
drums loop start and repeat the phrase. The bass and harmony channels don't<br />
have this looping behavior. This means that if the bass or harmony channels<br />
aren't long enough, the engine will happily just play whatever data comes next<br />
in the ROM.<br />
<br />
The melody is played on pulse 2 channel, the harmony on pulse 1 (which gets<br />
subverted by sound effects that need just one pulse channel), the bass on the<br />
triangle channel, and the drums on the noise channel.<br />
<br />
For the pulse channels, after the note is played, the envelope counter for that<br />
channel (<code>$07E2</code> for pulse 1, <code>$07E3</code> for pulse 2) is set. Normally the<br />
envelope is set to <code>$2F</code> but song <code>$40</code> (crystal fanfare and final boss music)<br />
sets it to <code>$18</code> instead. The envelope is not set if no note was played because<br />
the pitch index was <code>$02</code> which indicates a rest.<br />
<br />
Also for the pulse channels, after the above pseudocode, the vibrato and<br />
enveloping happens as long as there is no overriding sound effect. The envelope<br />
works by checking the envelope counter set previously and decrementing it. The<br />
counter value is halved and used to look up the envelope value in the LUT at<br />
<code>$9135</code>. These values are written directly to APU register <code>$4000</code> or <code>$4004</code><br />
depending on the channel.<br />
<br />
The bass channel has one special handling as well. The APU register <code>$4008</code> is<br />
set differently based on the current song id. For song <code>$10</code> (item get / level<br />
up fanfare) the register is set to <code>$60</code> but all other songs use <code>$1f</code>.<br />
<br />
The noise channel is not affect at all by the pitch. Any pitch value that is<br />
non zero will play a burst of noise.</div>Bentglasstubehttp://wiki.bindingforce.net/index.php?title=Music_Engine_Description&diff=363Music Engine Description2023-08-13T04:59:43Z<p>Bentglasstube: /* Pitch LUT */</p>
<hr />
<div>There are two separate music engines in Zelda 2. Both are in bank 6 (along<br />
with the song data). The music engine for the title screen resides at<br />
<code>$8000</code> and the engine for the rest of the game is at<br />
<code>$9000</code>. Each of these engines is called once per frame during the<br />
appropriate part of the game.<br />
<br />
Changes to the music engine should be very easy to make, as there is an<br />
abundance of free space in bank 6.<br />
<br />
== Title Music Engine ==<br />
<br />
The title music engine is different from the engine that plays music<br />
during the rest of the game. In particular, it has a wider range of<br />
notes that can be represented. If you want to look into the actual<br />
code, the title screen music engine main loop is at <code>$8000</code> (vesus<br />
<code>$9000</code> for the game music loop).<br />
<br />
The metadata for the songs is all the same as in the other areas,<br />
although the title music is actually broken up into several songs<br />
itself. These song boundaries control the timing of the title scroll.<br />
<br />
The following songs exist in the title song table:<br />
<br />
# Intro<br />
# Start<br />
# Build up<br />
# Main<br />
# Breakdown<br />
<br />
The start of song 2 triggers the title to scroll into view. The start<br />
of song 4 triggers a countdown until the story scroll begins. After<br />
song 5 finishes, the engine loops back to song 2.<br />
<br />
Within the note data, a special format is used. Rather than encoding<br />
the duration and pitch together in a single byte, the title music has<br />
"pitch" bytes and "duration" bytes. Any byte with the highest bit set<br />
(i.e. anything >= <code>$80</code>) is interpreted as a duration change, which<br />
sets the duration of all future notes. Anything else is a pitch value<br />
which indicates a note of the current duration should be played. The<br />
low nibble of duration values keys into a lookup table at bank 6 <code>$8084</code> <br />
and store the duration byte at <code>$07FF</code>. Value durations are as follows:<br />
<br />
* <code>$80</code> - 8 ticks (sixteenth note)<br />
* <code>$81</code> - 24 ticks (dotted eighth note)<br />
* <code>$82</code> - 16 ticks (eighth note)<br />
* <code>$83</code> - 32 ticks (quarter note)<br />
* <code>$84</code> - 48 ticks (dotted quarter note)<br />
* <code>$85</code> - 64 ticks (half note)<br />
* <code>$86</code> - 96 ticks (dotted half note)<br />
* <code>$87</code> - 128 ticks (whole note)<br />
* <code>$88</code> - 11 ticks (eighth note triplet, first two)<br />
* <code>$89</code> - 10 ticks (eighth note triplet, third)<br />
* <code>$8A</code> - 80 ticks (half note + eighth note)<br />
* <code>$8B</code> - 256 ticks (two whole notes)<br />
* <code>$8F</code> - 6 ticks (dotted 32nd note)<br />
<br />
Note: <code>$8C</code>, <code>$8D</code> and <code>$8E</code> are duplicates, so these could be used for<br />
custom durations if desired.<br />
<br />
The pitch values are much more straightforward. As far as I can tell,<br />
<code>$4C</code> is A4 and every semitone away from that adds or subtracts 2 from<br />
the value. Thus, C5 (three semitones above A4) is <code>$52</code>. As in the game music engine, the value<br />
<code>$02</code> represents a rest.<br />
<br />
-2- -3- -4- -5- -6- -7-<br />
A : $12 $2A $42 $5A $72<br />
Bb : $14 $2C $44 $5C $74<br />
B : $16 $2E $46 $5E $76<br />
C : $18 $30 $48 $60 $78<br />
C# : $1A $32 $4A $62 $7A<br />
D : $04 $1C $34 $4C $64<br />
Eb : $06 $1E $36 $4E $66<br />
E : $08 $20 $38 $50 $68<br />
F : $0A $22 $3A $52 $6A<br />
F# : $0C $24 $3C $54 $6C<br />
G : $0E $26 $3E $56 $6E<br />
G# : $10 $28 $40 $58 $70<br />
<br />
By way of an example, let's look at the main section of the vanilla<br />
title music. The title metadata starts at bank 6 <code>$84DA</code>:<br />
<br />
08 11 14 16 19 1E 1E 1E<br />
^ Main section<br />
<br />
The main section is the fourth song, starting at <code>$84DA + $16 = $84F0</code>:<br />
<br />
3F 3F 00<br />
<br />
This means there is a single phrase for the main section, which is<br />
repeated twice. The phrase data is at <code>$84DA + $3F = $8519</code>.<br />
<br />
00 3D 86 3A 1A 5F<br />
<br />
From this, we see the melody note data is located at <code>$863D</code>:<br />
<br />
83 Quarter notes<br />
02 Rest<br />
48 Ab4<br />
82 Eighth note<br />
46 G4<br />
83 Quarter notes<br />
3E Eb4<br />
34 Bb3<br />
84 Dotted quarter notes<br />
2E G3<br />
83 Quarter notes<br />
30 Ab3<br />
34 Bb3<br />
3A Db4<br />
38 C4<br />
34 Bb3<br />
30 Ab3<br />
82 Eighth notes<br />
34 Bb3<br />
83 Quarter notes<br />
30 Ab3<br />
85 Half notes<br />
2E G3<br />
82 Quarter notes<br />
02 Rest<br />
00 End of Data<br />
<br />
== Main Music Engine ==<br />
<br />
=== Data Tables ===<br />
<br />
There are several data tables used by the music engine.<br />
<br />
==== Pulse Envelope ====<br />
<br />
This table is used to set the volume of the pulse channels over time. The index<br />
used starts at a certain value and decrements, so the table is in reverse order.<br />
The index is halved before use, so each value lasts two frames.<br />
<br />
{| class="wikitable"<br />
|+ Pulse Envelope <code>$9135</code><br />
|90||91||91||91||92||92||92||92<br />
|-<br />
|93||93||94||94||94||95||95||95<br />
|-<br />
|96||96||96||97||97||97||98||98<br />
|}<br />
<br />
==== Duration LUT ====<br />
<br />
This table is used to determine the duration of a note. The note data is stored<br />
with 5 bits of pitch information and 3 bits of duration, as such:<br />
<br />
D1 D0 P4 P3 P2 P1 P0 D2<br />
<br />
The Get Note Duration routine shifts things around to get the D bits into the<br />
three least significant bits and masks it before use. This value is then added<br />
to the tempo value in <code>$E5</code> which is always a multiple of 8 to index<br />
into the following table:<br />
<br />
{| class="wikitable"<br />
|+Duration LUT <code>$914D</code><br />
|'''00'''||04||0C||08||10||18||20||05||06<br />
|-<br />
|'''08'''||04||0F||09||12||1B||24||06||06<br />
|-<br />
|'''10'''||05||0F||0A||14||1E||28||07||06<br />
|-<br />
|'''18'''||06||12||0C||18||24||30||08||10<br />
|-<br />
|'''20'''||07||15||0E||1C||2A||38||13||12<br />
|-<br />
|'''28'''||07||15||0E||1C||2A||38||XX||XX<br />
|}<br />
<br />
The last two values in each row seem a bit strange, as they are not nice<br />
multiples of the first entry which is usually thought of as the length of an<br />
eighth note. They are usually used to make triplets which don't divide evenly by slightly shortening or lengthening the third triplet. The last row doesn't include these two values because they are nonsensical and actually belong to the next LUT anyway. That row is used for the credits music which presumably avoids those last two values.<br />
<br />
==== Pitch LUT ====<br />
<br />
This table is used to detemine the pitch of a note. The note data is stored as<br />
described above, and the fact that the least significant bit is masked out is<br />
advantageous since the pulse channels can use 11 bits of timer data, so each<br />
entry in this table is actually two bytes wide.<br />
<br />
Rather than show the raw bytes here, it's more useful to show the rough note<br />
that those values represent. If the raw values are interesting to you, check<br />
the ROM for them. It's worth noting that some of the higher notes are several<br />
cents off from the listed note.<br />
<br />
{| class="wikitable"<br />
|+Pitch LUT <code>$918F</code><br />
| || 00|| 02|| 04|| 06|| 08|| 0a|| 0c|| 0e<br />
|-<br />
|00|| C3||---|| E3|| G3||G#3|| A3||A#3|| B3<br />
|-<br />
|10|| C4||C#4|| D4||D#4|| E4|| F4||F#4|| G4<br />
|-<br />
|20||G#4|| A4||A#4|| B4|| C5||C#5|| D5||D#5<br />
|-<br />
|30|| E5|| F5||F#5|| G5|| A5||A#5|| B5||C#3<br />
|-<br />
|40|| D3||D#3|| F3||F#3||G#5|| C6||C#6|| D6<br />
|-<br />
|50||D#6|| E6|| F6||F#6|| G6||G#6|| A6||A#6<br />
|-<br />
|60|| B6|| C7||C#7|| D7||D#7|| E7|| F7||F#7<br />
|-<br />
|70|| G7||G#7|| A7||A#7|| B7|| C8<br />
|}<br />
<br />
Value <code>$02</code> represents a rest.<br />
<br />
Note that although the table goes through <code>$7A</code> values above<br />
<code>$3E</code> aren't usable due to the 5 bit limit for pitch data in<br />
the song data. However, the sound effects routines make use of these<br />
extra notes. For example, the sword beam effect alternates between<br />
playing C7 and F6.<br />
<br />
==== Noise Samples ====<br />
<br />
Several sound effects use the same routine to load "samples" for the noise<br />
channel to play. These values have the noise volume in the high nybble and the<br />
noise period in the low nybble.<br />
<br />
$90E8 - Sword slash<br />
$9123 - Enemy hurt<br />
$912C - Crumble block<br />
<br />
=== Variables ===<br />
<br />
This is just a dump of RAM addresses used by the music engine and a short<br />
description of what they are.<br />
<br />
$00E0 - Current phrase note data address (low byte)<br />
$00E1 - Current phrase note data address (high byte)<br />
$00E2 - Song offset, converted from song id to be an index instead of a bit field<br />
$00E3 - Current phrase index<br />
$00E4 - Drums loop start<br />
$00E5 - Tempo<br />
$00E6 - Pulse 1 low bits (used for vibrato effect)<br />
$00E7 - Pulse 2 low bits (used for vibrato effect)<br />
$00E8 - Pitch storage, temporary<br />
$00E9 - Play sound effect<br />
$00EA - Disable music<br />
$00EB - Request new song<br />
$00EC - Play sound effect<br />
$00ED - Play sound effect<br />
$00EE - Play sound effect<br />
$00EF - Play sound effect<br />
<br />
$0707 - Current world<br />
$075F - Queued song, loaded after screen transitions<br />
$07DA - Ganon Laugh sample<br />
$07DB - Song to resume after fanfare<br />
$07DF - ??? Likely sound effect flag for pulse 1 channel override<br />
<br />
$07E0 - ??? Likely sound effect flag for noise channel<br />
$07E2 - Pulse 2 envelope index<br />
$07E3 - Pulse 1 envelope index<br />
$07E4 - Drums current note duration<br />
$07E5 - Bass current note duration<br />
$07E6 - Harmony current note duration<br />
$07E7 - Melody current note duration<br />
$07E8 - Drums next note index<br />
$07E9 - Bass next note index<br />
$07EA - Harmony next note index<br />
$07EB - Melody next note index<br />
<br />
$07EC - Ganon Laugh counter<br />
$07ED - Sound FX counter (E9)<br />
$07EE - Sound FX counter (E9)<br />
$07F5 - Sound FX counter (ED)<br />
<br />
$07FA - Current SFX (E9)<br />
$07FB - Current song<br />
$07FD - Current SFX (ED)<br />
$07FE - ??? Likely sound effect flag for pulse 2 channel override<br />
$07FF - Current SFX (EF)<br />
<br />
=== Routines ===<br />
<br />
This is a non-exhaustive list of the routines in bank 6 involving the playing of<br />
music and sound effects. Each routine also lists its address so you can search<br />
in a disassembly for the actual code for that routine if these descriptions<br />
aren't clear.<br />
<br />
==== Main Music Loop <code>$9000</code> ====<br />
<br />
Checks that the music disable flag is off, then runs several SFX routines.<br />
After the SFX routines, the main music routine runs. After all this, various<br />
music related memory locations are cleared.<br />
<br />
==== Configure Pulse1 Channel <code>$9031</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4000</code> and <code>$4001</code><br />
respectively.<br />
<br />
==== Configure Pulse2 Channel <code>$9038</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4004</code> and <code>$4005</code><br />
respectively.<br />
<br />
==== Play Note Pulse1 <code>$9042</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 1 channel.<br />
<br />
==== Play Note <code>$9044</code> ====<br />
<br />
Called by the various play note routines. Takes a pitch index in register a and<br />
uses register x as a channel selector. For the pulse channels, this routine<br />
also saves the lower 8 bits of the APU timer register to <code>$E6</code> or <code>$E7</code> which<br />
are used for a vibrato effect.<br />
<br />
==== Play Note Pulse2 <code>$9067</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 2 channel.<br />
<br />
==== Play Note Triangle <code>$906B</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the triangle channel.<br />
<br />
==== Get Note Duration <code>$906F</code> ====<br />
<br />
Takes note data in register a and looks up the duration. The original note<br />
data is saved in register x and the result of the duration lookup is put in<br />
register a. The duration lookup is offset by the tempo stored in <code>$E5</code>.<br />
<br />
==== Vibrato Pulse1 <code>$9089</code> ====<br />
<br />
Applies a vibrato effect on the pulse 1 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato Pulse2 <code>$9097</code> ====<br />
<br />
Applies a vibrato effect on the pulse 2 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato <code>$909E</code> ====<br />
<br />
Takes the duration of the note remaining in register a, the low bits of the APU<br />
timer in register y, and the channel to use in register x. This is called by<br />
the other vibrato routines after setting x appropriately.<br />
<br />
Uses the <code>$04</code> bit of the duration to either add or subtract 2 from the low<br />
timer bits. Only the low bits are used because writing to the high bits resets<br />
the phase of the channel which can cause clicks. None of the notes from the<br />
pitch LUT are close enough to the boundary for the change to require the high<br />
bits to change anyway, so this works out fine.<br />
<br />
==== Play E9 SFX <code>$920B</code> ====<br />
<br />
Plays the sound effect requested in <code>$E9</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EF SFX <code>$92F4</code> ====<br />
<br />
Plays the sound effect requested in <code>$EF</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EE SFX <code>$9408</code> ====<br />
<br />
Plays the sound effect requested in <code>$EE</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Noise <code>$959D</code> ====<br />
<br />
Configures the APU noise registers to make a noise burst. Takes configuration<br />
for registers <code>$400F</code>, <code>$400E</code>, and <code>$400C</code> in registers y, x, and a.<br />
<br />
==== Crumble Bridge SFX <code>$956C</code> ====<br />
<br />
Starts playing the sound effect for a crumble bridge crumbling. This uses both<br />
the noise and the triangle channels so it sets flags to disable the music on<br />
those channels. Continues with SFX Noise Decay.<br />
<br />
==== SFX Noise Decay <code>$9587</code> ====<br />
<br />
Counts down the timer in <code>$07F5</code> and turns off the noise when it reaches 0.<br />
Also clears the flag for the ED sound effect in <code>$07FD</code>.<br />
<br />
==== Play ED SFX <code>$95A7</code> ====<br />
<br />
Plays the sound effect request in <code>$ED</code> or continues the sound effect saved in<br />
<code>$07FD</code>. Existing sound effects which are higher than the current sound effect<br />
will be ignored. If the same sound effect is requested that is already playing,<br />
it will restart the sound effect except for <code>$80</code> which gives priority to<br />
continuing. When the sound is continued instead of newly played, the decay<br />
routine will be called instead.<br />
<br />
; <code>$02</code><br />
: Crumble Bridge<br />
; <code>$04</code> and <code>$10</code><br />
: Crumble Block / Enemy Hurt<br />
; <code>$20</code> and <code>$80</code><br />
: Sword Strike<br />
; <code>$40</code><br />
: Very short noise burst, probably unused. Doesn't store the effect, and doesn't have an associated decay.<br />
<br />
==== Crumble Block / Enemy Hurt SFX <code>$95E6</code> ====<br />
<br />
Starts playing the sound of a block breaking or an enemy getting hurt.<br />
<br />
==== Crumble Block / Enemy Hurt SFX Decay <code>$95EE</code> ====<br />
<br />
Looks up noise register values based on the timer and the sound effect value.<br />
Crumble Block samples are at <code>$912C</code> while Enemy Hurt is at <code>$9123</code>. Continues<br />
on to Play Noise Samples.<br />
<br />
==== Play Noise Samples <code>$9612</code> ====<br />
<br />
Takes a sample value in register a. The low four bits of this are used to set<br />
the noise period via APU register <code>$400E</code>. The high four bits are used to set<br />
the noise volume via APU register <code>$400C</code>.<br />
<br />
Continues on the SFX Noise Decay process.<br />
<br />
==== Sword Strike SFX <code>$9604</code> ====<br />
<br />
Starts playing the sound of swinging your sword. This looks up samples based on<br />
the duration left at <code>$90E8</code> and plays them via Play Noise Samples.<br />
<br />
==== Play EC SFX <code>$990B</code> ====<br />
<br />
Plays the sound effect requested in <code>$EC</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Music <code>$9B18</code> ====<br />
<br />
Plays the music for the game.<br />
<br />
Runs Load Song if a new song is requested in <code>$EB</code>. Otherwise, runs Play Notes<br />
if the current song is set in <code>$07FB</code>. If neither of these is true, do nothing.<br />
<br />
==== Next Song <code>$9B24</code> ====<br />
<br />
Checks if the previous song should loop. If not, calls Mute All and returns.<br />
<br />
If the previous song was <code>$01</code> (the "intro" to the main theme), sets the next<br />
song to <code>$02</code> (the main theme loop).<br />
<br />
If the previous song was <code>$10</code> (the item get / level up fanfare), sets the<br />
current song from <code>$07DB</code>. Otherwise, leaves the current song the same as the<br />
previous song.<br />
<br />
Proceeds to Load Song.<br />
<br />
==== Mute All <code>$9B3B</code> ====<br />
<br />
Clears the current song at <code>$07FB</code> and sets the APU registers to mute the volume<br />
on both pulse channels, the triangle channel, and the noise channel.<br />
<br />
==== Load Song <code>$9B61</code> ====<br />
<br />
Takes a song id in register a and preps some variables for that song.<br />
<br />
If the song is <code>$10</code> (item get / level up fanfare) then it first saves the<br />
previous song to <code>$07FB</code> if it is less than <code>$10</code> so that the previous music<br />
will resume after the fanfare.<br />
<br />
Sets the phrase counter at <code>$E3</code> to 0 and the song offset at <code>$E2</code> based on the<br />
song id. Song ids are a bit field, and the song offset is the position of the<br />
lowest bit in the song id for indexing into the song table.<br />
<br />
Proceeds to Load Song Data.<br />
<br />
==== Load Song Data <code>$9B80</code> ====<br />
<br />
Loads the music variables based on the current world and current song offset.<br />
<br />
There are four blocks of code that are basically the same, for each of the four<br />
different music tables. Each one just uses a different position for the tables<br />
to load.<br />
<br />
Based on the current world in <code>$0707</code> it loads data from these offsets:<br />
<br />
<code>$00</code><br />
: Overworld music - <code>$9B87</code><br />
<code>$01</code> or <code>$02</code><br />
: Town music - <code>$9BC6</code><br />
<code>$03</code> or <code>$04</code><br />
: Palace music - <code>$9C05</code><br />
<code>$05</code> or higher<br />
: Great Palace music - <code>$9C42</code><br />
<br />
First, uses the song offset in <code>$E2</code> to index into the song table at the base<br />
offset given above.<br />
<br />
The phrase counter at <code>$E3</code> is added to that and used as in index again to<br />
retrieve the current phrase offset. If the current phrase offset is <code>$00</code> that<br />
means the song is over and the process goes back to the Next Song routine.<br />
<br />
Otherwise, the following structure is read at the base offset above + phrase<br />
offset just calculated.<br />
<br />
* <code>$E5</code> Tempo<br />
* <code>$E0</code> Note Data Low<br />
* <code>$E1</code> Note Data High<br />
* <code>$07E9</code> Bass Note Pointer<br />
* <code>$07EA</code> Harmony Note Pointer<br />
* <code>$07E8</code> Drum Note Pointer<br />
<br />
After this, the drum loop start point at <code>$E4</code> is also set to the same value as<br />
the drum note pointer. The melody note pointer at <code>$07EB</code> is set to <code>$00</code>, and<br />
all the durations (melody at <code>$07E7</code>, harmony at <code>$07E6</code>, bass at <code>$07E5</code>, and<br />
drums at <code>$07E4</code>) are set to <code>$01</code>.<br />
<br />
Proceeds to Play Notes.<br />
<br />
==== Play Notes ====<br />
<br />
This routine is broken into four major and similar sections: one each for<br />
melody, harmony, bass, and drums. The general process is as follows:<br />
<br />
decrement duration<br />
if duration == 0 {<br />
load next note<br />
increment note pointer<br />
set duration for note<br />
if no overriding sound effect {<br />
play note on appropriate channel<br />
}<br />
}<br />
<br />
Some channels have unique processing at different points in this. For example,<br />
the melody note data is null terminated, so if the loaded note in <code>$00</code> then the<br />
routine will jump to Load Song Data instead to go to the next phrase. If the<br />
drums channel gets a <code>$00</code> note it will reset the drums note pointer to the<br />
drums loop start and repeat the phrase. The bass and harmony channels don't<br />
have this looping behavior. This means that if the bass or harmony channels<br />
aren't long enough, the engine will happily just play whatever data comes next<br />
in the ROM.<br />
<br />
The melody is played on pulse 2 channel, the harmony on pulse 1 (which gets<br />
subverted by sound effects that need just one pulse channel), the bass on the<br />
triangle channel, and the drums on the noise channel.<br />
<br />
For the pulse channels, after the note is played, the envelope counter for that<br />
channel (<code>$07E2</code> for pulse 1, <code>$07E3</code> for pulse 2) is set. Normally the<br />
envelope is set to <code>$2F</code> but song <code>$40</code> (crystal fanfare and final boss music)<br />
sets it to <code>$18</code> instead. The envelope is not set if no note was played because<br />
the pitch index was <code>$02</code> which indicates a rest.<br />
<br />
Also for the pulse channels, after the above pseudocode, the vibrato and<br />
enveloping happens as long as there is no overriding sound effect. The envelope<br />
works by checking the envelope counter set previously and decrementing it. The<br />
counter value is halved and used to look up the envelope value in the LUT at<br />
<code>$9135</code>. These values are written directly to APU register <code>$4000</code> or <code>$4004</code><br />
depending on the channel.<br />
<br />
The bass channel has one special handling as well. The APU register <code>$4008</code> is<br />
set differently based on the current song id. For song <code>$10</code> (item get / level<br />
up fanfare) the register is set to <code>$60</code> but all other songs use <code>$1f</code>.<br />
<br />
The noise channel is not affect at all by the pitch. Any pitch value that is<br />
non zero will play a burst of noise.</div>Bentglasstubehttp://wiki.bindingforce.net/index.php?title=Music_Engine_Description&diff=362Music Engine Description2023-08-13T04:59:15Z<p>Bentglasstube: /* Title Music Engine */</p>
<hr />
<div>There are two separate music engines in Zelda 2. Both are in bank 6 (along<br />
with the song data). The music engine for the title screen resides at<br />
<code>$8000</code> and the engine for the rest of the game is at<br />
<code>$9000</code>. Each of these engines is called once per frame during the<br />
appropriate part of the game.<br />
<br />
Changes to the music engine should be very easy to make, as there is an<br />
abundance of free space in bank 6.<br />
<br />
== Title Music Engine ==<br />
<br />
The title music engine is different from the engine that plays music<br />
during the rest of the game. In particular, it has a wider range of<br />
notes that can be represented. If you want to look into the actual<br />
code, the title screen music engine main loop is at <code>$8000</code> (vesus<br />
<code>$9000</code> for the game music loop).<br />
<br />
The metadata for the songs is all the same as in the other areas,<br />
although the title music is actually broken up into several songs<br />
itself. These song boundaries control the timing of the title scroll.<br />
<br />
The following songs exist in the title song table:<br />
<br />
# Intro<br />
# Start<br />
# Build up<br />
# Main<br />
# Breakdown<br />
<br />
The start of song 2 triggers the title to scroll into view. The start<br />
of song 4 triggers a countdown until the story scroll begins. After<br />
song 5 finishes, the engine loops back to song 2.<br />
<br />
Within the note data, a special format is used. Rather than encoding<br />
the duration and pitch together in a single byte, the title music has<br />
"pitch" bytes and "duration" bytes. Any byte with the highest bit set<br />
(i.e. anything >= <code>$80</code>) is interpreted as a duration change, which<br />
sets the duration of all future notes. Anything else is a pitch value<br />
which indicates a note of the current duration should be played. The<br />
low nibble of duration values keys into a lookup table at bank 6 <code>$8084</code> <br />
and store the duration byte at <code>$07FF</code>. Value durations are as follows:<br />
<br />
* <code>$80</code> - 8 ticks (sixteenth note)<br />
* <code>$81</code> - 24 ticks (dotted eighth note)<br />
* <code>$82</code> - 16 ticks (eighth note)<br />
* <code>$83</code> - 32 ticks (quarter note)<br />
* <code>$84</code> - 48 ticks (dotted quarter note)<br />
* <code>$85</code> - 64 ticks (half note)<br />
* <code>$86</code> - 96 ticks (dotted half note)<br />
* <code>$87</code> - 128 ticks (whole note)<br />
* <code>$88</code> - 11 ticks (eighth note triplet, first two)<br />
* <code>$89</code> - 10 ticks (eighth note triplet, third)<br />
* <code>$8A</code> - 80 ticks (half note + eighth note)<br />
* <code>$8B</code> - 256 ticks (two whole notes)<br />
* <code>$8F</code> - 6 ticks (dotted 32nd note)<br />
<br />
Note: <code>$8C</code>, <code>$8D</code> and <code>$8E</code> are duplicates, so these could be used for<br />
custom durations if desired.<br />
<br />
The pitch values are much more straightforward. As far as I can tell,<br />
<code>$4C</code> is A4 and every semitone away from that adds or subtracts 2 from<br />
the value. Thus, C5 (three semitones above A4) is <code>$52</code>. As in the game music engine, the value<br />
<code>$02</code> represents a rest.<br />
<br />
-2- -3- -4- -5- -6- -7-<br />
A : $12 $2A $42 $5A $72<br />
Bb : $14 $2C $44 $5C $74<br />
B : $16 $2E $46 $5E $76<br />
C : $18 $30 $48 $60 $78<br />
C# : $1A $32 $4A $62 $7A<br />
D : $04 $1C $34 $4C $64<br />
Eb : $06 $1E $36 $4E $66<br />
E : $08 $20 $38 $50 $68<br />
F : $0A $22 $3A $52 $6A<br />
F# : $0C $24 $3C $54 $6C<br />
G : $0E $26 $3E $56 $6E<br />
G# : $10 $28 $40 $58 $70<br />
<br />
By way of an example, let's look at the main section of the vanilla<br />
title music. The title metadata starts at bank 6 <code>$84DA</code>:<br />
<br />
08 11 14 16 19 1E 1E 1E<br />
^ Main section<br />
<br />
The main section is the fourth song, starting at <code>$84DA + $16 = $84F0</code>:<br />
<br />
3F 3F 00<br />
<br />
This means there is a single phrase for the main section, which is<br />
repeated twice. The phrase data is at <code>$84DA + $3F = $8519</code>.<br />
<br />
00 3D 86 3A 1A 5F<br />
<br />
From this, we see the melody note data is located at <code>$863D</code>:<br />
<br />
83 Quarter notes<br />
02 Rest<br />
48 Ab4<br />
82 Eighth note<br />
46 G4<br />
83 Quarter notes<br />
3E Eb4<br />
34 Bb3<br />
84 Dotted quarter notes<br />
2E G3<br />
83 Quarter notes<br />
30 Ab3<br />
34 Bb3<br />
3A Db4<br />
38 C4<br />
34 Bb3<br />
30 Ab3<br />
82 Eighth notes<br />
34 Bb3<br />
83 Quarter notes<br />
30 Ab3<br />
85 Half notes<br />
2E G3<br />
82 Quarter notes<br />
02 Rest<br />
00 End of Data<br />
<br />
== Main Music Engine ==<br />
<br />
=== Data Tables ===<br />
<br />
There are several data tables used by the music engine.<br />
<br />
==== Pulse Envelope ====<br />
<br />
This table is used to set the volume of the pulse channels over time. The index<br />
used starts at a certain value and decrements, so the table is in reverse order.<br />
The index is halved before use, so each value lasts two frames.<br />
<br />
{| class="wikitable"<br />
|+ Pulse Envelope <code>$9135</code><br />
|90||91||91||91||92||92||92||92<br />
|-<br />
|93||93||94||94||94||95||95||95<br />
|-<br />
|96||96||96||97||97||97||98||98<br />
|}<br />
<br />
==== Duration LUT ====<br />
<br />
This table is used to determine the duration of a note. The note data is stored<br />
with 5 bits of pitch information and 3 bits of duration, as such:<br />
<br />
D1 D0 P4 P3 P2 P1 P0 D2<br />
<br />
The Get Note Duration routine shifts things around to get the D bits into the<br />
three least significant bits and masks it before use. This value is then added<br />
to the tempo value in <code>$E5</code> which is always a multiple of 8 to index<br />
into the following table:<br />
<br />
{| class="wikitable"<br />
|+Duration LUT <code>$914D</code><br />
|'''00'''||04||0C||08||10||18||20||05||06<br />
|-<br />
|'''08'''||04||0F||09||12||1B||24||06||06<br />
|-<br />
|'''10'''||05||0F||0A||14||1E||28||07||06<br />
|-<br />
|'''18'''||06||12||0C||18||24||30||08||10<br />
|-<br />
|'''20'''||07||15||0E||1C||2A||38||13||12<br />
|-<br />
|'''28'''||07||15||0E||1C||2A||38||XX||XX<br />
|}<br />
<br />
The last two values in each row seem a bit strange, as they are not nice<br />
multiples of the first entry which is usually thought of as the length of an<br />
eighth note. They are usually used to make triplets which don't divide evenly by slightly shortening or lengthening the third triplet. The last row doesn't include these two values because they are nonsensical and actually belong to the next LUT anyway. That row is used for the credits music which presumably avoids those last two values.<br />
<br />
==== Pitch LUT ====<br />
<br />
This table is used to detemine the pitch of a note. The note data is stored as<br />
described above, and the fact that the least significant bit is masked out is<br />
advantageous since the pulse channels can use 11 bits of timer data, so each<br />
entry in this table is actually two bytes wide.<br />
<br />
Rather than show the raw bytes here, it's more useful to show the rough note<br />
that those values represent. If the raw values are interesting to you, check<br />
the ROM for them. It's worth noting that some of the higher notes are several<br />
cents off from the listed note.<br />
<br />
{| class="wikitable"<br />
|+Pitch LUT <code>$918F</code><br />
| || 00|| 02|| 04|| 06|| 08|| 0a|| 0c|| 0e<br />
|-<br />
|00|| C3||---|| E3|| G3||G#3|| A3||A#3|| B3<br />
|-<br />
|10|| C4||C#4|| D4||D#4|| E4|| F4||F#4|| G4<br />
|-<br />
|20||G#4|| A4||A#4|| B4|| C5||C#5|| D5||D#5<br />
|-<br />
|30|| E5|| F5||F#5|| G5|| A5||A#5|| B5||C#3<br />
|-<br />
|40|| D3||D#3|| F3||F#3||G#5|| C6||C#6|| D6<br />
|-<br />
|50||D#6|| E6|| F6||F#6|| G6||G#6|| A6||A#6<br />
|-<br />
|60|| B6|| C7||C#7|| D7||D#7|| E7|| F7||F#7<br />
|-<br />
|70|| G7||G#7|| A7||A#7|| B7|| C8<br />
|}<br />
<br />
Value <code>$02</code> represents a rest.<br />
<br />
Note that although the table goes through <code>$7A</code> values above<br />
<code>$3E</code> aren't usable due to the 5 bit limit for pitch data in<br />
the song data. However, the sound effects routines make use of these<br />
extra notes. For example, the sword beam effect alternates between<br />
playing C7 and F6. The title music engine also has a different format which allows use of more of these notes.<br />
<br />
==== Noise Samples ====<br />
<br />
Several sound effects use the same routine to load "samples" for the noise<br />
channel to play. These values have the noise volume in the high nybble and the<br />
noise period in the low nybble.<br />
<br />
$90E8 - Sword slash<br />
$9123 - Enemy hurt<br />
$912C - Crumble block<br />
<br />
=== Variables ===<br />
<br />
This is just a dump of RAM addresses used by the music engine and a short<br />
description of what they are.<br />
<br />
$00E0 - Current phrase note data address (low byte)<br />
$00E1 - Current phrase note data address (high byte)<br />
$00E2 - Song offset, converted from song id to be an index instead of a bit field<br />
$00E3 - Current phrase index<br />
$00E4 - Drums loop start<br />
$00E5 - Tempo<br />
$00E6 - Pulse 1 low bits (used for vibrato effect)<br />
$00E7 - Pulse 2 low bits (used for vibrato effect)<br />
$00E8 - Pitch storage, temporary<br />
$00E9 - Play sound effect<br />
$00EA - Disable music<br />
$00EB - Request new song<br />
$00EC - Play sound effect<br />
$00ED - Play sound effect<br />
$00EE - Play sound effect<br />
$00EF - Play sound effect<br />
<br />
$0707 - Current world<br />
$075F - Queued song, loaded after screen transitions<br />
$07DA - Ganon Laugh sample<br />
$07DB - Song to resume after fanfare<br />
$07DF - ??? Likely sound effect flag for pulse 1 channel override<br />
<br />
$07E0 - ??? Likely sound effect flag for noise channel<br />
$07E2 - Pulse 2 envelope index<br />
$07E3 - Pulse 1 envelope index<br />
$07E4 - Drums current note duration<br />
$07E5 - Bass current note duration<br />
$07E6 - Harmony current note duration<br />
$07E7 - Melody current note duration<br />
$07E8 - Drums next note index<br />
$07E9 - Bass next note index<br />
$07EA - Harmony next note index<br />
$07EB - Melody next note index<br />
<br />
$07EC - Ganon Laugh counter<br />
$07ED - Sound FX counter (E9)<br />
$07EE - Sound FX counter (E9)<br />
$07F5 - Sound FX counter (ED)<br />
<br />
$07FA - Current SFX (E9)<br />
$07FB - Current song<br />
$07FD - Current SFX (ED)<br />
$07FE - ??? Likely sound effect flag for pulse 2 channel override<br />
$07FF - Current SFX (EF)<br />
<br />
=== Routines ===<br />
<br />
This is a non-exhaustive list of the routines in bank 6 involving the playing of<br />
music and sound effects. Each routine also lists its address so you can search<br />
in a disassembly for the actual code for that routine if these descriptions<br />
aren't clear.<br />
<br />
==== Main Music Loop <code>$9000</code> ====<br />
<br />
Checks that the music disable flag is off, then runs several SFX routines.<br />
After the SFX routines, the main music routine runs. After all this, various<br />
music related memory locations are cleared.<br />
<br />
==== Configure Pulse1 Channel <code>$9031</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4000</code> and <code>$4001</code><br />
respectively.<br />
<br />
==== Configure Pulse2 Channel <code>$9038</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4004</code> and <code>$4005</code><br />
respectively.<br />
<br />
==== Play Note Pulse1 <code>$9042</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 1 channel.<br />
<br />
==== Play Note <code>$9044</code> ====<br />
<br />
Called by the various play note routines. Takes a pitch index in register a and<br />
uses register x as a channel selector. For the pulse channels, this routine<br />
also saves the lower 8 bits of the APU timer register to <code>$E6</code> or <code>$E7</code> which<br />
are used for a vibrato effect.<br />
<br />
==== Play Note Pulse2 <code>$9067</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 2 channel.<br />
<br />
==== Play Note Triangle <code>$906B</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the triangle channel.<br />
<br />
==== Get Note Duration <code>$906F</code> ====<br />
<br />
Takes note data in register a and looks up the duration. The original note<br />
data is saved in register x and the result of the duration lookup is put in<br />
register a. The duration lookup is offset by the tempo stored in <code>$E5</code>.<br />
<br />
==== Vibrato Pulse1 <code>$9089</code> ====<br />
<br />
Applies a vibrato effect on the pulse 1 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato Pulse2 <code>$9097</code> ====<br />
<br />
Applies a vibrato effect on the pulse 2 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato <code>$909E</code> ====<br />
<br />
Takes the duration of the note remaining in register a, the low bits of the APU<br />
timer in register y, and the channel to use in register x. This is called by<br />
the other vibrato routines after setting x appropriately.<br />
<br />
Uses the <code>$04</code> bit of the duration to either add or subtract 2 from the low<br />
timer bits. Only the low bits are used because writing to the high bits resets<br />
the phase of the channel which can cause clicks. None of the notes from the<br />
pitch LUT are close enough to the boundary for the change to require the high<br />
bits to change anyway, so this works out fine.<br />
<br />
==== Play E9 SFX <code>$920B</code> ====<br />
<br />
Plays the sound effect requested in <code>$E9</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EF SFX <code>$92F4</code> ====<br />
<br />
Plays the sound effect requested in <code>$EF</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EE SFX <code>$9408</code> ====<br />
<br />
Plays the sound effect requested in <code>$EE</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Noise <code>$959D</code> ====<br />
<br />
Configures the APU noise registers to make a noise burst. Takes configuration<br />
for registers <code>$400F</code>, <code>$400E</code>, and <code>$400C</code> in registers y, x, and a.<br />
<br />
==== Crumble Bridge SFX <code>$956C</code> ====<br />
<br />
Starts playing the sound effect for a crumble bridge crumbling. This uses both<br />
the noise and the triangle channels so it sets flags to disable the music on<br />
those channels. Continues with SFX Noise Decay.<br />
<br />
==== SFX Noise Decay <code>$9587</code> ====<br />
<br />
Counts down the timer in <code>$07F5</code> and turns off the noise when it reaches 0.<br />
Also clears the flag for the ED sound effect in <code>$07FD</code>.<br />
<br />
==== Play ED SFX <code>$95A7</code> ====<br />
<br />
Plays the sound effect request in <code>$ED</code> or continues the sound effect saved in<br />
<code>$07FD</code>. Existing sound effects which are higher than the current sound effect<br />
will be ignored. If the same sound effect is requested that is already playing,<br />
it will restart the sound effect except for <code>$80</code> which gives priority to<br />
continuing. When the sound is continued instead of newly played, the decay<br />
routine will be called instead.<br />
<br />
; <code>$02</code><br />
: Crumble Bridge<br />
; <code>$04</code> and <code>$10</code><br />
: Crumble Block / Enemy Hurt<br />
; <code>$20</code> and <code>$80</code><br />
: Sword Strike<br />
; <code>$40</code><br />
: Very short noise burst, probably unused. Doesn't store the effect, and doesn't have an associated decay.<br />
<br />
==== Crumble Block / Enemy Hurt SFX <code>$95E6</code> ====<br />
<br />
Starts playing the sound of a block breaking or an enemy getting hurt.<br />
<br />
==== Crumble Block / Enemy Hurt SFX Decay <code>$95EE</code> ====<br />
<br />
Looks up noise register values based on the timer and the sound effect value.<br />
Crumble Block samples are at <code>$912C</code> while Enemy Hurt is at <code>$9123</code>. Continues<br />
on to Play Noise Samples.<br />
<br />
==== Play Noise Samples <code>$9612</code> ====<br />
<br />
Takes a sample value in register a. The low four bits of this are used to set<br />
the noise period via APU register <code>$400E</code>. The high four bits are used to set<br />
the noise volume via APU register <code>$400C</code>.<br />
<br />
Continues on the SFX Noise Decay process.<br />
<br />
==== Sword Strike SFX <code>$9604</code> ====<br />
<br />
Starts playing the sound of swinging your sword. This looks up samples based on<br />
the duration left at <code>$90E8</code> and plays them via Play Noise Samples.<br />
<br />
==== Play EC SFX <code>$990B</code> ====<br />
<br />
Plays the sound effect requested in <code>$EC</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Music <code>$9B18</code> ====<br />
<br />
Plays the music for the game.<br />
<br />
Runs Load Song if a new song is requested in <code>$EB</code>. Otherwise, runs Play Notes<br />
if the current song is set in <code>$07FB</code>. If neither of these is true, do nothing.<br />
<br />
==== Next Song <code>$9B24</code> ====<br />
<br />
Checks if the previous song should loop. If not, calls Mute All and returns.<br />
<br />
If the previous song was <code>$01</code> (the "intro" to the main theme), sets the next<br />
song to <code>$02</code> (the main theme loop).<br />
<br />
If the previous song was <code>$10</code> (the item get / level up fanfare), sets the<br />
current song from <code>$07DB</code>. Otherwise, leaves the current song the same as the<br />
previous song.<br />
<br />
Proceeds to Load Song.<br />
<br />
==== Mute All <code>$9B3B</code> ====<br />
<br />
Clears the current song at <code>$07FB</code> and sets the APU registers to mute the volume<br />
on both pulse channels, the triangle channel, and the noise channel.<br />
<br />
==== Load Song <code>$9B61</code> ====<br />
<br />
Takes a song id in register a and preps some variables for that song.<br />
<br />
If the song is <code>$10</code> (item get / level up fanfare) then it first saves the<br />
previous song to <code>$07FB</code> if it is less than <code>$10</code> so that the previous music<br />
will resume after the fanfare.<br />
<br />
Sets the phrase counter at <code>$E3</code> to 0 and the song offset at <code>$E2</code> based on the<br />
song id. Song ids are a bit field, and the song offset is the position of the<br />
lowest bit in the song id for indexing into the song table.<br />
<br />
Proceeds to Load Song Data.<br />
<br />
==== Load Song Data <code>$9B80</code> ====<br />
<br />
Loads the music variables based on the current world and current song offset.<br />
<br />
There are four blocks of code that are basically the same, for each of the four<br />
different music tables. Each one just uses a different position for the tables<br />
to load.<br />
<br />
Based on the current world in <code>$0707</code> it loads data from these offsets:<br />
<br />
<code>$00</code><br />
: Overworld music - <code>$9B87</code><br />
<code>$01</code> or <code>$02</code><br />
: Town music - <code>$9BC6</code><br />
<code>$03</code> or <code>$04</code><br />
: Palace music - <code>$9C05</code><br />
<code>$05</code> or higher<br />
: Great Palace music - <code>$9C42</code><br />
<br />
First, uses the song offset in <code>$E2</code> to index into the song table at the base<br />
offset given above.<br />
<br />
The phrase counter at <code>$E3</code> is added to that and used as in index again to<br />
retrieve the current phrase offset. If the current phrase offset is <code>$00</code> that<br />
means the song is over and the process goes back to the Next Song routine.<br />
<br />
Otherwise, the following structure is read at the base offset above + phrase<br />
offset just calculated.<br />
<br />
* <code>$E5</code> Tempo<br />
* <code>$E0</code> Note Data Low<br />
* <code>$E1</code> Note Data High<br />
* <code>$07E9</code> Bass Note Pointer<br />
* <code>$07EA</code> Harmony Note Pointer<br />
* <code>$07E8</code> Drum Note Pointer<br />
<br />
After this, the drum loop start point at <code>$E4</code> is also set to the same value as<br />
the drum note pointer. The melody note pointer at <code>$07EB</code> is set to <code>$00</code>, and<br />
all the durations (melody at <code>$07E7</code>, harmony at <code>$07E6</code>, bass at <code>$07E5</code>, and<br />
drums at <code>$07E4</code>) are set to <code>$01</code>.<br />
<br />
Proceeds to Play Notes.<br />
<br />
==== Play Notes ====<br />
<br />
This routine is broken into four major and similar sections: one each for<br />
melody, harmony, bass, and drums. The general process is as follows:<br />
<br />
decrement duration<br />
if duration == 0 {<br />
load next note<br />
increment note pointer<br />
set duration for note<br />
if no overriding sound effect {<br />
play note on appropriate channel<br />
}<br />
}<br />
<br />
Some channels have unique processing at different points in this. For example,<br />
the melody note data is null terminated, so if the loaded note in <code>$00</code> then the<br />
routine will jump to Load Song Data instead to go to the next phrase. If the<br />
drums channel gets a <code>$00</code> note it will reset the drums note pointer to the<br />
drums loop start and repeat the phrase. The bass and harmony channels don't<br />
have this looping behavior. This means that if the bass or harmony channels<br />
aren't long enough, the engine will happily just play whatever data comes next<br />
in the ROM.<br />
<br />
The melody is played on pulse 2 channel, the harmony on pulse 1 (which gets<br />
subverted by sound effects that need just one pulse channel), the bass on the<br />
triangle channel, and the drums on the noise channel.<br />
<br />
For the pulse channels, after the note is played, the envelope counter for that<br />
channel (<code>$07E2</code> for pulse 1, <code>$07E3</code> for pulse 2) is set. Normally the<br />
envelope is set to <code>$2F</code> but song <code>$40</code> (crystal fanfare and final boss music)<br />
sets it to <code>$18</code> instead. The envelope is not set if no note was played because<br />
the pitch index was <code>$02</code> which indicates a rest.<br />
<br />
Also for the pulse channels, after the above pseudocode, the vibrato and<br />
enveloping happens as long as there is no overriding sound effect. The envelope<br />
works by checking the envelope counter set previously and decrementing it. The<br />
counter value is halved and used to look up the envelope value in the LUT at<br />
<code>$9135</code>. These values are written directly to APU register <code>$4000</code> or <code>$4004</code><br />
depending on the channel.<br />
<br />
The bass channel has one special handling as well. The APU register <code>$4008</code> is<br />
set differently based on the current song id. For song <code>$10</code> (item get / level<br />
up fanfare) the register is set to <code>$60</code> but all other songs use <code>$1f</code>.<br />
<br />
The noise channel is not affect at all by the pitch. Any pitch value that is<br />
non zero will play a burst of noise.</div>Bentglasstubehttp://wiki.bindingforce.net/index.php?title=Music_Engine_Description&diff=361Music Engine Description2023-08-13T04:56:44Z<p>Bentglasstube: /* Title Music Engine */</p>
<hr />
<div>There are two separate music engines in Zelda 2. Both are in bank 6 (along<br />
with the song data). The music engine for the title screen resides at<br />
<code>$8000</code> and the engine for the rest of the game is at<br />
<code>$9000</code>. Each of these engines is called once per frame during the<br />
appropriate part of the game.<br />
<br />
Changes to the music engine should be very easy to make, as there is an<br />
abundance of free space in bank 6.<br />
<br />
== Title Music Engine ==<br />
<br />
The title music engine is different from the engine that plays music<br />
during the rest of the game. In particular, it has a wider range of<br />
notes that can be represented. If you want to look into the actual<br />
code, the title screen music engine main loop is at <code>$8000</code> (vesus<br />
<code>$9000</code> for the game music loop).<br />
<br />
The metadata for the songs is all the same as in the other areas,<br />
although the title music is actually broken up into several songs<br />
itself. These song boundaries control the timing of the title scroll.<br />
<br />
The following songs exist in the title song table:<br />
<br />
1. Intro<br />
2. Start<br />
3. Build up<br />
4. Main<br />
5. Breakdown<br />
<br />
The start of song 2 triggers the title to scroll into view. The start<br />
of song 4 triggers a countdown until the story scroll begins. After<br />
song 5 finishes, the engine loops back to song 2.<br />
<br />
Within the note data, a special format is used. Rather than encoding<br />
the duration and pitch together in a single byte, the title music has<br />
"pitch" bytes and "duration" bytes. Any byte with the highest bit set<br />
(i.e. anything >= <code>$80</code>) is interpreted as a duration change, which<br />
sets the duration of all future notes. Anything else is a pitch value<br />
which indicates a note of the current duration should be played. The<br />
low nibble of duration values keys into a lookup table at bank 6 <code>$8084</code> <br />
and store the duration byte at <code>$07FF</code>. Value durations are as follows:<br />
<br />
* <code>$80</code> - 8 ticks (sixteenth note)<br />
* <code>$81</code> - 24 ticks (dotted eighth note)<br />
* <code>$82</code> - 16 ticks (eighth note)<br />
* <code>$83</code> - 32 ticks (quarter note)<br />
* <code>$84</code> - 48 ticks (dotted quarter note)<br />
* <code>$85</code> - 64 ticks (half note)<br />
* <code>$86</code> - 96 ticks (dotted half note)<br />
* <code>$87</code> - 128 ticks (whole note)<br />
* <code>$88</code> - 11 ticks (eighth note triplet, first two)<br />
* <code>$89</code> - 10 ticks (eighth note triplet, third)<br />
* <code>$8A</code> - 80 ticks (half note + eighth note)<br />
* <code>$8B</code> - 256 ticks (two whole notes)<br />
* <code>$8F</code> - 6 ticks (dotted 32nd note)<br />
<br />
Note: <code>$8C</code>, <code>$8D</code> and <code>$8E</code> are duplicates, so these could be used for<br />
custom durations if desired.<br />
<br />
The pitch values are much more straightforward. As far as I can tell,<br />
<code>$4C</code> is A4 and every semitone away from that adds or subtracts 2 from<br />
the value. Thus, C5 (three semitones above A4) is <code>$52</code>. As in the game music engine, the value<br />
<code>$02</code> represents a rest.<br />
<br />
-2- -3- -4- -5- -6- -7-<br />
A : $12 $2A $42 $5A $72<br />
Bb : $14 $2C $44 $5C $74<br />
B : $16 $2E $46 $5E $76<br />
C : $18 $30 $48 $60 $78<br />
C# : $1A $32 $4A $62 $7A<br />
D : $04 $1C $34 $4C $64<br />
Eb : $06 $1E $36 $4E $66<br />
E : $08 $20 $38 $50 $68<br />
F : $0A $22 $3A $52 $6A<br />
F# : $0C $24 $3C $54 $6C<br />
G : $0E $26 $3E $56 $6E<br />
G# : $10 $28 $40 $58 $70<br />
<br />
By way of an example, let's look at the main section of the vanilla<br />
title music. The title metadata starts at bank 6 <code>$84DA</code>:<br />
<br />
08 11 14 16 19 1E 1E 1E<br />
^ Main section<br />
<br />
The main section is the fourth song, starting at <code>$84DA + $16 = $84F0</code>:<br />
<br />
3F 3F 00<br />
<br />
This means there is a single phrase for the main section, which is<br />
repeated twice. The phrase data is at <code>$84DA + $3F = $8519</code>.<br />
<br />
00 3D 86 3A 1A 5F<br />
<br />
From this, we see the melody note data is located at <code>$863D</code>:<br />
<br />
83 Quarter notes<br />
02 Rest<br />
48 Ab4<br />
82 Eighth note<br />
46 G4<br />
83 Quarter notes<br />
3E Eb4<br />
34 Bb3<br />
84 Dotted quarter notes<br />
2E G3<br />
83 Quarter notes<br />
30 Ab3<br />
34 Bb3<br />
3A Db4<br />
38 C4<br />
34 Bb3<br />
30 Ab3<br />
82 Eighth notes<br />
34 Bb3<br />
83 Quarter notes<br />
30 Ab3<br />
85 Half notes<br />
2E G3<br />
82 Quarter notes<br />
02 Rest<br />
00 End of Data<br />
<br />
== Main Music Engine ==<br />
<br />
=== Data Tables ===<br />
<br />
There are several data tables used by the music engine.<br />
<br />
==== Pulse Envelope ====<br />
<br />
This table is used to set the volume of the pulse channels over time. The index<br />
used starts at a certain value and decrements, so the table is in reverse order.<br />
The index is halved before use, so each value lasts two frames.<br />
<br />
{| class="wikitable"<br />
|+ Pulse Envelope <code>$9135</code><br />
|90||91||91||91||92||92||92||92<br />
|-<br />
|93||93||94||94||94||95||95||95<br />
|-<br />
|96||96||96||97||97||97||98||98<br />
|}<br />
<br />
==== Duration LUT ====<br />
<br />
This table is used to determine the duration of a note. The note data is stored<br />
with 5 bits of pitch information and 3 bits of duration, as such:<br />
<br />
D1 D0 P4 P3 P2 P1 P0 D2<br />
<br />
The Get Note Duration routine shifts things around to get the D bits into the<br />
three least significant bits and masks it before use. This value is then added<br />
to the tempo value in <code>$E5</code> which is always a multiple of 8 to index<br />
into the following table:<br />
<br />
{| class="wikitable"<br />
|+Duration LUT <code>$914D</code><br />
|'''00'''||04||0C||08||10||18||20||05||06<br />
|-<br />
|'''08'''||04||0F||09||12||1B||24||06||06<br />
|-<br />
|'''10'''||05||0F||0A||14||1E||28||07||06<br />
|-<br />
|'''18'''||06||12||0C||18||24||30||08||10<br />
|-<br />
|'''20'''||07||15||0E||1C||2A||38||13||12<br />
|-<br />
|'''28'''||07||15||0E||1C||2A||38||XX||XX<br />
|}<br />
<br />
The last two values in each row seem a bit strange, as they are not nice<br />
multiples of the first entry which is usually thought of as the length of an<br />
eighth note. They are usually used to make triplets which don't divide evenly by slightly shortening or lengthening the third triplet. The last row doesn't include these two values because they are nonsensical and actually belong to the next LUT anyway. That row is used for the credits music which presumably avoids those last two values.<br />
<br />
==== Pitch LUT ====<br />
<br />
This table is used to detemine the pitch of a note. The note data is stored as<br />
described above, and the fact that the least significant bit is masked out is<br />
advantageous since the pulse channels can use 11 bits of timer data, so each<br />
entry in this table is actually two bytes wide.<br />
<br />
Rather than show the raw bytes here, it's more useful to show the rough note<br />
that those values represent. If the raw values are interesting to you, check<br />
the ROM for them. It's worth noting that some of the higher notes are several<br />
cents off from the listed note.<br />
<br />
{| class="wikitable"<br />
|+Pitch LUT <code>$918F</code><br />
| || 00|| 02|| 04|| 06|| 08|| 0a|| 0c|| 0e<br />
|-<br />
|00|| C3||---|| E3|| G3||G#3|| A3||A#3|| B3<br />
|-<br />
|10|| C4||C#4|| D4||D#4|| E4|| F4||F#4|| G4<br />
|-<br />
|20||G#4|| A4||A#4|| B4|| C5||C#5|| D5||D#5<br />
|-<br />
|30|| E5|| F5||F#5|| G5|| A5||A#5|| B5||C#3<br />
|-<br />
|40|| D3||D#3|| F3||F#3||G#5|| C6||C#6|| D6<br />
|-<br />
|50||D#6|| E6|| F6||F#6|| G6||G#6|| A6||A#6<br />
|-<br />
|60|| B6|| C7||C#7|| D7||D#7|| E7|| F7||F#7<br />
|-<br />
|70|| G7||G#7|| A7||A#7|| B7|| C8<br />
|}<br />
<br />
Value <code>$02</code> represents a rest.<br />
<br />
Note that although the table goes through <code>$7A</code> values above<br />
<code>$3E</code> aren't usable due to the 5 bit limit for pitch data in<br />
the song data. However, the sound effects routines make use of these<br />
extra notes. For example, the sword beam effect alternates between<br />
playing C7 and F6. The title music engine also has a different format which allows use of more of these notes.<br />
<br />
==== Noise Samples ====<br />
<br />
Several sound effects use the same routine to load "samples" for the noise<br />
channel to play. These values have the noise volume in the high nybble and the<br />
noise period in the low nybble.<br />
<br />
$90E8 - Sword slash<br />
$9123 - Enemy hurt<br />
$912C - Crumble block<br />
<br />
=== Variables ===<br />
<br />
This is just a dump of RAM addresses used by the music engine and a short<br />
description of what they are.<br />
<br />
$00E0 - Current phrase note data address (low byte)<br />
$00E1 - Current phrase note data address (high byte)<br />
$00E2 - Song offset, converted from song id to be an index instead of a bit field<br />
$00E3 - Current phrase index<br />
$00E4 - Drums loop start<br />
$00E5 - Tempo<br />
$00E6 - Pulse 1 low bits (used for vibrato effect)<br />
$00E7 - Pulse 2 low bits (used for vibrato effect)<br />
$00E8 - Pitch storage, temporary<br />
$00E9 - Play sound effect<br />
$00EA - Disable music<br />
$00EB - Request new song<br />
$00EC - Play sound effect<br />
$00ED - Play sound effect<br />
$00EE - Play sound effect<br />
$00EF - Play sound effect<br />
<br />
$0707 - Current world<br />
$075F - Queued song, loaded after screen transitions<br />
$07DA - Ganon Laugh sample<br />
$07DB - Song to resume after fanfare<br />
$07DF - ??? Likely sound effect flag for pulse 1 channel override<br />
<br />
$07E0 - ??? Likely sound effect flag for noise channel<br />
$07E2 - Pulse 2 envelope index<br />
$07E3 - Pulse 1 envelope index<br />
$07E4 - Drums current note duration<br />
$07E5 - Bass current note duration<br />
$07E6 - Harmony current note duration<br />
$07E7 - Melody current note duration<br />
$07E8 - Drums next note index<br />
$07E9 - Bass next note index<br />
$07EA - Harmony next note index<br />
$07EB - Melody next note index<br />
<br />
$07EC - Ganon Laugh counter<br />
$07ED - Sound FX counter (E9)<br />
$07EE - Sound FX counter (E9)<br />
$07F5 - Sound FX counter (ED)<br />
<br />
$07FA - Current SFX (E9)<br />
$07FB - Current song<br />
$07FD - Current SFX (ED)<br />
$07FE - ??? Likely sound effect flag for pulse 2 channel override<br />
$07FF - Current SFX (EF)<br />
<br />
=== Routines ===<br />
<br />
This is a non-exhaustive list of the routines in bank 6 involving the playing of<br />
music and sound effects. Each routine also lists its address so you can search<br />
in a disassembly for the actual code for that routine if these descriptions<br />
aren't clear.<br />
<br />
==== Main Music Loop <code>$9000</code> ====<br />
<br />
Checks that the music disable flag is off, then runs several SFX routines.<br />
After the SFX routines, the main music routine runs. After all this, various<br />
music related memory locations are cleared.<br />
<br />
==== Configure Pulse1 Channel <code>$9031</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4000</code> and <code>$4001</code><br />
respectively.<br />
<br />
==== Configure Pulse2 Channel <code>$9038</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4004</code> and <code>$4005</code><br />
respectively.<br />
<br />
==== Play Note Pulse1 <code>$9042</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 1 channel.<br />
<br />
==== Play Note <code>$9044</code> ====<br />
<br />
Called by the various play note routines. Takes a pitch index in register a and<br />
uses register x as a channel selector. For the pulse channels, this routine<br />
also saves the lower 8 bits of the APU timer register to <code>$E6</code> or <code>$E7</code> which<br />
are used for a vibrato effect.<br />
<br />
==== Play Note Pulse2 <code>$9067</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 2 channel.<br />
<br />
==== Play Note Triangle <code>$906B</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the triangle channel.<br />
<br />
==== Get Note Duration <code>$906F</code> ====<br />
<br />
Takes note data in register a and looks up the duration. The original note<br />
data is saved in register x and the result of the duration lookup is put in<br />
register a. The duration lookup is offset by the tempo stored in <code>$E5</code>.<br />
<br />
==== Vibrato Pulse1 <code>$9089</code> ====<br />
<br />
Applies a vibrato effect on the pulse 1 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato Pulse2 <code>$9097</code> ====<br />
<br />
Applies a vibrato effect on the pulse 2 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato <code>$909E</code> ====<br />
<br />
Takes the duration of the note remaining in register a, the low bits of the APU<br />
timer in register y, and the channel to use in register x. This is called by<br />
the other vibrato routines after setting x appropriately.<br />
<br />
Uses the <code>$04</code> bit of the duration to either add or subtract 2 from the low<br />
timer bits. Only the low bits are used because writing to the high bits resets<br />
the phase of the channel which can cause clicks. None of the notes from the<br />
pitch LUT are close enough to the boundary for the change to require the high<br />
bits to change anyway, so this works out fine.<br />
<br />
==== Play E9 SFX <code>$920B</code> ====<br />
<br />
Plays the sound effect requested in <code>$E9</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EF SFX <code>$92F4</code> ====<br />
<br />
Plays the sound effect requested in <code>$EF</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EE SFX <code>$9408</code> ====<br />
<br />
Plays the sound effect requested in <code>$EE</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Noise <code>$959D</code> ====<br />
<br />
Configures the APU noise registers to make a noise burst. Takes configuration<br />
for registers <code>$400F</code>, <code>$400E</code>, and <code>$400C</code> in registers y, x, and a.<br />
<br />
==== Crumble Bridge SFX <code>$956C</code> ====<br />
<br />
Starts playing the sound effect for a crumble bridge crumbling. This uses both<br />
the noise and the triangle channels so it sets flags to disable the music on<br />
those channels. Continues with SFX Noise Decay.<br />
<br />
==== SFX Noise Decay <code>$9587</code> ====<br />
<br />
Counts down the timer in <code>$07F5</code> and turns off the noise when it reaches 0.<br />
Also clears the flag for the ED sound effect in <code>$07FD</code>.<br />
<br />
==== Play ED SFX <code>$95A7</code> ====<br />
<br />
Plays the sound effect request in <code>$ED</code> or continues the sound effect saved in<br />
<code>$07FD</code>. Existing sound effects which are higher than the current sound effect<br />
will be ignored. If the same sound effect is requested that is already playing,<br />
it will restart the sound effect except for <code>$80</code> which gives priority to<br />
continuing. When the sound is continued instead of newly played, the decay<br />
routine will be called instead.<br />
<br />
; <code>$02</code><br />
: Crumble Bridge<br />
; <code>$04</code> and <code>$10</code><br />
: Crumble Block / Enemy Hurt<br />
; <code>$20</code> and <code>$80</code><br />
: Sword Strike<br />
; <code>$40</code><br />
: Very short noise burst, probably unused. Doesn't store the effect, and doesn't have an associated decay.<br />
<br />
==== Crumble Block / Enemy Hurt SFX <code>$95E6</code> ====<br />
<br />
Starts playing the sound of a block breaking or an enemy getting hurt.<br />
<br />
==== Crumble Block / Enemy Hurt SFX Decay <code>$95EE</code> ====<br />
<br />
Looks up noise register values based on the timer and the sound effect value.<br />
Crumble Block samples are at <code>$912C</code> while Enemy Hurt is at <code>$9123</code>. Continues<br />
on to Play Noise Samples.<br />
<br />
==== Play Noise Samples <code>$9612</code> ====<br />
<br />
Takes a sample value in register a. The low four bits of this are used to set<br />
the noise period via APU register <code>$400E</code>. The high four bits are used to set<br />
the noise volume via APU register <code>$400C</code>.<br />
<br />
Continues on the SFX Noise Decay process.<br />
<br />
==== Sword Strike SFX <code>$9604</code> ====<br />
<br />
Starts playing the sound of swinging your sword. This looks up samples based on<br />
the duration left at <code>$90E8</code> and plays them via Play Noise Samples.<br />
<br />
==== Play EC SFX <code>$990B</code> ====<br />
<br />
Plays the sound effect requested in <code>$EC</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Music <code>$9B18</code> ====<br />
<br />
Plays the music for the game.<br />
<br />
Runs Load Song if a new song is requested in <code>$EB</code>. Otherwise, runs Play Notes<br />
if the current song is set in <code>$07FB</code>. If neither of these is true, do nothing.<br />
<br />
==== Next Song <code>$9B24</code> ====<br />
<br />
Checks if the previous song should loop. If not, calls Mute All and returns.<br />
<br />
If the previous song was <code>$01</code> (the "intro" to the main theme), sets the next<br />
song to <code>$02</code> (the main theme loop).<br />
<br />
If the previous song was <code>$10</code> (the item get / level up fanfare), sets the<br />
current song from <code>$07DB</code>. Otherwise, leaves the current song the same as the<br />
previous song.<br />
<br />
Proceeds to Load Song.<br />
<br />
==== Mute All <code>$9B3B</code> ====<br />
<br />
Clears the current song at <code>$07FB</code> and sets the APU registers to mute the volume<br />
on both pulse channels, the triangle channel, and the noise channel.<br />
<br />
==== Load Song <code>$9B61</code> ====<br />
<br />
Takes a song id in register a and preps some variables for that song.<br />
<br />
If the song is <code>$10</code> (item get / level up fanfare) then it first saves the<br />
previous song to <code>$07FB</code> if it is less than <code>$10</code> so that the previous music<br />
will resume after the fanfare.<br />
<br />
Sets the phrase counter at <code>$E3</code> to 0 and the song offset at <code>$E2</code> based on the<br />
song id. Song ids are a bit field, and the song offset is the position of the<br />
lowest bit in the song id for indexing into the song table.<br />
<br />
Proceeds to Load Song Data.<br />
<br />
==== Load Song Data <code>$9B80</code> ====<br />
<br />
Loads the music variables based on the current world and current song offset.<br />
<br />
There are four blocks of code that are basically the same, for each of the four<br />
different music tables. Each one just uses a different position for the tables<br />
to load.<br />
<br />
Based on the current world in <code>$0707</code> it loads data from these offsets:<br />
<br />
<code>$00</code><br />
: Overworld music - <code>$9B87</code><br />
<code>$01</code> or <code>$02</code><br />
: Town music - <code>$9BC6</code><br />
<code>$03</code> or <code>$04</code><br />
: Palace music - <code>$9C05</code><br />
<code>$05</code> or higher<br />
: Great Palace music - <code>$9C42</code><br />
<br />
First, uses the song offset in <code>$E2</code> to index into the song table at the base<br />
offset given above.<br />
<br />
The phrase counter at <code>$E3</code> is added to that and used as in index again to<br />
retrieve the current phrase offset. If the current phrase offset is <code>$00</code> that<br />
means the song is over and the process goes back to the Next Song routine.<br />
<br />
Otherwise, the following structure is read at the base offset above + phrase<br />
offset just calculated.<br />
<br />
* <code>$E5</code> Tempo<br />
* <code>$E0</code> Note Data Low<br />
* <code>$E1</code> Note Data High<br />
* <code>$07E9</code> Bass Note Pointer<br />
* <code>$07EA</code> Harmony Note Pointer<br />
* <code>$07E8</code> Drum Note Pointer<br />
<br />
After this, the drum loop start point at <code>$E4</code> is also set to the same value as<br />
the drum note pointer. The melody note pointer at <code>$07EB</code> is set to <code>$00</code>, and<br />
all the durations (melody at <code>$07E7</code>, harmony at <code>$07E6</code>, bass at <code>$07E5</code>, and<br />
drums at <code>$07E4</code>) are set to <code>$01</code>.<br />
<br />
Proceeds to Play Notes.<br />
<br />
==== Play Notes ====<br />
<br />
This routine is broken into four major and similar sections: one each for<br />
melody, harmony, bass, and drums. The general process is as follows:<br />
<br />
decrement duration<br />
if duration == 0 {<br />
load next note<br />
increment note pointer<br />
set duration for note<br />
if no overriding sound effect {<br />
play note on appropriate channel<br />
}<br />
}<br />
<br />
Some channels have unique processing at different points in this. For example,<br />
the melody note data is null terminated, so if the loaded note in <code>$00</code> then the<br />
routine will jump to Load Song Data instead to go to the next phrase. If the<br />
drums channel gets a <code>$00</code> note it will reset the drums note pointer to the<br />
drums loop start and repeat the phrase. The bass and harmony channels don't<br />
have this looping behavior. This means that if the bass or harmony channels<br />
aren't long enough, the engine will happily just play whatever data comes next<br />
in the ROM.<br />
<br />
The melody is played on pulse 2 channel, the harmony on pulse 1 (which gets<br />
subverted by sound effects that need just one pulse channel), the bass on the<br />
triangle channel, and the drums on the noise channel.<br />
<br />
For the pulse channels, after the note is played, the envelope counter for that<br />
channel (<code>$07E2</code> for pulse 1, <code>$07E3</code> for pulse 2) is set. Normally the<br />
envelope is set to <code>$2F</code> but song <code>$40</code> (crystal fanfare and final boss music)<br />
sets it to <code>$18</code> instead. The envelope is not set if no note was played because<br />
the pitch index was <code>$02</code> which indicates a rest.<br />
<br />
Also for the pulse channels, after the above pseudocode, the vibrato and<br />
enveloping happens as long as there is no overriding sound effect. The envelope<br />
works by checking the envelope counter set previously and decrementing it. The<br />
counter value is halved and used to look up the envelope value in the LUT at<br />
<code>$9135</code>. These values are written directly to APU register <code>$4000</code> or <code>$4004</code><br />
depending on the channel.<br />
<br />
The bass channel has one special handling as well. The APU register <code>$4008</code> is<br />
set differently based on the current song id. For song <code>$10</code> (item get / level<br />
up fanfare) the register is set to <code>$60</code> but all other songs use <code>$1f</code>.<br />
<br />
The noise channel is not affect at all by the pitch. Any pitch value that is<br />
non zero will play a burst of noise.</div>Bentglasstubehttp://wiki.bindingforce.net/index.php?title=Music_Engine_Description&diff=360Music Engine Description2023-08-13T04:39:55Z<p>Bentglasstube: /* Pitch LUT */</p>
<hr />
<div>There are two separate music engines in Zelda 2. Both are in bank 6 (along<br />
with the song data). The music engine for the title screen resides at<br />
<code>$8000</code> and the engine for the rest of the game is at<br />
<code>$9000</code>. Each of these engines is called once per frame during the<br />
appropriate part of the game.<br />
<br />
Changes to the music engine should be very easy to make, as there is an<br />
abundance of free space in bank 6.<br />
<br />
== Title Music Engine ==<br />
<br />
'''TODO''' properly format the following by bgt (original at https://eab.xyz/W2zplGD) and dontbagume (on discord).<br />
<br />
# Title Music Engine<br />
<br />
The title music engine is different from the engine that plays music<br />
during the rest of the game. In particular, it has a wider range of<br />
notes that can be represented. If you want to look into the actual<br />
code, the title screen music engine main loop is at `$8000` (vesus<br />
`$9000` for the game music loop).<br />
<br />
The metadata for the songs is all the same as in the other areas,<br />
although the title music is actually broken up into several songs<br />
itself. These song boundaries control the timing of the title scroll.<br />
<br />
The following songs exist in the title song table:<br />
<br />
1. Intro<br />
2. Start<br />
3. Build up<br />
4. Main<br />
5. Breakdown<br />
<br />
The start of song 2 triggers the title to scroll into view. The start<br />
of song 4 triggers a countdown until the story scroll begins. After<br />
song 5 finishes, the engine loops back to song 2.<br />
<br />
Within the note data, a special format is used. Rather than encoding<br />
the duration and pitch together in a single byte, the title music has<br />
"pitch" bytes and "duration" bytes. Any byte with the highest bit set<br />
(i.e. anything >= `$80`) is interpreted as a duration change, which<br />
sets the duration of all future notes. Anything else is a pitch value<br />
which indicates a note of the current duration should be played. The<br />
low nibble of duration values keys into a lookup table at bank 6 `$8084` <br />
and store the duration byte at $07FF. Value durations are as follows:<br />
<br />
* `$80` - 8 ticks (sixteenth note)<br />
* `$81` - 24 ticks (dotted eighth note)<br />
* `$82` - 16 ticks (eighth note)<br />
* `$83` - 32 ticks (quarter note)<br />
* `$84` - 48 ticks (dotted quarter note)<br />
* `$85` - 64 ticks (half note)<br />
* `$86` - 96 ticks (dotted half note)<br />
* `$87` - 128 ticks (whole note)<br />
* `$88` - 11 ticks (eighth note triplet, first two)<br />
* `$89` - 10 ticks (eighth note triplet, third)<br />
* `$8A` - 80 ticks (half note + eighth note)<br />
* `$8B` - 256 ticks (two whole notes)<br />
* `$8F` - 6 ticks (dotted 32nd note)<br />
<br />
Note: $8C, $8D and $8E are duplicates, so these could be used for<br />
custom durations if desired.<br />
<br />
The pitch values are much more straightforward. As far as I can tell,<br />
`$4C` is A4 and every semitone away from that adds or subtracts 2 from<br />
the value. Thus, C5 (three semitones above A4) is `$52`. The value<br />
`$02` represents a rest.<br />
<br />
-2- -3- -4- -5- -6- -7-<br />
A : $12 $2A $42 $5A $72<br />
Bb : $14 $2C $44 $5C $74<br />
B : $16 $2E $46 $5E $76<br />
C : $18 $30 $48 $60 $78<br />
C# : $1A $32 $4A $62 $7A<br />
D : $04 $1C $34 $4C $64<br />
Eb : $06 $1E $36 $4E $66<br />
E : $08 $20 $38 $50 $68<br />
F : $0A $22 $3A $52 $6A<br />
F# : $0C $24 $3C $54 $6C<br />
G : $0E $26 $3E $56 $6E<br />
G# : $10 $28 $40 $58 $70<br />
<br />
By way of an example, let's look at the main section of the vanilla<br />
title music. The title metadata starts at bank 6 `$84DA`:<br />
<br />
08 11 14 16 19 1E 1E 1E<br />
^ Main section<br />
<br />
The main section is the fourth song, starting at `$84DA + $16 = $84F0`:<br />
<br />
3F 3F 00<br />
<br />
This means there is a single phrase for the main section, which is<br />
repeated twice. The phrase data is at `$84DA + $3F = $8519`.<br />
<br />
00 3D 86 3A 1A 5F<br />
<br />
From this, we see the melody note data is located at `$863D`:<br />
<br />
83 Quarter notes<br />
02 Rest<br />
48 Ab4<br />
82 Eighth note<br />
46 G4<br />
83 Quarter notes<br />
3E Eb4<br />
34 Bb3<br />
84 Dotted quarter notes<br />
2E G3<br />
83 Quarter notes<br />
30 Ab3<br />
34 Bb3<br />
3A Db4<br />
38 C4<br />
34 Bb3<br />
30 Ab3<br />
82 Eighth notes<br />
34 Bb3<br />
83 Quarter notes<br />
30 Ab3<br />
85 Half notes<br />
2E G3<br />
82 Quarter notes<br />
02 Rest<br />
00 End of Data<br />
<br />
== Main Music Engine ==<br />
<br />
=== Data Tables ===<br />
<br />
There are several data tables used by the music engine.<br />
<br />
==== Pulse Envelope ====<br />
<br />
This table is used to set the volume of the pulse channels over time. The index<br />
used starts at a certain value and decrements, so the table is in reverse order.<br />
The index is halved before use, so each value lasts two frames.<br />
<br />
{| class="wikitable"<br />
|+ Pulse Envelope <code>$9135</code><br />
|90||91||91||91||92||92||92||92<br />
|-<br />
|93||93||94||94||94||95||95||95<br />
|-<br />
|96||96||96||97||97||97||98||98<br />
|}<br />
<br />
==== Duration LUT ====<br />
<br />
This table is used to determine the duration of a note. The note data is stored<br />
with 5 bits of pitch information and 3 bits of duration, as such:<br />
<br />
D1 D0 P4 P3 P2 P1 P0 D2<br />
<br />
The Get Note Duration routine shifts things around to get the D bits into the<br />
three least significant bits and masks it before use. This value is then added<br />
to the tempo value in <code>$E5</code> which is always a multiple of 8 to index<br />
into the following table:<br />
<br />
{| class="wikitable"<br />
|+Duration LUT <code>$914D</code><br />
|'''00'''||04||0C||08||10||18||20||05||06<br />
|-<br />
|'''08'''||04||0F||09||12||1B||24||06||06<br />
|-<br />
|'''10'''||05||0F||0A||14||1E||28||07||06<br />
|-<br />
|'''18'''||06||12||0C||18||24||30||08||10<br />
|-<br />
|'''20'''||07||15||0E||1C||2A||38||13||12<br />
|-<br />
|'''28'''||07||15||0E||1C||2A||38||XX||XX<br />
|}<br />
<br />
The last two values in each row seem a bit strange, as they are not nice<br />
multiples of the first entry which is usually thought of as the length of an<br />
eighth note. They are usually used to make triplets which don't divide evenly by slightly shortening or lengthening the third triplet. The last row doesn't include these two values because they are nonsensical and actually belong to the next LUT anyway. That row is used for the credits music which presumably avoids those last two values.<br />
<br />
==== Pitch LUT ====<br />
<br />
This table is used to detemine the pitch of a note. The note data is stored as<br />
described above, and the fact that the least significant bit is masked out is<br />
advantageous since the pulse channels can use 11 bits of timer data, so each<br />
entry in this table is actually two bytes wide.<br />
<br />
Rather than show the raw bytes here, it's more useful to show the rough note<br />
that those values represent. If the raw values are interesting to you, check<br />
the ROM for them. It's worth noting that some of the higher notes are several<br />
cents off from the listed note.<br />
<br />
{| class="wikitable"<br />
|+Pitch LUT <code>$918F</code><br />
| || 00|| 02|| 04|| 06|| 08|| 0a|| 0c|| 0e<br />
|-<br />
|00|| C3||---|| E3|| G3||G#3|| A3||A#3|| B3<br />
|-<br />
|10|| C4||C#4|| D4||D#4|| E4|| F4||F#4|| G4<br />
|-<br />
|20||G#4|| A4||A#4|| B4|| C5||C#5|| D5||D#5<br />
|-<br />
|30|| E5|| F5||F#5|| G5|| A5||A#5|| B5||C#3<br />
|-<br />
|40|| D3||D#3|| F3||F#3||G#5|| C6||C#6|| D6<br />
|-<br />
|50||D#6|| E6|| F6||F#6|| G6||G#6|| A6||A#6<br />
|-<br />
|60|| B6|| C7||C#7|| D7||D#7|| E7|| F7||F#7<br />
|-<br />
|70|| G7||G#7|| A7||A#7|| B7|| C8<br />
|}<br />
<br />
Value <code>$02</code> represents a rest.<br />
<br />
Note that although the table goes through <code>$7A</code> values above<br />
<code>$3E</code> aren't usable due to the 5 bit limit for pitch data in<br />
the song data. However, the sound effects routines make use of these<br />
extra notes. For example, the sword beam effect alternates between<br />
playing C7 and F6. The title music engine also has a different format which allows use of more of these notes.<br />
<br />
==== Noise Samples ====<br />
<br />
Several sound effects use the same routine to load "samples" for the noise<br />
channel to play. These values have the noise volume in the high nybble and the<br />
noise period in the low nybble.<br />
<br />
$90E8 - Sword slash<br />
$9123 - Enemy hurt<br />
$912C - Crumble block<br />
<br />
=== Variables ===<br />
<br />
This is just a dump of RAM addresses used by the music engine and a short<br />
description of what they are.<br />
<br />
$00E0 - Current phrase note data address (low byte)<br />
$00E1 - Current phrase note data address (high byte)<br />
$00E2 - Song offset, converted from song id to be an index instead of a bit field<br />
$00E3 - Current phrase index<br />
$00E4 - Drums loop start<br />
$00E5 - Tempo<br />
$00E6 - Pulse 1 low bits (used for vibrato effect)<br />
$00E7 - Pulse 2 low bits (used for vibrato effect)<br />
$00E8 - Pitch storage, temporary<br />
$00E9 - Play sound effect<br />
$00EA - Disable music<br />
$00EB - Request new song<br />
$00EC - Play sound effect<br />
$00ED - Play sound effect<br />
$00EE - Play sound effect<br />
$00EF - Play sound effect<br />
<br />
$0707 - Current world<br />
$075F - Queued song, loaded after screen transitions<br />
$07DA - Ganon Laugh sample<br />
$07DB - Song to resume after fanfare<br />
$07DF - ??? Likely sound effect flag for pulse 1 channel override<br />
<br />
$07E0 - ??? Likely sound effect flag for noise channel<br />
$07E2 - Pulse 2 envelope index<br />
$07E3 - Pulse 1 envelope index<br />
$07E4 - Drums current note duration<br />
$07E5 - Bass current note duration<br />
$07E6 - Harmony current note duration<br />
$07E7 - Melody current note duration<br />
$07E8 - Drums next note index<br />
$07E9 - Bass next note index<br />
$07EA - Harmony next note index<br />
$07EB - Melody next note index<br />
<br />
$07EC - Ganon Laugh counter<br />
$07ED - Sound FX counter (E9)<br />
$07EE - Sound FX counter (E9)<br />
$07F5 - Sound FX counter (ED)<br />
<br />
$07FA - Current SFX (E9)<br />
$07FB - Current song<br />
$07FD - Current SFX (ED)<br />
$07FE - ??? Likely sound effect flag for pulse 2 channel override<br />
$07FF - Current SFX (EF)<br />
<br />
=== Routines ===<br />
<br />
This is a non-exhaustive list of the routines in bank 6 involving the playing of<br />
music and sound effects. Each routine also lists its address so you can search<br />
in a disassembly for the actual code for that routine if these descriptions<br />
aren't clear.<br />
<br />
==== Main Music Loop <code>$9000</code> ====<br />
<br />
Checks that the music disable flag is off, then runs several SFX routines.<br />
After the SFX routines, the main music routine runs. After all this, various<br />
music related memory locations are cleared.<br />
<br />
==== Configure Pulse1 Channel <code>$9031</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4000</code> and <code>$4001</code><br />
respectively.<br />
<br />
==== Configure Pulse2 Channel <code>$9038</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4004</code> and <code>$4005</code><br />
respectively.<br />
<br />
==== Play Note Pulse1 <code>$9042</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 1 channel.<br />
<br />
==== Play Note <code>$9044</code> ====<br />
<br />
Called by the various play note routines. Takes a pitch index in register a and<br />
uses register x as a channel selector. For the pulse channels, this routine<br />
also saves the lower 8 bits of the APU timer register to <code>$E6</code> or <code>$E7</code> which<br />
are used for a vibrato effect.<br />
<br />
==== Play Note Pulse2 <code>$9067</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 2 channel.<br />
<br />
==== Play Note Triangle <code>$906B</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the triangle channel.<br />
<br />
==== Get Note Duration <code>$906F</code> ====<br />
<br />
Takes note data in register a and looks up the duration. The original note<br />
data is saved in register x and the result of the duration lookup is put in<br />
register a. The duration lookup is offset by the tempo stored in <code>$E5</code>.<br />
<br />
==== Vibrato Pulse1 <code>$9089</code> ====<br />
<br />
Applies a vibrato effect on the pulse 1 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato Pulse2 <code>$9097</code> ====<br />
<br />
Applies a vibrato effect on the pulse 2 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato <code>$909E</code> ====<br />
<br />
Takes the duration of the note remaining in register a, the low bits of the APU<br />
timer in register y, and the channel to use in register x. This is called by<br />
the other vibrato routines after setting x appropriately.<br />
<br />
Uses the <code>$04</code> bit of the duration to either add or subtract 2 from the low<br />
timer bits. Only the low bits are used because writing to the high bits resets<br />
the phase of the channel which can cause clicks. None of the notes from the<br />
pitch LUT are close enough to the boundary for the change to require the high<br />
bits to change anyway, so this works out fine.<br />
<br />
==== Play E9 SFX <code>$920B</code> ====<br />
<br />
Plays the sound effect requested in <code>$E9</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EF SFX <code>$92F4</code> ====<br />
<br />
Plays the sound effect requested in <code>$EF</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EE SFX <code>$9408</code> ====<br />
<br />
Plays the sound effect requested in <code>$EE</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Noise <code>$959D</code> ====<br />
<br />
Configures the APU noise registers to make a noise burst. Takes configuration<br />
for registers <code>$400F</code>, <code>$400E</code>, and <code>$400C</code> in registers y, x, and a.<br />
<br />
==== Crumble Bridge SFX <code>$956C</code> ====<br />
<br />
Starts playing the sound effect for a crumble bridge crumbling. This uses both<br />
the noise and the triangle channels so it sets flags to disable the music on<br />
those channels. Continues with SFX Noise Decay.<br />
<br />
==== SFX Noise Decay <code>$9587</code> ====<br />
<br />
Counts down the timer in <code>$07F5</code> and turns off the noise when it reaches 0.<br />
Also clears the flag for the ED sound effect in <code>$07FD</code>.<br />
<br />
==== Play ED SFX <code>$95A7</code> ====<br />
<br />
Plays the sound effect request in <code>$ED</code> or continues the sound effect saved in<br />
<code>$07FD</code>. Existing sound effects which are higher than the current sound effect<br />
will be ignored. If the same sound effect is requested that is already playing,<br />
it will restart the sound effect except for <code>$80</code> which gives priority to<br />
continuing. When the sound is continued instead of newly played, the decay<br />
routine will be called instead.<br />
<br />
; <code>$02</code><br />
: Crumble Bridge<br />
; <code>$04</code> and <code>$10</code><br />
: Crumble Block / Enemy Hurt<br />
; <code>$20</code> and <code>$80</code><br />
: Sword Strike<br />
; <code>$40</code><br />
: Very short noise burst, probably unused. Doesn't store the effect, and doesn't have an associated decay.<br />
<br />
==== Crumble Block / Enemy Hurt SFX <code>$95E6</code> ====<br />
<br />
Starts playing the sound of a block breaking or an enemy getting hurt.<br />
<br />
==== Crumble Block / Enemy Hurt SFX Decay <code>$95EE</code> ====<br />
<br />
Looks up noise register values based on the timer and the sound effect value.<br />
Crumble Block samples are at <code>$912C</code> while Enemy Hurt is at <code>$9123</code>. Continues<br />
on to Play Noise Samples.<br />
<br />
==== Play Noise Samples <code>$9612</code> ====<br />
<br />
Takes a sample value in register a. The low four bits of this are used to set<br />
the noise period via APU register <code>$400E</code>. The high four bits are used to set<br />
the noise volume via APU register <code>$400C</code>.<br />
<br />
Continues on the SFX Noise Decay process.<br />
<br />
==== Sword Strike SFX <code>$9604</code> ====<br />
<br />
Starts playing the sound of swinging your sword. This looks up samples based on<br />
the duration left at <code>$90E8</code> and plays them via Play Noise Samples.<br />
<br />
==== Play EC SFX <code>$990B</code> ====<br />
<br />
Plays the sound effect requested in <code>$EC</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Music <code>$9B18</code> ====<br />
<br />
Plays the music for the game.<br />
<br />
Runs Load Song if a new song is requested in <code>$EB</code>. Otherwise, runs Play Notes<br />
if the current song is set in <code>$07FB</code>. If neither of these is true, do nothing.<br />
<br />
==== Next Song <code>$9B24</code> ====<br />
<br />
Checks if the previous song should loop. If not, calls Mute All and returns.<br />
<br />
If the previous song was <code>$01</code> (the "intro" to the main theme), sets the next<br />
song to <code>$02</code> (the main theme loop).<br />
<br />
If the previous song was <code>$10</code> (the item get / level up fanfare), sets the<br />
current song from <code>$07DB</code>. Otherwise, leaves the current song the same as the<br />
previous song.<br />
<br />
Proceeds to Load Song.<br />
<br />
==== Mute All <code>$9B3B</code> ====<br />
<br />
Clears the current song at <code>$07FB</code> and sets the APU registers to mute the volume<br />
on both pulse channels, the triangle channel, and the noise channel.<br />
<br />
==== Load Song <code>$9B61</code> ====<br />
<br />
Takes a song id in register a and preps some variables for that song.<br />
<br />
If the song is <code>$10</code> (item get / level up fanfare) then it first saves the<br />
previous song to <code>$07FB</code> if it is less than <code>$10</code> so that the previous music<br />
will resume after the fanfare.<br />
<br />
Sets the phrase counter at <code>$E3</code> to 0 and the song offset at <code>$E2</code> based on the<br />
song id. Song ids are a bit field, and the song offset is the position of the<br />
lowest bit in the song id for indexing into the song table.<br />
<br />
Proceeds to Load Song Data.<br />
<br />
==== Load Song Data <code>$9B80</code> ====<br />
<br />
Loads the music variables based on the current world and current song offset.<br />
<br />
There are four blocks of code that are basically the same, for each of the four<br />
different music tables. Each one just uses a different position for the tables<br />
to load.<br />
<br />
Based on the current world in <code>$0707</code> it loads data from these offsets:<br />
<br />
<code>$00</code><br />
: Overworld music - <code>$9B87</code><br />
<code>$01</code> or <code>$02</code><br />
: Town music - <code>$9BC6</code><br />
<code>$03</code> or <code>$04</code><br />
: Palace music - <code>$9C05</code><br />
<code>$05</code> or higher<br />
: Great Palace music - <code>$9C42</code><br />
<br />
First, uses the song offset in <code>$E2</code> to index into the song table at the base<br />
offset given above.<br />
<br />
The phrase counter at <code>$E3</code> is added to that and used as in index again to<br />
retrieve the current phrase offset. If the current phrase offset is <code>$00</code> that<br />
means the song is over and the process goes back to the Next Song routine.<br />
<br />
Otherwise, the following structure is read at the base offset above + phrase<br />
offset just calculated.<br />
<br />
* <code>$E5</code> Tempo<br />
* <code>$E0</code> Note Data Low<br />
* <code>$E1</code> Note Data High<br />
* <code>$07E9</code> Bass Note Pointer<br />
* <code>$07EA</code> Harmony Note Pointer<br />
* <code>$07E8</code> Drum Note Pointer<br />
<br />
After this, the drum loop start point at <code>$E4</code> is also set to the same value as<br />
the drum note pointer. The melody note pointer at <code>$07EB</code> is set to <code>$00</code>, and<br />
all the durations (melody at <code>$07E7</code>, harmony at <code>$07E6</code>, bass at <code>$07E5</code>, and<br />
drums at <code>$07E4</code>) are set to <code>$01</code>.<br />
<br />
Proceeds to Play Notes.<br />
<br />
==== Play Notes ====<br />
<br />
This routine is broken into four major and similar sections: one each for<br />
melody, harmony, bass, and drums. The general process is as follows:<br />
<br />
decrement duration<br />
if duration == 0 {<br />
load next note<br />
increment note pointer<br />
set duration for note<br />
if no overriding sound effect {<br />
play note on appropriate channel<br />
}<br />
}<br />
<br />
Some channels have unique processing at different points in this. For example,<br />
the melody note data is null terminated, so if the loaded note in <code>$00</code> then the<br />
routine will jump to Load Song Data instead to go to the next phrase. If the<br />
drums channel gets a <code>$00</code> note it will reset the drums note pointer to the<br />
drums loop start and repeat the phrase. The bass and harmony channels don't<br />
have this looping behavior. This means that if the bass or harmony channels<br />
aren't long enough, the engine will happily just play whatever data comes next<br />
in the ROM.<br />
<br />
The melody is played on pulse 2 channel, the harmony on pulse 1 (which gets<br />
subverted by sound effects that need just one pulse channel), the bass on the<br />
triangle channel, and the drums on the noise channel.<br />
<br />
For the pulse channels, after the note is played, the envelope counter for that<br />
channel (<code>$07E2</code> for pulse 1, <code>$07E3</code> for pulse 2) is set. Normally the<br />
envelope is set to <code>$2F</code> but song <code>$40</code> (crystal fanfare and final boss music)<br />
sets it to <code>$18</code> instead. The envelope is not set if no note was played because<br />
the pitch index was <code>$02</code> which indicates a rest.<br />
<br />
Also for the pulse channels, after the above pseudocode, the vibrato and<br />
enveloping happens as long as there is no overriding sound effect. The envelope<br />
works by checking the envelope counter set previously and decrementing it. The<br />
counter value is halved and used to look up the envelope value in the LUT at<br />
<code>$9135</code>. These values are written directly to APU register <code>$4000</code> or <code>$4004</code><br />
depending on the channel.<br />
<br />
The bass channel has one special handling as well. The APU register <code>$4008</code> is<br />
set differently based on the current song id. For song <code>$10</code> (item get / level<br />
up fanfare) the register is set to <code>$60</code> but all other songs use <code>$1f</code>.<br />
<br />
The noise channel is not affect at all by the pitch. Any pitch value that is<br />
non zero will play a burst of noise.</div>Bentglasstubehttp://wiki.bindingforce.net/index.php?title=Music_Engine_Description&diff=359Music Engine Description2023-08-06T18:50:00Z<p>Bentglasstube: Clarify use of strange durations in duration LUT</p>
<hr />
<div>There are two separate music engines in Zelda 2. Both are in bank 6 (along<br />
with the song data). The music engine for the title screen resides at<br />
<code>$8000</code> and the engine for the rest of the game is at<br />
<code>$9000</code>. Each of these engines is called once per frame during the<br />
appropriate part of the game.<br />
<br />
Changes to the music engine should be very easy to make, as there is an<br />
abundance of free space in bank 6.<br />
<br />
== Title Music Engine ==<br />
<br />
'''TODO''' properly format the following by bgt (original at https://eab.xyz/W2zplGD) and dontbagume (on discord).<br />
<br />
# Title Music Engine<br />
<br />
The title music engine is different from the engine that plays music<br />
during the rest of the game. In particular, it has a wider range of<br />
notes that can be represented. If you want to look into the actual<br />
code, the title screen music engine main loop is at `$8000` (vesus<br />
`$9000` for the game music loop).<br />
<br />
The metadata for the songs is all the same as in the other areas,<br />
although the title music is actually broken up into several songs<br />
itself. These song boundaries control the timing of the title scroll.<br />
<br />
The following songs exist in the title song table:<br />
<br />
1. Intro<br />
2. Start<br />
3. Build up<br />
4. Main<br />
5. Breakdown<br />
<br />
The start of song 2 triggers the title to scroll into view. The start<br />
of song 4 triggers a countdown until the story scroll begins. After<br />
song 5 finishes, the engine loops back to song 2.<br />
<br />
Within the note data, a special format is used. Rather than encoding<br />
the duration and pitch together in a single byte, the title music has<br />
"pitch" bytes and "duration" bytes. Any byte with the highest bit set<br />
(i.e. anything >= `$80`) is interpreted as a duration change, which<br />
sets the duration of all future notes. Anything else is a pitch value<br />
which indicates a note of the current duration should be played. The<br />
low nibble of duration values keys into a lookup table at bank 6 `$8084` <br />
and store the duration byte at $07FF. Value durations are as follows:<br />
<br />
* `$80` - 8 ticks (sixteenth note)<br />
* `$81` - 24 ticks (dotted eighth note)<br />
* `$82` - 16 ticks (eighth note)<br />
* `$83` - 32 ticks (quarter note)<br />
* `$84` - 48 ticks (dotted quarter note)<br />
* `$85` - 64 ticks (half note)<br />
* `$86` - 96 ticks (dotted half note)<br />
* `$87` - 128 ticks (whole note)<br />
* `$88` - 11 ticks (eighth note triplet, first two)<br />
* `$89` - 10 ticks (eighth note triplet, third)<br />
* `$8A` - 80 ticks (half note + eighth note)<br />
* `$8B` - 256 ticks (two whole notes)<br />
* `$8F` - 6 ticks (dotted 32nd note)<br />
<br />
Note: $8C, $8D and $8E are duplicates, so these could be used for<br />
custom durations if desired.<br />
<br />
The pitch values are much more straightforward. As far as I can tell,<br />
`$4C` is A4 and every semitone away from that adds or subtracts 2 from<br />
the value. Thus, C5 (three semitones above A4) is `$52`. The value<br />
`$02` represents a rest.<br />
<br />
-2- -3- -4- -5- -6- -7-<br />
A : $12 $2A $42 $5A $72<br />
Bb : $14 $2C $44 $5C $74<br />
B : $16 $2E $46 $5E $76<br />
C : $18 $30 $48 $60 $78<br />
C# : $1A $32 $4A $62 $7A<br />
D : $04 $1C $34 $4C $64<br />
Eb : $06 $1E $36 $4E $66<br />
E : $08 $20 $38 $50 $68<br />
F : $0A $22 $3A $52 $6A<br />
F# : $0C $24 $3C $54 $6C<br />
G : $0E $26 $3E $56 $6E<br />
G# : $10 $28 $40 $58 $70<br />
<br />
By way of an example, let's look at the main section of the vanilla<br />
title music. The title metadata starts at bank 6 `$84DA`:<br />
<br />
08 11 14 16 19 1E 1E 1E<br />
^ Main section<br />
<br />
The main section is the fourth song, starting at `$84DA + $16 = $84F0`:<br />
<br />
3F 3F 00<br />
<br />
This means there is a single phrase for the main section, which is<br />
repeated twice. The phrase data is at `$84DA + $3F = $8519`.<br />
<br />
00 3D 86 3A 1A 5F<br />
<br />
From this, we see the melody note data is located at `$863D`:<br />
<br />
83 Quarter notes<br />
02 Rest<br />
48 Ab4<br />
82 Eighth note<br />
46 G4<br />
83 Quarter notes<br />
3E Eb4<br />
34 Bb3<br />
84 Dotted quarter notes<br />
2E G3<br />
83 Quarter notes<br />
30 Ab3<br />
34 Bb3<br />
3A Db4<br />
38 C4<br />
34 Bb3<br />
30 Ab3<br />
82 Eighth notes<br />
34 Bb3<br />
83 Quarter notes<br />
30 Ab3<br />
85 Half notes<br />
2E G3<br />
82 Quarter notes<br />
02 Rest<br />
00 End of Data<br />
<br />
== Main Music Engine ==<br />
<br />
=== Data Tables ===<br />
<br />
There are several data tables used by the music engine.<br />
<br />
==== Pulse Envelope ====<br />
<br />
This table is used to set the volume of the pulse channels over time. The index<br />
used starts at a certain value and decrements, so the table is in reverse order.<br />
The index is halved before use, so each value lasts two frames.<br />
<br />
{| class="wikitable"<br />
|+ Pulse Envelope <code>$9135</code><br />
|90||91||91||91||92||92||92||92<br />
|-<br />
|93||93||94||94||94||95||95||95<br />
|-<br />
|96||96||96||97||97||97||98||98<br />
|}<br />
<br />
==== Duration LUT ====<br />
<br />
This table is used to determine the duration of a note. The note data is stored<br />
with 5 bits of pitch information and 3 bits of duration, as such:<br />
<br />
D1 D0 P4 P3 P2 P1 P0 D2<br />
<br />
The Get Note Duration routine shifts things around to get the D bits into the<br />
three least significant bits and masks it before use. This value is then added<br />
to the tempo value in <code>$E5</code> which is always a multiple of 8 to index<br />
into the following table:<br />
<br />
{| class="wikitable"<br />
|+Duration LUT <code>$914D</code><br />
|'''00'''||04||0C||08||10||18||20||05||06<br />
|-<br />
|'''08'''||04||0F||09||12||1B||24||06||06<br />
|-<br />
|'''10'''||05||0F||0A||14||1E||28||07||06<br />
|-<br />
|'''18'''||06||12||0C||18||24||30||08||10<br />
|-<br />
|'''20'''||07||15||0E||1C||2A||38||13||12<br />
|-<br />
|'''28'''||07||15||0E||1C||2A||38||XX||XX<br />
|}<br />
<br />
The last two values in each row seem a bit strange, as they are not nice<br />
multiples of the first entry which is usually thought of as the length of an<br />
eighth note. They are usually used to make triplets which don't divide evenly by slightly shortening or lengthening the third triplet. The last row doesn't include these two values because they are nonsensical and actually belong to the next LUT anyway. That row is used for the credits music which presumably avoids those last two values.<br />
<br />
==== Pitch LUT ====<br />
<br />
This table is used to detemine the pitch of a note. The note data is stored as<br />
described above, and the fact that the least significant bit is masked out is<br />
advantageous since the pulse channels can use 11 bits of timer data, so each<br />
entry in this table is actually two bytes wide.<br />
<br />
Rather than show the raw bytes here, it's more useful to show the rough note<br />
that those values represent. If the raw values are interesting to you, check<br />
the ROM for them. It's worth noting that some of the higher notes are several<br />
cents off from the listed note.<br />
<br />
{| class="wikitable"<br />
|+Pitch LUT <code>$918F</code><br />
| || 00|| 02|| 04|| 06|| 08|| 0a|| 0c|| 0e<br />
|-<br />
|00|| C3||---|| E3|| G3||G#3|| A3||A#3|| B3<br />
|-<br />
|10|| C4||C#4|| D4||D#4|| E4|| F4||F#4|| G4<br />
|-<br />
|20||G#4|| A4||A#4|| B4|| C5||C#5|| D5||D#5<br />
|-<br />
|30|| E5|| F5||F#5|| G5|| A5||A#5|| B5||C#3<br />
|-<br />
|40|| D3||D#3|| F3||F#3||G#5|| C6||C#6|| D6<br />
|-<br />
|50||D#6|| E6|| F6||F#6|| G6||G#6|| A6||A#6<br />
|-<br />
|60|| B6|| C7||C#7|| D7||D#7|| E7|| F7||F#7<br />
|-<br />
|70|| G7||G#7|| A7||A#7|| B7|| C8<br />
|}<br />
<br />
Value <code>$02</code> represents a rest.<br />
<br />
Note that although the table goes through <code>$7A</code> values above<br />
<code>$3E</code> aren't usable due to the 5 bit limit for pitch data in<br />
the song data. However, the sound effects routines make use of these<br />
extra notes. For example, the sword beam effect alternates between<br />
playing C7 and F6.<br />
<br />
==== Noise Samples ====<br />
<br />
Several sound effects use the same routine to load "samples" for the noise<br />
channel to play. These values have the noise volume in the high nybble and the<br />
noise period in the low nybble.<br />
<br />
$90E8 - Sword slash<br />
$9123 - Enemy hurt<br />
$912C - Crumble block<br />
<br />
=== Variables ===<br />
<br />
This is just a dump of RAM addresses used by the music engine and a short<br />
description of what they are.<br />
<br />
$00E0 - Current phrase note data address (low byte)<br />
$00E1 - Current phrase note data address (high byte)<br />
$00E2 - Song offset, converted from song id to be an index instead of a bit field<br />
$00E3 - Current phrase index<br />
$00E4 - Drums loop start<br />
$00E5 - Tempo<br />
$00E6 - Pulse 1 low bits (used for vibrato effect)<br />
$00E7 - Pulse 2 low bits (used for vibrato effect)<br />
$00E8 - Pitch storage, temporary<br />
$00E9 - Play sound effect<br />
$00EA - Disable music<br />
$00EB - Request new song<br />
$00EC - Play sound effect<br />
$00ED - Play sound effect<br />
$00EE - Play sound effect<br />
$00EF - Play sound effect<br />
<br />
$0707 - Current world<br />
$075F - Queued song, loaded after screen transitions<br />
$07DA - Ganon Laugh sample<br />
$07DB - Song to resume after fanfare<br />
$07DF - ??? Likely sound effect flag for pulse 1 channel override<br />
<br />
$07E0 - ??? Likely sound effect flag for noise channel<br />
$07E2 - Pulse 2 envelope index<br />
$07E3 - Pulse 1 envelope index<br />
$07E4 - Drums current note duration<br />
$07E5 - Bass current note duration<br />
$07E6 - Harmony current note duration<br />
$07E7 - Melody current note duration<br />
$07E8 - Drums next note index<br />
$07E9 - Bass next note index<br />
$07EA - Harmony next note index<br />
$07EB - Melody next note index<br />
<br />
$07EC - Ganon Laugh counter<br />
$07ED - Sound FX counter (E9)<br />
$07EE - Sound FX counter (E9)<br />
$07F5 - Sound FX counter (ED)<br />
<br />
$07FA - Current SFX (E9)<br />
$07FB - Current song<br />
$07FD - Current SFX (ED)<br />
$07FE - ??? Likely sound effect flag for pulse 2 channel override<br />
$07FF - Current SFX (EF)<br />
<br />
=== Routines ===<br />
<br />
This is a non-exhaustive list of the routines in bank 6 involving the playing of<br />
music and sound effects. Each routine also lists its address so you can search<br />
in a disassembly for the actual code for that routine if these descriptions<br />
aren't clear.<br />
<br />
==== Main Music Loop <code>$9000</code> ====<br />
<br />
Checks that the music disable flag is off, then runs several SFX routines.<br />
After the SFX routines, the main music routine runs. After all this, various<br />
music related memory locations are cleared.<br />
<br />
==== Configure Pulse1 Channel <code>$9031</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4000</code> and <code>$4001</code><br />
respectively.<br />
<br />
==== Configure Pulse2 Channel <code>$9038</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4004</code> and <code>$4005</code><br />
respectively.<br />
<br />
==== Play Note Pulse1 <code>$9042</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 1 channel.<br />
<br />
==== Play Note <code>$9044</code> ====<br />
<br />
Called by the various play note routines. Takes a pitch index in register a and<br />
uses register x as a channel selector. For the pulse channels, this routine<br />
also saves the lower 8 bits of the APU timer register to <code>$E6</code> or <code>$E7</code> which<br />
are used for a vibrato effect.<br />
<br />
==== Play Note Pulse2 <code>$9067</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 2 channel.<br />
<br />
==== Play Note Triangle <code>$906B</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the triangle channel.<br />
<br />
==== Get Note Duration <code>$906F</code> ====<br />
<br />
Takes note data in register a and looks up the duration. The original note<br />
data is saved in register x and the result of the duration lookup is put in<br />
register a. The duration lookup is offset by the tempo stored in <code>$E5</code>.<br />
<br />
==== Vibrato Pulse1 <code>$9089</code> ====<br />
<br />
Applies a vibrato effect on the pulse 1 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato Pulse2 <code>$9097</code> ====<br />
<br />
Applies a vibrato effect on the pulse 2 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato <code>$909E</code> ====<br />
<br />
Takes the duration of the note remaining in register a, the low bits of the APU<br />
timer in register y, and the channel to use in register x. This is called by<br />
the other vibrato routines after setting x appropriately.<br />
<br />
Uses the <code>$04</code> bit of the duration to either add or subtract 2 from the low<br />
timer bits. Only the low bits are used because writing to the high bits resets<br />
the phase of the channel which can cause clicks. None of the notes from the<br />
pitch LUT are close enough to the boundary for the change to require the high<br />
bits to change anyway, so this works out fine.<br />
<br />
==== Play E9 SFX <code>$920B</code> ====<br />
<br />
Plays the sound effect requested in <code>$E9</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EF SFX <code>$92F4</code> ====<br />
<br />
Plays the sound effect requested in <code>$EF</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EE SFX <code>$9408</code> ====<br />
<br />
Plays the sound effect requested in <code>$EE</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Noise <code>$959D</code> ====<br />
<br />
Configures the APU noise registers to make a noise burst. Takes configuration<br />
for registers <code>$400F</code>, <code>$400E</code>, and <code>$400C</code> in registers y, x, and a.<br />
<br />
==== Crumble Bridge SFX <code>$956C</code> ====<br />
<br />
Starts playing the sound effect for a crumble bridge crumbling. This uses both<br />
the noise and the triangle channels so it sets flags to disable the music on<br />
those channels. Continues with SFX Noise Decay.<br />
<br />
==== SFX Noise Decay <code>$9587</code> ====<br />
<br />
Counts down the timer in <code>$07F5</code> and turns off the noise when it reaches 0.<br />
Also clears the flag for the ED sound effect in <code>$07FD</code>.<br />
<br />
==== Play ED SFX <code>$95A7</code> ====<br />
<br />
Plays the sound effect request in <code>$ED</code> or continues the sound effect saved in<br />
<code>$07FD</code>. Existing sound effects which are higher than the current sound effect<br />
will be ignored. If the same sound effect is requested that is already playing,<br />
it will restart the sound effect except for <code>$80</code> which gives priority to<br />
continuing. When the sound is continued instead of newly played, the decay<br />
routine will be called instead.<br />
<br />
; <code>$02</code><br />
: Crumble Bridge<br />
; <code>$04</code> and <code>$10</code><br />
: Crumble Block / Enemy Hurt<br />
; <code>$20</code> and <code>$80</code><br />
: Sword Strike<br />
; <code>$40</code><br />
: Very short noise burst, probably unused. Doesn't store the effect, and doesn't have an associated decay.<br />
<br />
==== Crumble Block / Enemy Hurt SFX <code>$95E6</code> ====<br />
<br />
Starts playing the sound of a block breaking or an enemy getting hurt.<br />
<br />
==== Crumble Block / Enemy Hurt SFX Decay <code>$95EE</code> ====<br />
<br />
Looks up noise register values based on the timer and the sound effect value.<br />
Crumble Block samples are at <code>$912C</code> while Enemy Hurt is at <code>$9123</code>. Continues<br />
on to Play Noise Samples.<br />
<br />
==== Play Noise Samples <code>$9612</code> ====<br />
<br />
Takes a sample value in register a. The low four bits of this are used to set<br />
the noise period via APU register <code>$400E</code>. The high four bits are used to set<br />
the noise volume via APU register <code>$400C</code>.<br />
<br />
Continues on the SFX Noise Decay process.<br />
<br />
==== Sword Strike SFX <code>$9604</code> ====<br />
<br />
Starts playing the sound of swinging your sword. This looks up samples based on<br />
the duration left at <code>$90E8</code> and plays them via Play Noise Samples.<br />
<br />
==== Play EC SFX <code>$990B</code> ====<br />
<br />
Plays the sound effect requested in <code>$EC</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Music <code>$9B18</code> ====<br />
<br />
Plays the music for the game.<br />
<br />
Runs Load Song if a new song is requested in <code>$EB</code>. Otherwise, runs Play Notes<br />
if the current song is set in <code>$07FB</code>. If neither of these is true, do nothing.<br />
<br />
==== Next Song <code>$9B24</code> ====<br />
<br />
Checks if the previous song should loop. If not, calls Mute All and returns.<br />
<br />
If the previous song was <code>$01</code> (the "intro" to the main theme), sets the next<br />
song to <code>$02</code> (the main theme loop).<br />
<br />
If the previous song was <code>$10</code> (the item get / level up fanfare), sets the<br />
current song from <code>$07DB</code>. Otherwise, leaves the current song the same as the<br />
previous song.<br />
<br />
Proceeds to Load Song.<br />
<br />
==== Mute All <code>$9B3B</code> ====<br />
<br />
Clears the current song at <code>$07FB</code> and sets the APU registers to mute the volume<br />
on both pulse channels, the triangle channel, and the noise channel.<br />
<br />
==== Load Song <code>$9B61</code> ====<br />
<br />
Takes a song id in register a and preps some variables for that song.<br />
<br />
If the song is <code>$10</code> (item get / level up fanfare) then it first saves the<br />
previous song to <code>$07FB</code> if it is less than <code>$10</code> so that the previous music<br />
will resume after the fanfare.<br />
<br />
Sets the phrase counter at <code>$E3</code> to 0 and the song offset at <code>$E2</code> based on the<br />
song id. Song ids are a bit field, and the song offset is the position of the<br />
lowest bit in the song id for indexing into the song table.<br />
<br />
Proceeds to Load Song Data.<br />
<br />
==== Load Song Data <code>$9B80</code> ====<br />
<br />
Loads the music variables based on the current world and current song offset.<br />
<br />
There are four blocks of code that are basically the same, for each of the four<br />
different music tables. Each one just uses a different position for the tables<br />
to load.<br />
<br />
Based on the current world in <code>$0707</code> it loads data from these offsets:<br />
<br />
<code>$00</code><br />
: Overworld music - <code>$9B87</code><br />
<code>$01</code> or <code>$02</code><br />
: Town music - <code>$9BC6</code><br />
<code>$03</code> or <code>$04</code><br />
: Palace music - <code>$9C05</code><br />
<code>$05</code> or higher<br />
: Great Palace music - <code>$9C42</code><br />
<br />
First, uses the song offset in <code>$E2</code> to index into the song table at the base<br />
offset given above.<br />
<br />
The phrase counter at <code>$E3</code> is added to that and used as in index again to<br />
retrieve the current phrase offset. If the current phrase offset is <code>$00</code> that<br />
means the song is over and the process goes back to the Next Song routine.<br />
<br />
Otherwise, the following structure is read at the base offset above + phrase<br />
offset just calculated.<br />
<br />
* <code>$E5</code> Tempo<br />
* <code>$E0</code> Note Data Low<br />
* <code>$E1</code> Note Data High<br />
* <code>$07E9</code> Bass Note Pointer<br />
* <code>$07EA</code> Harmony Note Pointer<br />
* <code>$07E8</code> Drum Note Pointer<br />
<br />
After this, the drum loop start point at <code>$E4</code> is also set to the same value as<br />
the drum note pointer. The melody note pointer at <code>$07EB</code> is set to <code>$00</code>, and<br />
all the durations (melody at <code>$07E7</code>, harmony at <code>$07E6</code>, bass at <code>$07E5</code>, and<br />
drums at <code>$07E4</code>) are set to <code>$01</code>.<br />
<br />
Proceeds to Play Notes.<br />
<br />
==== Play Notes ====<br />
<br />
This routine is broken into four major and similar sections: one each for<br />
melody, harmony, bass, and drums. The general process is as follows:<br />
<br />
decrement duration<br />
if duration == 0 {<br />
load next note<br />
increment note pointer<br />
set duration for note<br />
if no overriding sound effect {<br />
play note on appropriate channel<br />
}<br />
}<br />
<br />
Some channels have unique processing at different points in this. For example,<br />
the melody note data is null terminated, so if the loaded note in <code>$00</code> then the<br />
routine will jump to Load Song Data instead to go to the next phrase. If the<br />
drums channel gets a <code>$00</code> note it will reset the drums note pointer to the<br />
drums loop start and repeat the phrase. The bass and harmony channels don't<br />
have this looping behavior. This means that if the bass or harmony channels<br />
aren't long enough, the engine will happily just play whatever data comes next<br />
in the ROM.<br />
<br />
The melody is played on pulse 2 channel, the harmony on pulse 1 (which gets<br />
subverted by sound effects that need just one pulse channel), the bass on the<br />
triangle channel, and the drums on the noise channel.<br />
<br />
For the pulse channels, after the note is played, the envelope counter for that<br />
channel (<code>$07E2</code> for pulse 1, <code>$07E3</code> for pulse 2) is set. Normally the<br />
envelope is set to <code>$2F</code> but song <code>$40</code> (crystal fanfare and final boss music)<br />
sets it to <code>$18</code> instead. The envelope is not set if no note was played because<br />
the pitch index was <code>$02</code> which indicates a rest.<br />
<br />
Also for the pulse channels, after the above pseudocode, the vibrato and<br />
enveloping happens as long as there is no overriding sound effect. The envelope<br />
works by checking the envelope counter set previously and decrementing it. The<br />
counter value is halved and used to look up the envelope value in the LUT at<br />
<code>$9135</code>. These values are written directly to APU register <code>$4000</code> or <code>$4004</code><br />
depending on the channel.<br />
<br />
The bass channel has one special handling as well. The APU register <code>$4008</code> is<br />
set differently based on the current song id. For song <code>$10</code> (item get / level<br />
up fanfare) the register is set to <code>$60</code> but all other songs use <code>$1f</code>.<br />
<br />
The noise channel is not affect at all by the pitch. Any pitch value that is<br />
non zero will play a burst of noise.</div>Bentglasstubehttp://wiki.bindingforce.net/index.php?title=Music_Engine_Description&diff=338Music Engine Description2021-09-26T14:16:33Z<p>Bentglasstube: /* Pitch LUT */ Add note about SFX using higher pitches.</p>
<hr />
<div>There are two separate music engines in Zelda 2. Both are in bank 6 (along<br />
with the song data). The music engine for the title screen resides at<br />
<code>$8000</code> and the engine for the rest of the game is at<br />
<code>$9000</code>. Each of these engines is called once per frame during the<br />
appropriate part of the game.<br />
<br />
Changes to the music engine should be very easy to make, as there is an<br />
abundance of free space in bank 6.<br />
<br />
== Title Music Engine ==<br />
<br />
'''TODO''' document further.<br />
<br />
== Main Music Engine ==<br />
<br />
=== Data Tables ===<br />
<br />
There are several data tables used by the music engine.<br />
<br />
==== Pulse Envelope ====<br />
<br />
This table is used to set the volume of the pulse channels over time. The index<br />
used starts at a certain value and decrements, so the table is in reverse order.<br />
The index is halved before use, so each value lasts two frames.<br />
<br />
{| class="wikitable"<br />
|+ Pulse Envelope <code>$9135</code><br />
|90||91||91||91||92||92||92||92<br />
|-<br />
|93||93||94||94||94||95||95||95<br />
|-<br />
|96||96||96||97||97||97||98||98<br />
|}<br />
<br />
==== Duration LUT ====<br />
<br />
This table is used to determine the duration of a note. The note data is stored<br />
with 5 bits of pitch information and 3 bits of duration, as such:<br />
<br />
D1 D0 P4 P3 P2 P1 P0 D2<br />
<br />
The Get Note Duration routine shifts things around to get the D bits into the<br />
three least significant bits and masks it before use. This value is then added<br />
to the tempo value in <code>$E5</code> which is always a multiple of 8 to index<br />
into the following table:<br />
<br />
{| class="wikitable"<br />
|+Duration LUT <code>$914D</code><br />
|'''00'''||04||0C||08||10||18||20||05||06<br />
|-<br />
|'''08'''||04||0F||09||12||1B||24||06||06<br />
|-<br />
|'''10'''||05||0F||0A||14||1E||28||07||06<br />
|-<br />
|'''18'''||06||12||0C||18||24||30||08||10<br />
|-<br />
|'''20'''||07||15||0E||1C||2A||38||13||12<br />
|-<br />
|'''28'''||07||15||0E||1C||2A||38||XX||XX<br />
|}<br />
<br />
The last two values in each row seem a bit strange, as they are not nice<br />
multiples of the first entry which is usually thought of as the length of an<br />
eighth note. The last row has garbage values in those positions as that is the<br />
start of another data table, so they are not even listed here.<br />
<br />
'''TODO''' Check what values are used in vanilla.<br />
<br />
==== Pitch LUT ====<br />
<br />
This table is used to detemine the pitch of a note. The note data is stored as<br />
described above, and the fact that the least significant bit is masked out is<br />
advantageous since the pulse channels can use 11 bits of timer data, so each<br />
entry in this table is actually two bytes wide.<br />
<br />
Rather than show the raw bytes here, it's more useful to show the rough note<br />
that those values represent. If the raw values are interesting to you, check<br />
the ROM for them. It's worth noting that some of the higher notes are several<br />
cents off from the listed note.<br />
<br />
{| class="wikitable"<br />
|+Pitch LUT <code>$918F</code><br />
| || 00|| 02|| 04|| 06|| 08|| 0a|| 0c|| 0e<br />
|-<br />
|00|| C3||---|| E3|| G3||G#3|| A3||A#3|| B3<br />
|-<br />
|10|| C4||C#4|| D4||D#4|| E4|| F4||F#4|| G4<br />
|-<br />
|20||G#4|| A4||A#4|| B4|| C5||C#5|| D5||D#5<br />
|-<br />
|30|| E5|| F5||F#5|| G5|| A5||A#5|| B5||C#3<br />
|-<br />
|40|| D3||D#3|| F3||F#3||G#5|| C6||C#6|| D6<br />
|-<br />
|50||D#6|| E6|| F6||F#6|| G6||G#6|| A6||A#6<br />
|-<br />
|60|| B6|| C7||C#7|| D7||D#7|| E7|| F7||F#7<br />
|-<br />
|70|| G7||G#7|| A7||A#7|| B7|| C8<br />
|}<br />
<br />
Value <code>$02</code> represents a rest.<br />
<br />
Note that although the table goes through <code>$7A</code> values above<br />
<code>$3E</code> aren't usable due to the 5 bit limit for pitch data in<br />
the song data. However, the sound effects routines make use of these<br />
extra notes. For example, the sword beam effect alternates between<br />
playing C7 and F6.<br />
<br />
==== Noise Samples ====<br />
<br />
Several sound effects use the same routine to load "samples" for the noise<br />
channel to play. These values have the noise volume in the high nybble and the<br />
noise period in the low nybble.<br />
<br />
$90E8 - Sword slash<br />
$9123 - Enemy hurt<br />
$912C - Crumble block<br />
<br />
=== Variables ===<br />
<br />
This is just a dump of RAM addresses used by the music engine and a short<br />
description of what they are.<br />
<br />
$00E0 - Current phrase note data address (low byte)<br />
$00E1 - Current phrase note data address (high byte)<br />
$00E2 - Song offset, converted from song id to be an index instead of a bit field<br />
$00E3 - Current phrase index<br />
$00E4 - Drums loop start<br />
$00E5 - Tempo<br />
$00E6 - Pulse 1 low bits (used for vibrato effect)<br />
$00E7 - Pulse 2 low bits (used for vibrato effect)<br />
$00E8 - Pitch storage, temporary<br />
$00E9 - Play sound effect<br />
$00EA - Disable music<br />
$00EB - Request new song<br />
$00EC - Play sound effect<br />
$00ED - Play sound effect<br />
$00EE - Play sound effect<br />
$00EF - Play sound effect<br />
<br />
$0707 - Current world<br />
$075F - Queued song, loaded after screen transitions<br />
$07DA - Ganon Laugh sample<br />
$07DB - Song to resume after fanfare<br />
$07DF - ??? Likely sound effect flag for pulse 1 channel override<br />
<br />
$07E0 - ??? Likely sound effect flag for noise channel<br />
$07E2 - Pulse 2 envelope index<br />
$07E3 - Pulse 1 envelope index<br />
$07E4 - Drums current note duration<br />
$07E5 - Bass current note duration<br />
$07E6 - Harmony current note duration<br />
$07E7 - Melody current note duration<br />
$07E8 - Drums next note index<br />
$07E9 - Bass next note index<br />
$07EA - Harmony next note index<br />
$07EB - Melody next note index<br />
<br />
$07EC - Ganon Laugh counter<br />
$07ED - Sound FX counter (E9)<br />
$07EE - Sound FX counter (E9)<br />
$07F5 - Sound FX counter (ED)<br />
<br />
$07FA - Current SFX (E9)<br />
$07FB - Current song<br />
$07FD - Current SFX (ED)<br />
$07FE - ??? Likely sound effect flag for pulse 2 channel override<br />
$07FF - Current SFX (EF)<br />
<br />
=== Routines ===<br />
<br />
This is a non-exhaustive list of the routines in bank 6 involving the playing of<br />
music and sound effects. Each routine also lists its address so you can search<br />
in a disassembly for the actual code for that routine if these descriptions<br />
aren't clear.<br />
<br />
==== Main Music Loop <code>$9000</code> ====<br />
<br />
Checks that the music disable flag is off, then runs several SFX routines.<br />
After the SFX routines, the main music routine runs. After all this, various<br />
music related memory locations are cleared.<br />
<br />
==== Configure Pulse1 Channel <code>$9031</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4000</code> and <code>$4001</code><br />
respectively.<br />
<br />
==== Configure Pulse2 Channel <code>$9038</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4004</code> and <code>$4005</code><br />
respectively.<br />
<br />
==== Play Note Pulse1 <code>$9042</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 1 channel.<br />
<br />
==== Play Note <code>$9044</code> ====<br />
<br />
Called by the various play note routines. Takes a pitch index in register a and<br />
uses register x as a channel selector. For the pulse channels, this routine<br />
also saves the lower 8 bits of the APU timer register to <code>$E6</code> or <code>$E7</code> which<br />
are used for a vibrato effect.<br />
<br />
==== Play Note Pulse2 <code>$9067</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 2 channel.<br />
<br />
==== Play Note Triangle <code>$906B</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the triangle channel.<br />
<br />
==== Get Note Duration <code>$906F</code> ====<br />
<br />
Takes note data in register a and looks up the duration. The original note<br />
data is saved in register x and the result of the duration lookup is put in<br />
register a. The duration lookup is offset by the tempo stored in <code>$E5</code>.<br />
<br />
==== Vibrato Pulse1 <code>$9089</code> ====<br />
<br />
Applies a vibrato effect on the pulse 1 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato Pulse2 <code>$9097</code> ====<br />
<br />
Applies a vibrato effect on the pulse 2 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato <code>$909E</code> ====<br />
<br />
Takes the duration of the note remaining in register a, the low bits of the APU<br />
timer in register y, and the channel to use in register x. This is called by<br />
the other vibrato routines after setting x appropriately.<br />
<br />
Uses the <code>$04</code> bit of the duration to either add or subtract 2 from the low<br />
timer bits. Only the low bits are used because writing to the high bits resets<br />
the phase of the channel which can cause clicks. None of the notes from the<br />
pitch LUT are close enough to the boundary for the change to require the high<br />
bits to change anyway, so this works out fine.<br />
<br />
==== Play E9 SFX <code>$920B</code> ====<br />
<br />
Plays the sound effect requested in <code>$E9</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EF SFX <code>$92F4</code> ====<br />
<br />
Plays the sound effect requested in <code>$EF</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EE SFX <code>$9408</code> ====<br />
<br />
Plays the sound effect requested in <code>$EE</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Noise <code>$959D</code> ====<br />
<br />
Configures the APU noise registers to make a noise burst. Takes configuration<br />
for registers <code>$400F</code>, <code>$400E</code>, and <code>$400C</code> in registers y, x, and a.<br />
<br />
==== Crumble Bridge SFX <code>$956C</code> ====<br />
<br />
Starts playing the sound effect for a crumble bridge crumbling. This uses both<br />
the noise and the triangle channels so it sets flags to disable the music on<br />
those channels. Continues with SFX Noise Decay.<br />
<br />
==== SFX Noise Decay <code>$9587</code> ====<br />
<br />
Counts down the timer in <code>$07F5</code> and turns off the noise when it reaches 0.<br />
Also clears the flag for the ED sound effect in <code>$07FD</code>.<br />
<br />
==== Play ED SFX <code>$95A7</code> ====<br />
<br />
Plays the sound effect request in <code>$ED</code> or continues the sound effect saved in<br />
<code>$07FD</code>. Existing sound effects which are higher than the current sound effect<br />
will be ignored. If the same sound effect is requested that is already playing,<br />
it will restart the sound effect except for <code>$80</code> which gives priority to<br />
continuing. When the sound is continued instead of newly played, the decay<br />
routine will be called instead.<br />
<br />
; <code>$02</code><br />
: Crumble Bridge<br />
; <code>$04</code> and <code>$10</code><br />
: Crumble Block / Enemy Hurt<br />
; <code>$20</code> and <code>$80</code><br />
: Sword Strike<br />
; <code>$40</code><br />
: Very short noise burst, probably unused. Doesn't store the effect, and doesn't have an associated decay.<br />
<br />
==== Crumble Block / Enemy Hurt SFX <code>$95E6</code> ====<br />
<br />
Starts playing the sound of a block breaking or an enemy getting hurt.<br />
<br />
==== Crumble Block / Enemy Hurt SFX Decay <code>$95EE</code> ====<br />
<br />
Looks up noise register values based on the timer and the sound effect value.<br />
Crumble Block samples are at <code>$912C</code> while Enemy Hurt is at <code>$9123</code>. Continues<br />
on to Play Noise Samples.<br />
<br />
==== Play Noise Samples <code>$9612</code> ====<br />
<br />
Takes a sample value in register a. The low four bits of this are used to set<br />
the noise period via APU register <code>$400E</code>. The high four bits are used to set<br />
the noise volume via APU register <code>$400C</code>.<br />
<br />
Continues on the SFX Noise Decay process.<br />
<br />
==== Sword Strike SFX <code>$9604</code> ====<br />
<br />
Starts playing the sound of swinging your sword. This looks up samples based on<br />
the duration left at <code>$90E8</code> and plays them via Play Noise Samples.<br />
<br />
==== Play EC SFX <code>$990B</code> ====<br />
<br />
Plays the sound effect requested in <code>$EC</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Music <code>$9B18</code> ====<br />
<br />
Plays the music for the game.<br />
<br />
Runs Load Song if a new song is requested in <code>$EB</code>. Otherwise, runs Play Notes<br />
if the current song is set in <code>$07FB</code>. If neither of these is true, do nothing.<br />
<br />
==== Next Song <code>$9B24</code> ====<br />
<br />
Checks if the previous song should loop. If not, calls Mute All and returns.<br />
<br />
If the previous song was <code>$01</code> (the "intro" to the main theme), sets the next<br />
song to <code>$02</code> (the main theme loop).<br />
<br />
If the previous song was <code>$10</code> (the item get / level up fanfare), sets the<br />
current song from <code>$07DB</code>. Otherwise, leaves the current song the same as the<br />
previous song.<br />
<br />
Proceeds to Load Song.<br />
<br />
==== Mute All <code>$9B3B</code> ====<br />
<br />
Clears the current song at <code>$07FB</code> and sets the APU registers to mute the volume<br />
on both pulse channels, the triangle channel, and the noise channel.<br />
<br />
==== Load Song <code>$9B61</code> ====<br />
<br />
Takes a song id in register a and preps some variables for that song.<br />
<br />
If the song is <code>$10</code> (item get / level up fanfare) then it first saves the<br />
previous song to <code>$07FB</code> if it is less than <code>$10</code> so that the previous music<br />
will resume after the fanfare.<br />
<br />
Sets the phrase counter at <code>$E3</code> to 0 and the song offset at <code>$E2</code> based on the<br />
song id. Song ids are a bit field, and the song offset is the position of the<br />
lowest bit in the song id for indexing into the song table.<br />
<br />
Proceeds to Load Song Data.<br />
<br />
==== Load Song Data <code>$9B80</code> ====<br />
<br />
Loads the music variables based on the current world and current song offset.<br />
<br />
There are four blocks of code that are basically the same, for each of the four<br />
different music tables. Each one just uses a different position for the tables<br />
to load.<br />
<br />
Based on the current world in <code>$0707</code> it loads data from these offsets:<br />
<br />
<code>$00</code><br />
: Overworld music - <code>$9B87</code><br />
<code>$01</code> or <code>$02</code><br />
: Town music - <code>$9BC6</code><br />
<code>$03</code> or <code>$04</code><br />
: Palace music - <code>$9C05</code><br />
<code>$05</code> or higher<br />
: Great Palace music - <code>$9C42</code><br />
<br />
First, uses the song offset in <code>$E2</code> to index into the song table at the base<br />
offset given above.<br />
<br />
The phrase counter at <code>$E3</code> is added to that and used as in index again to<br />
retrieve the current phrase offset. If the current phrase offset is <code>$00</code> that<br />
means the song is over and the process goes back to the Next Song routine.<br />
<br />
Otherwise, the following structure is read at the base offset above + phrase<br />
offset just calculated.<br />
<br />
* <code>$E5</code> Tempo<br />
* <code>$E0</code> Note Data Low<br />
* <code>$E1</code> Note Data High<br />
* <code>$07E9</code> Bass Note Pointer<br />
* <code>$07EA</code> Harmony Note Pointer<br />
* <code>$07E8</code> Drum Note Pointer<br />
<br />
After this, the drum loop start point at <code>$E4</code> is also set to the same value as<br />
the drum note pointer. The melody note pointer at <code>$07EB</code> is set to <code>$00</code>, and<br />
all the durations (melody at <code>$07E7</code>, harmony at <code>$07E6</code>, bass at <code>$07E5</code>, and<br />
drums at <code>$07E4</code>) are set to <code>$01</code>.<br />
<br />
Proceeds to Play Notes.<br />
<br />
==== Play Notes ====<br />
<br />
This routine is broken into four major and similar sections: one each for<br />
melody, harmony, bass, and drums. The general process is as follows:<br />
<br />
decrement duration<br />
if duration == 0 {<br />
load next note<br />
increment note pointer<br />
set duration for note<br />
if no overriding sound effect {<br />
play note on appropriate channel<br />
}<br />
}<br />
<br />
Some channels have unique processing at different points in this. For example,<br />
the melody note data is null terminated, so if the loaded note in <code>$00</code> then the<br />
routine will jump to Load Song Data instead to go to the next phrase. If the<br />
drums channel gets a <code>$00</code> note it will reset the drums note pointer to the<br />
drums loop start and repeat the phrase. The bass and harmony channels don't<br />
have this looping behavior. This means that if the bass or harmony channels<br />
aren't long enough, the engine will happily just play whatever data comes next<br />
in the ROM.<br />
<br />
The melody is played on pulse 2 channel, the harmony on pulse 1 (which gets<br />
subverted by sound effects that need just one pulse channel), the bass on the<br />
triangle channel, and the drums on the noise channel.<br />
<br />
For the pulse channels, after the note is played, the envelope counter for that<br />
channel (<code>$07E2</code> for pulse 1, <code>$07E3</code> for pulse 2) is set. Normally the<br />
envelope is set to <code>$2F</code> but song <code>$40</code> (crystal fanfare and final boss music)<br />
sets it to <code>$18</code> instead. The envelope is not set if no note was played because<br />
the pitch index was <code>$02</code> which indicates a rest.<br />
<br />
Also for the pulse channels, after the above pseudocode, the vibrato and<br />
enveloping happens as long as there is no overriding sound effect. The envelope<br />
works by checking the envelope counter set previously and decrementing it. The<br />
counter value is halved and used to look up the envelope value in the LUT at<br />
<code>$9135</code>. These values are written directly to APU register <code>$4000</code> or <code>$4004</code><br />
depending on the channel.<br />
<br />
The bass channel has one special handling as well. The APU register <code>$4008</code> is<br />
set differently based on the current song id. For song <code>$10</code> (item get / level<br />
up fanfare) the register is set to <code>$60</code> but all other songs use <code>$1f</code>.<br />
<br />
The noise channel is not affect at all by the pitch. Any pitch value that is<br />
non zero will play a burst of noise.</div>Bentglasstubehttp://wiki.bindingforce.net/index.php?title=Music_Engine_Description&diff=337Music Engine Description2021-09-26T07:04:27Z<p>Bentglasstube: /* Variables */</p>
<hr />
<div>There are two separate music engines in Zelda 2. Both are in bank 6 (along<br />
with the song data). The music engine for the title screen resides at<br />
<code>$8000</code> and the engine for the rest of the game is at<br />
<code>$9000</code>. Each of these engines is called once per frame during the<br />
appropriate part of the game.<br />
<br />
Changes to the music engine should be very easy to make, as there is an<br />
abundance of free space in bank 6.<br />
<br />
== Title Music Engine ==<br />
<br />
'''TODO''' document further.<br />
<br />
== Main Music Engine ==<br />
<br />
=== Data Tables ===<br />
<br />
There are several data tables used by the music engine.<br />
<br />
==== Pulse Envelope ====<br />
<br />
This table is used to set the volume of the pulse channels over time. The index<br />
used starts at a certain value and decrements, so the table is in reverse order.<br />
The index is halved before use, so each value lasts two frames.<br />
<br />
{| class="wikitable"<br />
|+ Pulse Envelope <code>$9135</code><br />
|90||91||91||91||92||92||92||92<br />
|-<br />
|93||93||94||94||94||95||95||95<br />
|-<br />
|96||96||96||97||97||97||98||98<br />
|}<br />
<br />
==== Duration LUT ====<br />
<br />
This table is used to determine the duration of a note. The note data is stored<br />
with 5 bits of pitch information and 3 bits of duration, as such:<br />
<br />
D1 D0 P4 P3 P2 P1 P0 D2<br />
<br />
The Get Note Duration routine shifts things around to get the D bits into the<br />
three least significant bits and masks it before use. This value is then added<br />
to the tempo value in <code>$E5</code> which is always a multiple of 8 to index<br />
into the following table:<br />
<br />
{| class="wikitable"<br />
|+Duration LUT <code>$914D</code><br />
|'''00'''||04||0C||08||10||18||20||05||06<br />
|-<br />
|'''08'''||04||0F||09||12||1B||24||06||06<br />
|-<br />
|'''10'''||05||0F||0A||14||1E||28||07||06<br />
|-<br />
|'''18'''||06||12||0C||18||24||30||08||10<br />
|-<br />
|'''20'''||07||15||0E||1C||2A||38||13||12<br />
|-<br />
|'''28'''||07||15||0E||1C||2A||38||XX||XX<br />
|}<br />
<br />
The last two values in each row seem a bit strange, as they are not nice<br />
multiples of the first entry which is usually thought of as the length of an<br />
eighth note. The last row has garbage values in those positions as that is the<br />
start of another data table, so they are not even listed here.<br />
<br />
'''TODO''' Check what values are used in vanilla.<br />
<br />
==== Pitch LUT ====<br />
<br />
This table is used to detemine the pitch of a note. The note data is stored as<br />
described above, and the fact that the least significant bit is masked out is<br />
advantageous since the pulse channels can use 11 bits of timer data, so each<br />
entry in this table is actually two bytes wide.<br />
<br />
Rather than show the raw bytes here, it's more useful to show the rough note<br />
that those values represent. If the raw values are interesting to you, check<br />
the ROM for them. It's worth noting that some of the higher notes are several<br />
cents off from the listed note.<br />
<br />
{| class="wikitable"<br />
|+Pitch LUT <code>$918F</code><br />
| || 00|| 02|| 04|| 06|| 08|| 0a|| 0c|| 0e<br />
|-<br />
|00|| C3||---|| E3|| G3||G#3|| A3||A#3|| B3<br />
|-<br />
|10|| C4||C#4|| D4||D#4|| E4|| F4||F#4|| G4<br />
|-<br />
|20||G#4|| A4||A#4|| B4|| C5||C#5|| D5||D#5<br />
|-<br />
|30|| E5|| F5||F#5|| G5|| A5||A#5|| B5||C#3<br />
|-<br />
|40|| D3||D#3|| F3||F#3||G#5|| C6||C#6|| D6<br />
|-<br />
|50||D#6|| E6|| F6||F#6|| G6||G#6|| A6||A#6<br />
|-<br />
|60|| B6|| C7||C#7|| D7||D#7|| E7|| F7||F#7<br />
|-<br />
|70|| G7||G#7|| A7||A#7|| B7|| C8<br />
|}<br />
<br />
Note that although the table goes through <code>$7A</code> values above<br />
<code>$3E</code> aren't usable due to the 5 bit limit for pitch data.<br />
<br />
Value <code>$02</code> represents a rest.<br />
<br />
==== Noise Samples ====<br />
<br />
Several sound effects use the same routine to load "samples" for the noise<br />
channel to play. These values have the noise volume in the high nybble and the<br />
noise period in the low nybble.<br />
<br />
$90E8 - Sword slash<br />
$9123 - Enemy hurt<br />
$912C - Crumble block<br />
<br />
=== Variables ===<br />
<br />
This is just a dump of RAM addresses used by the music engine and a short<br />
description of what they are.<br />
<br />
$00E0 - Current phrase note data address (low byte)<br />
$00E1 - Current phrase note data address (high byte)<br />
$00E2 - Song offset, converted from song id to be an index instead of a bit field<br />
$00E3 - Current phrase index<br />
$00E4 - Drums loop start<br />
$00E5 - Tempo<br />
$00E6 - Pulse 1 low bits (used for vibrato effect)<br />
$00E7 - Pulse 2 low bits (used for vibrato effect)<br />
$00E8 - Pitch storage, temporary<br />
$00E9 - Play sound effect<br />
$00EA - Disable music<br />
$00EB - Request new song<br />
$00EC - Play sound effect<br />
$00ED - Play sound effect<br />
$00EE - Play sound effect<br />
$00EF - Play sound effect<br />
<br />
$0707 - Current world<br />
$075F - Queued song, loaded after screen transitions<br />
$07DA - Ganon Laugh sample<br />
$07DB - Song to resume after fanfare<br />
$07DF - ??? Likely sound effect flag for pulse 1 channel override<br />
<br />
$07E0 - ??? Likely sound effect flag for noise channel<br />
$07E2 - Pulse 2 envelope index<br />
$07E3 - Pulse 1 envelope index<br />
$07E4 - Drums current note duration<br />
$07E5 - Bass current note duration<br />
$07E6 - Harmony current note duration<br />
$07E7 - Melody current note duration<br />
$07E8 - Drums next note index<br />
$07E9 - Bass next note index<br />
$07EA - Harmony next note index<br />
$07EB - Melody next note index<br />
<br />
$07EC - Ganon Laugh counter<br />
$07ED - Sound FX counter (E9)<br />
$07EE - Sound FX counter (E9)<br />
$07F5 - Sound FX counter (ED)<br />
<br />
$07FA - Current SFX (E9)<br />
$07FB - Current song<br />
$07FD - Current SFX (ED)<br />
$07FE - ??? Likely sound effect flag for pulse 2 channel override<br />
$07FF - Current SFX (EF)<br />
<br />
=== Routines ===<br />
<br />
This is a non-exhaustive list of the routines in bank 6 involving the playing of<br />
music and sound effects. Each routine also lists its address so you can search<br />
in a disassembly for the actual code for that routine if these descriptions<br />
aren't clear.<br />
<br />
==== Main Music Loop <code>$9000</code> ====<br />
<br />
Checks that the music disable flag is off, then runs several SFX routines.<br />
After the SFX routines, the main music routine runs. After all this, various<br />
music related memory locations are cleared.<br />
<br />
==== Configure Pulse1 Channel <code>$9031</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4000</code> and <code>$4001</code><br />
respectively.<br />
<br />
==== Configure Pulse2 Channel <code>$9038</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4004</code> and <code>$4005</code><br />
respectively.<br />
<br />
==== Play Note Pulse1 <code>$9042</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 1 channel.<br />
<br />
==== Play Note <code>$9044</code> ====<br />
<br />
Called by the various play note routines. Takes a pitch index in register a and<br />
uses register x as a channel selector. For the pulse channels, this routine<br />
also saves the lower 8 bits of the APU timer register to <code>$E6</code> or <code>$E7</code> which<br />
are used for a vibrato effect.<br />
<br />
==== Play Note Pulse2 <code>$9067</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 2 channel.<br />
<br />
==== Play Note Triangle <code>$906B</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the triangle channel.<br />
<br />
==== Get Note Duration <code>$906F</code> ====<br />
<br />
Takes note data in register a and looks up the duration. The original note<br />
data is saved in register x and the result of the duration lookup is put in<br />
register a. The duration lookup is offset by the tempo stored in <code>$E5</code>.<br />
<br />
==== Vibrato Pulse1 <code>$9089</code> ====<br />
<br />
Applies a vibrato effect on the pulse 1 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato Pulse2 <code>$9097</code> ====<br />
<br />
Applies a vibrato effect on the pulse 2 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato <code>$909E</code> ====<br />
<br />
Takes the duration of the note remaining in register a, the low bits of the APU<br />
timer in register y, and the channel to use in register x. This is called by<br />
the other vibrato routines after setting x appropriately.<br />
<br />
Uses the <code>$04</code> bit of the duration to either add or subtract 2 from the low<br />
timer bits. Only the low bits are used because writing to the high bits resets<br />
the phase of the channel which can cause clicks. None of the notes from the<br />
pitch LUT are close enough to the boundary for the change to require the high<br />
bits to change anyway, so this works out fine.<br />
<br />
==== Play E9 SFX <code>$920B</code> ====<br />
<br />
Plays the sound effect requested in <code>$E9</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EF SFX <code>$92F4</code> ====<br />
<br />
Plays the sound effect requested in <code>$EF</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EE SFX <code>$9408</code> ====<br />
<br />
Plays the sound effect requested in <code>$EE</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Noise <code>$959D</code> ====<br />
<br />
Configures the APU noise registers to make a noise burst. Takes configuration<br />
for registers <code>$400F</code>, <code>$400E</code>, and <code>$400C</code> in registers y, x, and a.<br />
<br />
==== Crumble Bridge SFX <code>$956C</code> ====<br />
<br />
Starts playing the sound effect for a crumble bridge crumbling. This uses both<br />
the noise and the triangle channels so it sets flags to disable the music on<br />
those channels. Continues with SFX Noise Decay.<br />
<br />
==== SFX Noise Decay <code>$9587</code> ====<br />
<br />
Counts down the timer in <code>$07F5</code> and turns off the noise when it reaches 0.<br />
Also clears the flag for the ED sound effect in <code>$07FD</code>.<br />
<br />
==== Play ED SFX <code>$95A7</code> ====<br />
<br />
Plays the sound effect request in <code>$ED</code> or continues the sound effect saved in<br />
<code>$07FD</code>. Existing sound effects which are higher than the current sound effect<br />
will be ignored. If the same sound effect is requested that is already playing,<br />
it will restart the sound effect except for <code>$80</code> which gives priority to<br />
continuing. When the sound is continued instead of newly played, the decay<br />
routine will be called instead.<br />
<br />
; <code>$02</code><br />
: Crumble Bridge<br />
; <code>$04</code> and <code>$10</code><br />
: Crumble Block / Enemy Hurt<br />
; <code>$20</code> and <code>$80</code><br />
: Sword Strike<br />
; <code>$40</code><br />
: Very short noise burst, probably unused. Doesn't store the effect, and doesn't have an associated decay.<br />
<br />
==== Crumble Block / Enemy Hurt SFX <code>$95E6</code> ====<br />
<br />
Starts playing the sound of a block breaking or an enemy getting hurt.<br />
<br />
==== Crumble Block / Enemy Hurt SFX Decay <code>$95EE</code> ====<br />
<br />
Looks up noise register values based on the timer and the sound effect value.<br />
Crumble Block samples are at <code>$912C</code> while Enemy Hurt is at <code>$9123</code>. Continues<br />
on to Play Noise Samples.<br />
<br />
==== Play Noise Samples <code>$9612</code> ====<br />
<br />
Takes a sample value in register a. The low four bits of this are used to set<br />
the noise period via APU register <code>$400E</code>. The high four bits are used to set<br />
the noise volume via APU register <code>$400C</code>.<br />
<br />
Continues on the SFX Noise Decay process.<br />
<br />
==== Sword Strike SFX <code>$9604</code> ====<br />
<br />
Starts playing the sound of swinging your sword. This looks up samples based on<br />
the duration left at <code>$90E8</code> and plays them via Play Noise Samples.<br />
<br />
==== Play EC SFX <code>$990B</code> ====<br />
<br />
Plays the sound effect requested in <code>$EC</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Music <code>$9B18</code> ====<br />
<br />
Plays the music for the game.<br />
<br />
Runs Load Song if a new song is requested in <code>$EB</code>. Otherwise, runs Play Notes<br />
if the current song is set in <code>$07FB</code>. If neither of these is true, do nothing.<br />
<br />
==== Next Song <code>$9B24</code> ====<br />
<br />
Checks if the previous song should loop. If not, calls Mute All and returns.<br />
<br />
If the previous song was <code>$01</code> (the "intro" to the main theme), sets the next<br />
song to <code>$02</code> (the main theme loop).<br />
<br />
If the previous song was <code>$10</code> (the item get / level up fanfare), sets the<br />
current song from <code>$07DB</code>. Otherwise, leaves the current song the same as the<br />
previous song.<br />
<br />
Proceeds to Load Song.<br />
<br />
==== Mute All <code>$9B3B</code> ====<br />
<br />
Clears the current song at <code>$07FB</code> and sets the APU registers to mute the volume<br />
on both pulse channels, the triangle channel, and the noise channel.<br />
<br />
==== Load Song <code>$9B61</code> ====<br />
<br />
Takes a song id in register a and preps some variables for that song.<br />
<br />
If the song is <code>$10</code> (item get / level up fanfare) then it first saves the<br />
previous song to <code>$07FB</code> if it is less than <code>$10</code> so that the previous music<br />
will resume after the fanfare.<br />
<br />
Sets the phrase counter at <code>$E3</code> to 0 and the song offset at <code>$E2</code> based on the<br />
song id. Song ids are a bit field, and the song offset is the position of the<br />
lowest bit in the song id for indexing into the song table.<br />
<br />
Proceeds to Load Song Data.<br />
<br />
==== Load Song Data <code>$9B80</code> ====<br />
<br />
Loads the music variables based on the current world and current song offset.<br />
<br />
There are four blocks of code that are basically the same, for each of the four<br />
different music tables. Each one just uses a different position for the tables<br />
to load.<br />
<br />
Based on the current world in <code>$0707</code> it loads data from these offsets:<br />
<br />
<code>$00</code><br />
: Overworld music - <code>$9B87</code><br />
<code>$01</code> or <code>$02</code><br />
: Town music - <code>$9BC6</code><br />
<code>$03</code> or <code>$04</code><br />
: Palace music - <code>$9C05</code><br />
<code>$05</code> or higher<br />
: Great Palace music - <code>$9C42</code><br />
<br />
First, uses the song offset in <code>$E2</code> to index into the song table at the base<br />
offset given above.<br />
<br />
The phrase counter at <code>$E3</code> is added to that and used as in index again to<br />
retrieve the current phrase offset. If the current phrase offset is <code>$00</code> that<br />
means the song is over and the process goes back to the Next Song routine.<br />
<br />
Otherwise, the following structure is read at the base offset above + phrase<br />
offset just calculated.<br />
<br />
* <code>$E5</code> Tempo<br />
* <code>$E0</code> Note Data Low<br />
* <code>$E1</code> Note Data High<br />
* <code>$07E9</code> Bass Note Pointer<br />
* <code>$07EA</code> Harmony Note Pointer<br />
* <code>$07E8</code> Drum Note Pointer<br />
<br />
After this, the drum loop start point at <code>$E4</code> is also set to the same value as<br />
the drum note pointer. The melody note pointer at <code>$07EB</code> is set to <code>$00</code>, and<br />
all the durations (melody at <code>$07E7</code>, harmony at <code>$07E6</code>, bass at <code>$07E5</code>, and<br />
drums at <code>$07E4</code>) are set to <code>$01</code>.<br />
<br />
Proceeds to Play Notes.<br />
<br />
==== Play Notes ====<br />
<br />
This routine is broken into four major and similar sections: one each for<br />
melody, harmony, bass, and drums. The general process is as follows:<br />
<br />
decrement duration<br />
if duration == 0 {<br />
load next note<br />
increment note pointer<br />
set duration for note<br />
if no overriding sound effect {<br />
play note on appropriate channel<br />
}<br />
}<br />
<br />
Some channels have unique processing at different points in this. For example,<br />
the melody note data is null terminated, so if the loaded note in <code>$00</code> then the<br />
routine will jump to Load Song Data instead to go to the next phrase. If the<br />
drums channel gets a <code>$00</code> note it will reset the drums note pointer to the<br />
drums loop start and repeat the phrase. The bass and harmony channels don't<br />
have this looping behavior. This means that if the bass or harmony channels<br />
aren't long enough, the engine will happily just play whatever data comes next<br />
in the ROM.<br />
<br />
The melody is played on pulse 2 channel, the harmony on pulse 1 (which gets<br />
subverted by sound effects that need just one pulse channel), the bass on the<br />
triangle channel, and the drums on the noise channel.<br />
<br />
For the pulse channels, after the note is played, the envelope counter for that<br />
channel (<code>$07E2</code> for pulse 1, <code>$07E3</code> for pulse 2) is set. Normally the<br />
envelope is set to <code>$2F</code> but song <code>$40</code> (crystal fanfare and final boss music)<br />
sets it to <code>$18</code> instead. The envelope is not set if no note was played because<br />
the pitch index was <code>$02</code> which indicates a rest.<br />
<br />
Also for the pulse channels, after the above pseudocode, the vibrato and<br />
enveloping happens as long as there is no overriding sound effect. The envelope<br />
works by checking the envelope counter set previously and decrementing it. The<br />
counter value is halved and used to look up the envelope value in the LUT at<br />
<code>$9135</code>. These values are written directly to APU register <code>$4000</code> or <code>$4004</code><br />
depending on the channel.<br />
<br />
The bass channel has one special handling as well. The APU register <code>$4008</code> is<br />
set differently based on the current song id. For song <code>$10</code> (item get / level<br />
up fanfare) the register is set to <code>$60</code> but all other songs use <code>$1f</code>.<br />
<br />
The noise channel is not affect at all by the pitch. Any pitch value that is<br />
non zero will play a burst of noise.</div>Bentglasstubehttp://wiki.bindingforce.net/index.php?title=Music_Engine_Description&diff=336Music Engine Description2021-09-26T06:50:08Z<p>Bentglasstube: /* Variables */ Add some SFX related variables</p>
<hr />
<div>There are two separate music engines in Zelda 2. Both are in bank 6 (along<br />
with the song data). The music engine for the title screen resides at<br />
<code>$8000</code> and the engine for the rest of the game is at<br />
<code>$9000</code>. Each of these engines is called once per frame during the<br />
appropriate part of the game.<br />
<br />
Changes to the music engine should be very easy to make, as there is an<br />
abundance of free space in bank 6.<br />
<br />
== Title Music Engine ==<br />
<br />
'''TODO''' document further.<br />
<br />
== Main Music Engine ==<br />
<br />
=== Data Tables ===<br />
<br />
There are several data tables used by the music engine.<br />
<br />
==== Pulse Envelope ====<br />
<br />
This table is used to set the volume of the pulse channels over time. The index<br />
used starts at a certain value and decrements, so the table is in reverse order.<br />
The index is halved before use, so each value lasts two frames.<br />
<br />
{| class="wikitable"<br />
|+ Pulse Envelope <code>$9135</code><br />
|90||91||91||91||92||92||92||92<br />
|-<br />
|93||93||94||94||94||95||95||95<br />
|-<br />
|96||96||96||97||97||97||98||98<br />
|}<br />
<br />
==== Duration LUT ====<br />
<br />
This table is used to determine the duration of a note. The note data is stored<br />
with 5 bits of pitch information and 3 bits of duration, as such:<br />
<br />
D1 D0 P4 P3 P2 P1 P0 D2<br />
<br />
The Get Note Duration routine shifts things around to get the D bits into the<br />
three least significant bits and masks it before use. This value is then added<br />
to the tempo value in <code>$E5</code> which is always a multiple of 8 to index<br />
into the following table:<br />
<br />
{| class="wikitable"<br />
|+Duration LUT <code>$914D</code><br />
|'''00'''||04||0C||08||10||18||20||05||06<br />
|-<br />
|'''08'''||04||0F||09||12||1B||24||06||06<br />
|-<br />
|'''10'''||05||0F||0A||14||1E||28||07||06<br />
|-<br />
|'''18'''||06||12||0C||18||24||30||08||10<br />
|-<br />
|'''20'''||07||15||0E||1C||2A||38||13||12<br />
|-<br />
|'''28'''||07||15||0E||1C||2A||38||XX||XX<br />
|}<br />
<br />
The last two values in each row seem a bit strange, as they are not nice<br />
multiples of the first entry which is usually thought of as the length of an<br />
eighth note. The last row has garbage values in those positions as that is the<br />
start of another data table, so they are not even listed here.<br />
<br />
'''TODO''' Check what values are used in vanilla.<br />
<br />
==== Pitch LUT ====<br />
<br />
This table is used to detemine the pitch of a note. The note data is stored as<br />
described above, and the fact that the least significant bit is masked out is<br />
advantageous since the pulse channels can use 11 bits of timer data, so each<br />
entry in this table is actually two bytes wide.<br />
<br />
Rather than show the raw bytes here, it's more useful to show the rough note<br />
that those values represent. If the raw values are interesting to you, check<br />
the ROM for them. It's worth noting that some of the higher notes are several<br />
cents off from the listed note.<br />
<br />
{| class="wikitable"<br />
|+Pitch LUT <code>$918F</code><br />
| || 00|| 02|| 04|| 06|| 08|| 0a|| 0c|| 0e<br />
|-<br />
|00|| C3||---|| E3|| G3||G#3|| A3||A#3|| B3<br />
|-<br />
|10|| C4||C#4|| D4||D#4|| E4|| F4||F#4|| G4<br />
|-<br />
|20||G#4|| A4||A#4|| B4|| C5||C#5|| D5||D#5<br />
|-<br />
|30|| E5|| F5||F#5|| G5|| A5||A#5|| B5||C#3<br />
|-<br />
|40|| D3||D#3|| F3||F#3||G#5|| C6||C#6|| D6<br />
|-<br />
|50||D#6|| E6|| F6||F#6|| G6||G#6|| A6||A#6<br />
|-<br />
|60|| B6|| C7||C#7|| D7||D#7|| E7|| F7||F#7<br />
|-<br />
|70|| G7||G#7|| A7||A#7|| B7|| C8<br />
|}<br />
<br />
Note that although the table goes through <code>$7A</code> values above<br />
<code>$3E</code> aren't usable due to the 5 bit limit for pitch data.<br />
<br />
Value <code>$02</code> represents a rest.<br />
<br />
==== Noise Samples ====<br />
<br />
Several sound effects use the same routine to load "samples" for the noise<br />
channel to play. These values have the noise volume in the high nybble and the<br />
noise period in the low nybble.<br />
<br />
$90E8 - Sword slash<br />
$9123 - Enemy hurt<br />
$912C - Crumble block<br />
<br />
=== Variables ===<br />
<br />
This is just a dump of RAM addresses used by the music engine and a short<br />
description of what they are.<br />
<br />
$00E0 - Current phrase note data address (low byte)<br />
$00E1 - Current phrase note data address (high byte)<br />
$00E2 - Song offset, converted from song id to be an index instead of a bit field<br />
$00E3 - Current phrase index<br />
$00E4 - Drums loop start<br />
$00E5 - Tempo<br />
$00E6 - Pulse 1 low bits (used for vibrato effect)<br />
$00E7 - Pulse 2 low bits (used for vibrato effect)<br />
$00E8 - Pitch storage, temporary<br />
$00E9 - Play sound effect<br />
$00EA - Disable music<br />
$00EB - Request new song<br />
$00EC - Play sound effect<br />
$00ED - Play sound effect<br />
$00EE - Play sound effect<br />
$00EF - Play sound effect<br />
<br />
$0707 - Current world<br />
$075F - Queued song, loaded after screen transitions<br />
$07DA - Ganon Laugh sample<br />
$07DB - Song to resume after fanfare<br />
$07DF - ??? Likely sound effect flag for pulse 1 channel override<br />
<br />
$07E0 - ??? Likely sound effect flag for noise channel<br />
$07E2 - Pulse 2 envelope index<br />
$07E3 - Pulse 1 envelope index<br />
$07E4 - Drums current note duration<br />
$07E5 - Bass current note duration<br />
$07E6 - Harmony current note duration<br />
$07E7 - Melody current note duration<br />
$07E8 - Drums next note index<br />
$07E9 - Bass next note index<br />
$07EA - Harmony next note index<br />
$07EB - Melody next note index<br />
<br />
$07EC - Ganon Laugh counter<br />
$07ED - Sound FX counter (E9)<br />
$07EE - Sound FX counter (E9)<br />
$07F5 - Sound FX counter (ED)<br />
<br />
$07FA - Current SFX (E9)<br />
$07FB - Current song<br />
$07FD - Current SFX (ED)<br />
$07FE - ??? Likely sound effect flag for pulse 2 channel override<br />
$07FF - ??? Likely sound effect flag for pulse 1 channel override<br />
</code><br />
<br />
=== Routines ===<br />
<br />
This is a non-exhaustive list of the routines in bank 6 involving the playing of<br />
music and sound effects. Each routine also lists its address so you can search<br />
in a disassembly for the actual code for that routine if these descriptions<br />
aren't clear.<br />
<br />
==== Main Music Loop <code>$9000</code> ====<br />
<br />
Checks that the music disable flag is off, then runs several SFX routines.<br />
After the SFX routines, the main music routine runs. After all this, various<br />
music related memory locations are cleared.<br />
<br />
==== Configure Pulse1 Channel <code>$9031</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4000</code> and <code>$4001</code><br />
respectively.<br />
<br />
==== Configure Pulse2 Channel <code>$9038</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4004</code> and <code>$4005</code><br />
respectively.<br />
<br />
==== Play Note Pulse1 <code>$9042</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 1 channel.<br />
<br />
==== Play Note <code>$9044</code> ====<br />
<br />
Called by the various play note routines. Takes a pitch index in register a and<br />
uses register x as a channel selector. For the pulse channels, this routine<br />
also saves the lower 8 bits of the APU timer register to <code>$E6</code> or <code>$E7</code> which<br />
are used for a vibrato effect.<br />
<br />
==== Play Note Pulse2 <code>$9067</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 2 channel.<br />
<br />
==== Play Note Triangle <code>$906B</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the triangle channel.<br />
<br />
==== Get Note Duration <code>$906F</code> ====<br />
<br />
Takes note data in register a and looks up the duration. The original note<br />
data is saved in register x and the result of the duration lookup is put in<br />
register a. The duration lookup is offset by the tempo stored in <code>$E5</code>.<br />
<br />
==== Vibrato Pulse1 <code>$9089</code> ====<br />
<br />
Applies a vibrato effect on the pulse 1 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato Pulse2 <code>$9097</code> ====<br />
<br />
Applies a vibrato effect on the pulse 2 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato <code>$909E</code> ====<br />
<br />
Takes the duration of the note remaining in register a, the low bits of the APU<br />
timer in register y, and the channel to use in register x. This is called by<br />
the other vibrato routines after setting x appropriately.<br />
<br />
Uses the <code>$04</code> bit of the duration to either add or subtract 2 from the low<br />
timer bits. Only the low bits are used because writing to the high bits resets<br />
the phase of the channel which can cause clicks. None of the notes from the<br />
pitch LUT are close enough to the boundary for the change to require the high<br />
bits to change anyway, so this works out fine.<br />
<br />
==== Play E9 SFX <code>$920B</code> ====<br />
<br />
Plays the sound effect requested in <code>$E9</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EF SFX <code>$92F4</code> ====<br />
<br />
Plays the sound effect requested in <code>$EF</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EE SFX <code>$9408</code> ====<br />
<br />
Plays the sound effect requested in <code>$EE</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Noise <code>$959D</code> ====<br />
<br />
Configures the APU noise registers to make a noise burst. Takes configuration<br />
for registers <code>$400F</code>, <code>$400E</code>, and <code>$400C</code> in registers y, x, and a.<br />
<br />
==== Crumble Bridge SFX <code>$956C</code> ====<br />
<br />
Starts playing the sound effect for a crumble bridge crumbling. This uses both<br />
the noise and the triangle channels so it sets flags to disable the music on<br />
those channels. Continues with SFX Noise Decay.<br />
<br />
==== SFX Noise Decay <code>$9587</code> ====<br />
<br />
Counts down the timer in <code>$07F5</code> and turns off the noise when it reaches 0.<br />
Also clears the flag for the ED sound effect in <code>$07FD</code>.<br />
<br />
==== Play ED SFX <code>$95A7</code> ====<br />
<br />
Plays the sound effect request in <code>$ED</code> or continues the sound effect saved in<br />
<code>$07FD</code>. Existing sound effects which are higher than the current sound effect<br />
will be ignored. If the same sound effect is requested that is already playing,<br />
it will restart the sound effect except for <code>$80</code> which gives priority to<br />
continuing. When the sound is continued instead of newly played, the decay<br />
routine will be called instead.<br />
<br />
; <code>$02</code><br />
: Crumble Bridge<br />
; <code>$04</code> and <code>$10</code><br />
: Crumble Block / Enemy Hurt<br />
; <code>$20</code> and <code>$80</code><br />
: Sword Strike<br />
; <code>$40</code><br />
: Very short noise burst, probably unused. Doesn't store the effect, and doesn't have an associated decay.<br />
<br />
==== Crumble Block / Enemy Hurt SFX <code>$95E6</code> ====<br />
<br />
Starts playing the sound of a block breaking or an enemy getting hurt.<br />
<br />
==== Crumble Block / Enemy Hurt SFX Decay <code>$95EE</code> ====<br />
<br />
Looks up noise register values based on the timer and the sound effect value.<br />
Crumble Block samples are at <code>$912C</code> while Enemy Hurt is at <code>$9123</code>. Continues<br />
on to Play Noise Samples.<br />
<br />
==== Play Noise Samples <code>$9612</code> ====<br />
<br />
Takes a sample value in register a. The low four bits of this are used to set<br />
the noise period via APU register <code>$400E</code>. The high four bits are used to set<br />
the noise volume via APU register <code>$400C</code>.<br />
<br />
Continues on the SFX Noise Decay process.<br />
<br />
==== Sword Strike SFX <code>$9604</code> ====<br />
<br />
Starts playing the sound of swinging your sword. This looks up samples based on<br />
the duration left at <code>$90E8</code> and plays them via Play Noise Samples.<br />
<br />
==== Play EC SFX <code>$990B</code> ====<br />
<br />
Plays the sound effect requested in <code>$EC</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Music <code>$9B18</code> ====<br />
<br />
Plays the music for the game.<br />
<br />
Runs Load Song if a new song is requested in <code>$EB</code>. Otherwise, runs Play Notes<br />
if the current song is set in <code>$07FB</code>. If neither of these is true, do nothing.<br />
<br />
==== Next Song <code>$9B24</code> ====<br />
<br />
Checks if the previous song should loop. If not, calls Mute All and returns.<br />
<br />
If the previous song was <code>$01</code> (the "intro" to the main theme), sets the next<br />
song to <code>$02</code> (the main theme loop).<br />
<br />
If the previous song was <code>$10</code> (the item get / level up fanfare), sets the<br />
current song from <code>$07DB</code>. Otherwise, leaves the current song the same as the<br />
previous song.<br />
<br />
Proceeds to Load Song.<br />
<br />
==== Mute All <code>$9B3B</code> ====<br />
<br />
Clears the current song at <code>$07FB</code> and sets the APU registers to mute the volume<br />
on both pulse channels, the triangle channel, and the noise channel.<br />
<br />
==== Load Song <code>$9B61</code> ====<br />
<br />
Takes a song id in register a and preps some variables for that song.<br />
<br />
If the song is <code>$10</code> (item get / level up fanfare) then it first saves the<br />
previous song to <code>$07FB</code> if it is less than <code>$10</code> so that the previous music<br />
will resume after the fanfare.<br />
<br />
Sets the phrase counter at <code>$E3</code> to 0 and the song offset at <code>$E2</code> based on the<br />
song id. Song ids are a bit field, and the song offset is the position of the<br />
lowest bit in the song id for indexing into the song table.<br />
<br />
Proceeds to Load Song Data.<br />
<br />
==== Load Song Data <code>$9B80</code> ====<br />
<br />
Loads the music variables based on the current world and current song offset.<br />
<br />
There are four blocks of code that are basically the same, for each of the four<br />
different music tables. Each one just uses a different position for the tables<br />
to load.<br />
<br />
Based on the current world in <code>$0707</code> it loads data from these offsets:<br />
<br />
<code>$00</code><br />
: Overworld music - <code>$9B87</code><br />
<code>$01</code> or <code>$02</code><br />
: Town music - <code>$9BC6</code><br />
<code>$03</code> or <code>$04</code><br />
: Palace music - <code>$9C05</code><br />
<code>$05</code> or higher<br />
: Great Palace music - <code>$9C42</code><br />
<br />
First, uses the song offset in <code>$E2</code> to index into the song table at the base<br />
offset given above.<br />
<br />
The phrase counter at <code>$E3</code> is added to that and used as in index again to<br />
retrieve the current phrase offset. If the current phrase offset is <code>$00</code> that<br />
means the song is over and the process goes back to the Next Song routine.<br />
<br />
Otherwise, the following structure is read at the base offset above + phrase<br />
offset just calculated.<br />
<br />
* <code>$E5</code> Tempo<br />
* <code>$E0</code> Note Data Low<br />
* <code>$E1</code> Note Data High<br />
* <code>$07E9</code> Bass Note Pointer<br />
* <code>$07EA</code> Harmony Note Pointer<br />
* <code>$07E8</code> Drum Note Pointer<br />
<br />
After this, the drum loop start point at <code>$E4</code> is also set to the same value as<br />
the drum note pointer. The melody note pointer at <code>$07EB</code> is set to <code>$00</code>, and<br />
all the durations (melody at <code>$07E7</code>, harmony at <code>$07E6</code>, bass at <code>$07E5</code>, and<br />
drums at <code>$07E4</code>) are set to <code>$01</code>.<br />
<br />
Proceeds to Play Notes.<br />
<br />
==== Play Notes ====<br />
<br />
This routine is broken into four major and similar sections: one each for<br />
melody, harmony, bass, and drums. The general process is as follows:<br />
<br />
decrement duration<br />
if duration == 0 {<br />
load next note<br />
increment note pointer<br />
set duration for note<br />
if no overriding sound effect {<br />
play note on appropriate channel<br />
}<br />
}<br />
<br />
Some channels have unique processing at different points in this. For example,<br />
the melody note data is null terminated, so if the loaded note in <code>$00</code> then the<br />
routine will jump to Load Song Data instead to go to the next phrase. If the<br />
drums channel gets a <code>$00</code> note it will reset the drums note pointer to the<br />
drums loop start and repeat the phrase. The bass and harmony channels don't<br />
have this looping behavior. This means that if the bass or harmony channels<br />
aren't long enough, the engine will happily just play whatever data comes next<br />
in the ROM.<br />
<br />
The melody is played on pulse 2 channel, the harmony on pulse 1 (which gets<br />
subverted by sound effects that need just one pulse channel), the bass on the<br />
triangle channel, and the drums on the noise channel.<br />
<br />
For the pulse channels, after the note is played, the envelope counter for that<br />
channel (<code>$07E2</code> for pulse 1, <code>$07E3</code> for pulse 2) is set. Normally the<br />
envelope is set to <code>$2F</code> but song <code>$40</code> (crystal fanfare and final boss music)<br />
sets it to <code>$18</code> instead. The envelope is not set if no note was played because<br />
the pitch index was <code>$02</code> which indicates a rest.<br />
<br />
Also for the pulse channels, after the above pseudocode, the vibrato and<br />
enveloping happens as long as there is no overriding sound effect. The envelope<br />
works by checking the envelope counter set previously and decrementing it. The<br />
counter value is halved and used to look up the envelope value in the LUT at<br />
<code>$9135</code>. These values are written directly to APU register <code>$4000</code> or <code>$4004</code><br />
depending on the channel.<br />
<br />
The bass channel has one special handling as well. The APU register <code>$4008</code> is<br />
set differently based on the current song id. For song <code>$10</code> (item get / level<br />
up fanfare) the register is set to <code>$60</code> but all other songs use <code>$1f</code>.<br />
<br />
The noise channel is not affect at all by the pitch. Any pitch value that is<br />
non zero will play a burst of noise.</div>Bentglasstubehttp://wiki.bindingforce.net/index.php?title=Music_Engine_Description&diff=335Music Engine Description2021-09-26T04:35:19Z<p>Bentglasstube: /* Main Music Engine */</p>
<hr />
<div>There are two separate music engines in Zelda 2. Both are in bank 6 (along<br />
with the song data). The music engine for the title screen resides at<br />
<code>$8000</code> and the engine for the rest of the game is at<br />
<code>$9000</code>. Each of these engines is called once per frame during the<br />
appropriate part of the game.<br />
<br />
Changes to the music engine should be very easy to make, as there is an<br />
abundance of free space in bank 6.<br />
<br />
== Title Music Engine ==<br />
<br />
'''TODO''' document further.<br />
<br />
== Main Music Engine ==<br />
<br />
=== Data Tables ===<br />
<br />
There are several data tables used by the music engine.<br />
<br />
==== Pulse Envelope ====<br />
<br />
This table is used to set the volume of the pulse channels over time. The index<br />
used starts at a certain value and decrements, so the table is in reverse order.<br />
The index is halved before use, so each value lasts two frames.<br />
<br />
{| class="wikitable"<br />
|+ Pulse Envelope <code>$9135</code><br />
|90||91||91||91||92||92||92||92<br />
|-<br />
|93||93||94||94||94||95||95||95<br />
|-<br />
|96||96||96||97||97||97||98||98<br />
|}<br />
<br />
==== Duration LUT ====<br />
<br />
This table is used to determine the duration of a note. The note data is stored<br />
with 5 bits of pitch information and 3 bits of duration, as such:<br />
<br />
D1 D0 P4 P3 P2 P1 P0 D2<br />
<br />
The Get Note Duration routine shifts things around to get the D bits into the<br />
three least significant bits and masks it before use. This value is then added<br />
to the tempo value in <code>$E5</code> which is always a multiple of 8 to index<br />
into the following table:<br />
<br />
{| class="wikitable"<br />
|+Duration LUT <code>$914D</code><br />
|'''00'''||04||0C||08||10||18||20||05||06<br />
|-<br />
|'''08'''||04||0F||09||12||1B||24||06||06<br />
|-<br />
|'''10'''||05||0F||0A||14||1E||28||07||06<br />
|-<br />
|'''18'''||06||12||0C||18||24||30||08||10<br />
|-<br />
|'''20'''||07||15||0E||1C||2A||38||13||12<br />
|-<br />
|'''28'''||07||15||0E||1C||2A||38||XX||XX<br />
|}<br />
<br />
The last two values in each row seem a bit strange, as they are not nice<br />
multiples of the first entry which is usually thought of as the length of an<br />
eighth note. The last row has garbage values in those positions as that is the<br />
start of another data table, so they are not even listed here.<br />
<br />
'''TODO''' Check what values are used in vanilla.<br />
<br />
==== Pitch LUT ====<br />
<br />
This table is used to detemine the pitch of a note. The note data is stored as<br />
described above, and the fact that the least significant bit is masked out is<br />
advantageous since the pulse channels can use 11 bits of timer data, so each<br />
entry in this table is actually two bytes wide.<br />
<br />
Rather than show the raw bytes here, it's more useful to show the rough note<br />
that those values represent. If the raw values are interesting to you, check<br />
the ROM for them. It's worth noting that some of the higher notes are several<br />
cents off from the listed note.<br />
<br />
{| class="wikitable"<br />
|+Pitch LUT <code>$918F</code><br />
| || 00|| 02|| 04|| 06|| 08|| 0a|| 0c|| 0e<br />
|-<br />
|00|| C3||---|| E3|| G3||G#3|| A3||A#3|| B3<br />
|-<br />
|10|| C4||C#4|| D4||D#4|| E4|| F4||F#4|| G4<br />
|-<br />
|20||G#4|| A4||A#4|| B4|| C5||C#5|| D5||D#5<br />
|-<br />
|30|| E5|| F5||F#5|| G5|| A5||A#5|| B5||C#3<br />
|-<br />
|40|| D3||D#3|| F3||F#3||G#5|| C6||C#6|| D6<br />
|-<br />
|50||D#6|| E6|| F6||F#6|| G6||G#6|| A6||A#6<br />
|-<br />
|60|| B6|| C7||C#7|| D7||D#7|| E7|| F7||F#7<br />
|-<br />
|70|| G7||G#7|| A7||A#7|| B7|| C8<br />
|}<br />
<br />
Note that although the table goes through <code>$7A</code> values above<br />
<code>$3E</code> aren't usable due to the 5 bit limit for pitch data.<br />
<br />
Value <code>$02</code> represents a rest.<br />
<br />
==== Noise Samples ====<br />
<br />
Several sound effects use the same routine to load "samples" for the noise<br />
channel to play. These values have the noise volume in the high nybble and the<br />
noise period in the low nybble.<br />
<br />
$90E8 - Sword slash<br />
$9123 - Enemy hurt<br />
$912C - Crumble block<br />
<br />
=== Variables ===<br />
<br />
This is just a dump of RAM addresses used by the music engine and a short<br />
description of what they are.<br />
<br />
$00E0 - Current phrase note data address (low byte)<br />
$00E1 - Current phrase note data address (high byte)<br />
$00E2 - Song offset, converted from song id to be an index instead of a bit field<br />
$00E3 - Current phrase index<br />
$00E4 - Drums loop start<br />
$00E5 - Tempo<br />
$00E6 - Pulse 1 low bits (used for vibrato effect)<br />
$00E7 - Pulse 2 low bits (used for vibrato effect)<br />
$00E8 - Pitch storage, temporary<br />
$00E9 - Play sound effect<br />
$00EA - Disable music<br />
$00EB - Request new song<br />
$00EC - Play sound effect<br />
$00ED - Play sound effect<br />
$00EE - Play sound effect<br />
$00EF - Play sound effect<br />
<br />
$0707 - Current world<br />
$075F - Queued song, loaded after screen transitions<br />
$07DB - Song to resume after fanfare<br />
$07DF - ??? Likely sound effect flag for pulse 1 channel override<br />
<br />
$07E0 - ??? Likely sound effect flag for noise channel<br />
$07E2 - Pulse 2 envelope index<br />
$07E3 - Pulse 1 envelope index<br />
$07E4 - Drums current note duration<br />
$07E5 - Bass current note duration<br />
$07E6 - Harmony current note duration<br />
$07E7 - Melody current note duration<br />
$07E8 - Drums next note index<br />
$07E9 - Bass next note index<br />
$07EA - Harmony next note index<br />
$07EB - Melody next note index<br />
<br />
$07F5 - Sound FX counter<br />
<br />
$07FB - Current song<br />
$07FD - Current SFX (ED)<br />
$07FE - ??? Likely sound effect flag for pulse 2 channel override<br />
$07FF - ??? Likely sound effect flag for pulse 1 channel override<br />
</code><br />
<br />
=== Routines ===<br />
<br />
This is a non-exhaustive list of the routines in bank 6 involving the playing of<br />
music and sound effects. Each routine also lists its address so you can search<br />
in a disassembly for the actual code for that routine if these descriptions<br />
aren't clear.<br />
<br />
==== Main Music Loop <code>$9000</code> ====<br />
<br />
Checks that the music disable flag is off, then runs several SFX routines.<br />
After the SFX routines, the main music routine runs. After all this, various<br />
music related memory locations are cleared.<br />
<br />
==== Configure Pulse1 Channel <code>$9031</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4000</code> and <code>$4001</code><br />
respectively.<br />
<br />
==== Configure Pulse2 Channel <code>$9038</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4004</code> and <code>$4005</code><br />
respectively.<br />
<br />
==== Play Note Pulse1 <code>$9042</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 1 channel.<br />
<br />
==== Play Note <code>$9044</code> ====<br />
<br />
Called by the various play note routines. Takes a pitch index in register a and<br />
uses register x as a channel selector. For the pulse channels, this routine<br />
also saves the lower 8 bits of the APU timer register to <code>$E6</code> or <code>$E7</code> which<br />
are used for a vibrato effect.<br />
<br />
==== Play Note Pulse2 <code>$9067</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 2 channel.<br />
<br />
==== Play Note Triangle <code>$906B</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the triangle channel.<br />
<br />
==== Get Note Duration <code>$906F</code> ====<br />
<br />
Takes note data in register a and looks up the duration. The original note<br />
data is saved in register x and the result of the duration lookup is put in<br />
register a. The duration lookup is offset by the tempo stored in <code>$E5</code>.<br />
<br />
==== Vibrato Pulse1 <code>$9089</code> ====<br />
<br />
Applies a vibrato effect on the pulse 1 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato Pulse2 <code>$9097</code> ====<br />
<br />
Applies a vibrato effect on the pulse 2 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato <code>$909E</code> ====<br />
<br />
Takes the duration of the note remaining in register a, the low bits of the APU<br />
timer in register y, and the channel to use in register x. This is called by<br />
the other vibrato routines after setting x appropriately.<br />
<br />
Uses the <code>$04</code> bit of the duration to either add or subtract 2 from the low<br />
timer bits. Only the low bits are used because writing to the high bits resets<br />
the phase of the channel which can cause clicks. None of the notes from the<br />
pitch LUT are close enough to the boundary for the change to require the high<br />
bits to change anyway, so this works out fine.<br />
<br />
==== Play E9 SFX <code>$920B</code> ====<br />
<br />
Plays the sound effect requested in <code>$E9</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EF SFX <code>$92F4</code> ====<br />
<br />
Plays the sound effect requested in <code>$EF</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EE SFX <code>$9408</code> ====<br />
<br />
Plays the sound effect requested in <code>$EE</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Noise <code>$959D</code> ====<br />
<br />
Configures the APU noise registers to make a noise burst. Takes configuration<br />
for registers <code>$400F</code>, <code>$400E</code>, and <code>$400C</code> in registers y, x, and a.<br />
<br />
==== Crumble Bridge SFX <code>$956C</code> ====<br />
<br />
Starts playing the sound effect for a crumble bridge crumbling. This uses both<br />
the noise and the triangle channels so it sets flags to disable the music on<br />
those channels. Continues with SFX Noise Decay.<br />
<br />
==== SFX Noise Decay <code>$9587</code> ====<br />
<br />
Counts down the timer in <code>$07F5</code> and turns off the noise when it reaches 0.<br />
Also clears the flag for the ED sound effect in <code>$07FD</code>.<br />
<br />
==== Play ED SFX <code>$95A7</code> ====<br />
<br />
Plays the sound effect request in <code>$ED</code> or continues the sound effect saved in<br />
<code>$07FD</code>. Existing sound effects which are higher than the current sound effect<br />
will be ignored. If the same sound effect is requested that is already playing,<br />
it will restart the sound effect except for <code>$80</code> which gives priority to<br />
continuing. When the sound is continued instead of newly played, the decay<br />
routine will be called instead.<br />
<br />
; <code>$02</code><br />
: Crumble Bridge<br />
; <code>$04</code> and <code>$10</code><br />
: Crumble Block / Enemy Hurt<br />
; <code>$20</code> and <code>$80</code><br />
: Sword Strike<br />
; <code>$40</code><br />
: Very short noise burst, probably unused. Doesn't store the effect, and doesn't have an associated decay.<br />
<br />
==== Crumble Block / Enemy Hurt SFX <code>$95E6</code> ====<br />
<br />
Starts playing the sound of a block breaking or an enemy getting hurt.<br />
<br />
==== Crumble Block / Enemy Hurt SFX Decay <code>$95EE</code> ====<br />
<br />
Looks up noise register values based on the timer and the sound effect value.<br />
Crumble Block samples are at <code>$912C</code> while Enemy Hurt is at <code>$9123</code>. Continues<br />
on to Play Noise Samples.<br />
<br />
==== Play Noise Samples <code>$9612</code> ====<br />
<br />
Takes a sample value in register a. The low four bits of this are used to set<br />
the noise period via APU register <code>$400E</code>. The high four bits are used to set<br />
the noise volume via APU register <code>$400C</code>.<br />
<br />
Continues on the SFX Noise Decay process.<br />
<br />
==== Sword Strike SFX <code>$9604</code> ====<br />
<br />
Starts playing the sound of swinging your sword. This looks up samples based on<br />
the duration left at <code>$90E8</code> and plays them via Play Noise Samples.<br />
<br />
==== Play EC SFX <code>$990B</code> ====<br />
<br />
Plays the sound effect requested in <code>$EC</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Music <code>$9B18</code> ====<br />
<br />
Plays the music for the game.<br />
<br />
Runs Load Song if a new song is requested in <code>$EB</code>. Otherwise, runs Play Notes<br />
if the current song is set in <code>$07FB</code>. If neither of these is true, do nothing.<br />
<br />
==== Next Song <code>$9B24</code> ====<br />
<br />
Checks if the previous song should loop. If not, calls Mute All and returns.<br />
<br />
If the previous song was <code>$01</code> (the "intro" to the main theme), sets the next<br />
song to <code>$02</code> (the main theme loop).<br />
<br />
If the previous song was <code>$10</code> (the item get / level up fanfare), sets the<br />
current song from <code>$07DB</code>. Otherwise, leaves the current song the same as the<br />
previous song.<br />
<br />
Proceeds to Load Song.<br />
<br />
==== Mute All <code>$9B3B</code> ====<br />
<br />
Clears the current song at <code>$07FB</code> and sets the APU registers to mute the volume<br />
on both pulse channels, the triangle channel, and the noise channel.<br />
<br />
==== Load Song <code>$9B61</code> ====<br />
<br />
Takes a song id in register a and preps some variables for that song.<br />
<br />
If the song is <code>$10</code> (item get / level up fanfare) then it first saves the<br />
previous song to <code>$07FB</code> if it is less than <code>$10</code> so that the previous music<br />
will resume after the fanfare.<br />
<br />
Sets the phrase counter at <code>$E3</code> to 0 and the song offset at <code>$E2</code> based on the<br />
song id. Song ids are a bit field, and the song offset is the position of the<br />
lowest bit in the song id for indexing into the song table.<br />
<br />
Proceeds to Load Song Data.<br />
<br />
==== Load Song Data <code>$9B80</code> ====<br />
<br />
Loads the music variables based on the current world and current song offset.<br />
<br />
There are four blocks of code that are basically the same, for each of the four<br />
different music tables. Each one just uses a different position for the tables<br />
to load.<br />
<br />
Based on the current world in <code>$0707</code> it loads data from these offsets:<br />
<br />
<code>$00</code><br />
: Overworld music - <code>$9B87</code><br />
<code>$01</code> or <code>$02</code><br />
: Town music - <code>$9BC6</code><br />
<code>$03</code> or <code>$04</code><br />
: Palace music - <code>$9C05</code><br />
<code>$05</code> or higher<br />
: Great Palace music - <code>$9C42</code><br />
<br />
First, uses the song offset in <code>$E2</code> to index into the song table at the base<br />
offset given above.<br />
<br />
The phrase counter at <code>$E3</code> is added to that and used as in index again to<br />
retrieve the current phrase offset. If the current phrase offset is <code>$00</code> that<br />
means the song is over and the process goes back to the Next Song routine.<br />
<br />
Otherwise, the following structure is read at the base offset above + phrase<br />
offset just calculated.<br />
<br />
* <code>$E5</code> Tempo<br />
* <code>$E0</code> Note Data Low<br />
* <code>$E1</code> Note Data High<br />
* <code>$07E9</code> Bass Note Pointer<br />
* <code>$07EA</code> Harmony Note Pointer<br />
* <code>$07E8</code> Drum Note Pointer<br />
<br />
After this, the drum loop start point at <code>$E4</code> is also set to the same value as<br />
the drum note pointer. The melody note pointer at <code>$07EB</code> is set to <code>$00</code>, and<br />
all the durations (melody at <code>$07E7</code>, harmony at <code>$07E6</code>, bass at <code>$07E5</code>, and<br />
drums at <code>$07E4</code>) are set to <code>$01</code>.<br />
<br />
Proceeds to Play Notes.<br />
<br />
==== Play Notes ====<br />
<br />
This routine is broken into four major and similar sections: one each for<br />
melody, harmony, bass, and drums. The general process is as follows:<br />
<br />
decrement duration<br />
if duration == 0 {<br />
load next note<br />
increment note pointer<br />
set duration for note<br />
if no overriding sound effect {<br />
play note on appropriate channel<br />
}<br />
}<br />
<br />
Some channels have unique processing at different points in this. For example,<br />
the melody note data is null terminated, so if the loaded note in <code>$00</code> then the<br />
routine will jump to Load Song Data instead to go to the next phrase. If the<br />
drums channel gets a <code>$00</code> note it will reset the drums note pointer to the<br />
drums loop start and repeat the phrase. The bass and harmony channels don't<br />
have this looping behavior. This means that if the bass or harmony channels<br />
aren't long enough, the engine will happily just play whatever data comes next<br />
in the ROM.<br />
<br />
The melody is played on pulse 2 channel, the harmony on pulse 1 (which gets<br />
subverted by sound effects that need just one pulse channel), the bass on the<br />
triangle channel, and the drums on the noise channel.<br />
<br />
For the pulse channels, after the note is played, the envelope counter for that<br />
channel (<code>$07E2</code> for pulse 1, <code>$07E3</code> for pulse 2) is set. Normally the<br />
envelope is set to <code>$2F</code> but song <code>$40</code> (crystal fanfare and final boss music)<br />
sets it to <code>$18</code> instead. The envelope is not set if no note was played because<br />
the pitch index was <code>$02</code> which indicates a rest.<br />
<br />
Also for the pulse channels, after the above pseudocode, the vibrato and<br />
enveloping happens as long as there is no overriding sound effect. The envelope<br />
works by checking the envelope counter set previously and decrementing it. The<br />
counter value is halved and used to look up the envelope value in the LUT at<br />
<code>$9135</code>. These values are written directly to APU register <code>$4000</code> or <code>$4004</code><br />
depending on the channel.<br />
<br />
The bass channel has one special handling as well. The APU register <code>$4008</code> is<br />
set differently based on the current song id. For song <code>$10</code> (item get / level<br />
up fanfare) the register is set to <code>$60</code> but all other songs use <code>$1f</code>.<br />
<br />
The noise channel is not affect at all by the pitch. Any pitch value that is<br />
non zero will play a burst of noise.</div>Bentglasstubehttp://wiki.bindingforce.net/index.php?title=Music_Engine_Description&diff=334Music Engine Description2021-09-26T04:34:09Z<p>Bentglasstube: </p>
<hr />
<div>There are two separate music engines in Zelda 2. Both are in bank 6 (along<br />
with the song data). The music engine for the title screen resides at<br />
<code>$8000</code> and the engine for the rest of the game is at<br />
<code>$9000</code>. Each of these engines is called once per frame during the<br />
appropriate part of the game.<br />
<br />
Changes to the music engine should be very easy to make, as there is an<br />
abundance of free space in bank 6.<br />
<br />
== Title Music Engine ==<br />
<br />
'''TODO''' document further.<br />
<br />
== Main Music Engine ==<br />
<br />
The main loop for starts at bank 6 $9000<br />
<br />
=== Data Tables ===<br />
<br />
There are several data tables used by the music engine.<br />
<br />
==== Pulse Envelope ====<br />
<br />
This table is used to set the volume of the pulse channels over time. The index<br />
used starts at a certain value and decrements, so the table is in reverse order.<br />
The index is halved before use, so each value lasts two frames.<br />
<br />
{| class="wikitable"<br />
|+ Pulse Envelope <code>$9135</code><br />
|90||91||91||91||92||92||92||92<br />
|-<br />
|93||93||94||94||94||95||95||95<br />
|-<br />
|96||96||96||97||97||97||98||98<br />
|}<br />
<br />
==== Duration LUT ====<br />
<br />
This table is used to determine the duration of a note. The note data is stored<br />
with 5 bits of pitch information and 3 bits of duration, as such:<br />
<br />
D1 D0 P4 P3 P2 P1 P0 D2<br />
<br />
The Get Note Duration routine shifts things around to get the D bits into the<br />
three least significant bits and masks it before use. This value is then added<br />
to the tempo value in <code>$E5</code> which is always a multiple of 8 to index<br />
into the following table:<br />
<br />
{| class="wikitable"<br />
|+Duration LUT <code>$914D</code><br />
|'''00'''||04||0C||08||10||18||20||05||06<br />
|-<br />
|'''08'''||04||0F||09||12||1B||24||06||06<br />
|-<br />
|'''10'''||05||0F||0A||14||1E||28||07||06<br />
|-<br />
|'''18'''||06||12||0C||18||24||30||08||10<br />
|-<br />
|'''20'''||07||15||0E||1C||2A||38||13||12<br />
|-<br />
|'''28'''||07||15||0E||1C||2A||38||XX||XX<br />
|}<br />
<br />
The last two values in each row seem a bit strange, as they are not nice<br />
multiples of the first entry which is usually thought of as the length of an<br />
eighth note. The last row has garbage values in those positions as that is the<br />
start of another data table, so they are not even listed here.<br />
<br />
'''TODO''' Check what values are used in vanilla.<br />
<br />
==== Pitch LUT ====<br />
<br />
This table is used to detemine the pitch of a note. The note data is stored as<br />
described above, and the fact that the least significant bit is masked out is<br />
advantageous since the pulse channels can use 11 bits of timer data, so each<br />
entry in this table is actually two bytes wide.<br />
<br />
Rather than show the raw bytes here, it's more useful to show the rough note<br />
that those values represent. If the raw values are interesting to you, check<br />
the ROM for them. It's worth noting that some of the higher notes are several<br />
cents off from the listed note.<br />
<br />
{| class="wikitable"<br />
|+Pitch LUT <code>$918F</code><br />
| || 00|| 02|| 04|| 06|| 08|| 0a|| 0c|| 0e<br />
|-<br />
|00|| C3||---|| E3|| G3||G#3|| A3||A#3|| B3<br />
|-<br />
|10|| C4||C#4|| D4||D#4|| E4|| F4||F#4|| G4<br />
|-<br />
|20||G#4|| A4||A#4|| B4|| C5||C#5|| D5||D#5<br />
|-<br />
|30|| E5|| F5||F#5|| G5|| A5||A#5|| B5||C#3<br />
|-<br />
|40|| D3||D#3|| F3||F#3||G#5|| C6||C#6|| D6<br />
|-<br />
|50||D#6|| E6|| F6||F#6|| G6||G#6|| A6||A#6<br />
|-<br />
|60|| B6|| C7||C#7|| D7||D#7|| E7|| F7||F#7<br />
|-<br />
|70|| G7||G#7|| A7||A#7|| B7|| C8<br />
|}<br />
<br />
Note that although the table goes through <code>$7A</code> values above<br />
<code>$3E</code> aren't usable due to the 5 bit limit for pitch data.<br />
<br />
Value <code>$02</code> represents a rest.<br />
<br />
==== Noise Samples ====<br />
<br />
Several sound effects use the same routine to load "samples" for the noise<br />
channel to play. These values have the noise volume in the high nybble and the<br />
noise period in the low nybble.<br />
<br />
$90E8 - Sword slash<br />
$9123 - Enemy hurt<br />
$912C - Crumble block<br />
<br />
=== Variables ===<br />
<br />
This is just a dump of RAM addresses used by the music engine and a short<br />
description of what they are.<br />
<br />
$00E0 - Current phrase note data address (low byte)<br />
$00E1 - Current phrase note data address (high byte)<br />
$00E2 - Song offset, converted from song id to be an index instead of a bit field<br />
$00E3 - Current phrase index<br />
$00E4 - Drums loop start<br />
$00E5 - Tempo<br />
$00E6 - Pulse 1 low bits (used for vibrato effect)<br />
$00E7 - Pulse 2 low bits (used for vibrato effect)<br />
$00E8 - Pitch storage, temporary<br />
$00E9 - Play sound effect<br />
$00EA - Disable music<br />
$00EB - Request new song<br />
$00EC - Play sound effect<br />
$00ED - Play sound effect<br />
$00EE - Play sound effect<br />
$00EF - Play sound effect<br />
<br />
$0707 - Current world<br />
$075F - Queued song, loaded after screen transitions<br />
$07DB - Song to resume after fanfare<br />
$07DF - ??? Likely sound effect flag for pulse 1 channel override<br />
<br />
$07E0 - ??? Likely sound effect flag for noise channel<br />
$07E2 - Pulse 2 envelope index<br />
$07E3 - Pulse 1 envelope index<br />
$07E4 - Drums current note duration<br />
$07E5 - Bass current note duration<br />
$07E6 - Harmony current note duration<br />
$07E7 - Melody current note duration<br />
$07E8 - Drums next note index<br />
$07E9 - Bass next note index<br />
$07EA - Harmony next note index<br />
$07EB - Melody next note index<br />
<br />
$07F5 - Sound FX counter<br />
<br />
$07FB - Current song<br />
$07FD - Current SFX (ED)<br />
$07FE - ??? Likely sound effect flag for pulse 2 channel override<br />
$07FF - ??? Likely sound effect flag for pulse 1 channel override<br />
</code><br />
<br />
=== Routines ===<br />
<br />
This is a non-exhaustive list of the routines in bank 6 involving the playing of<br />
music and sound effects. Each routine also lists its address so you can search<br />
in a disassembly for the actual code for that routine if these descriptions<br />
aren't clear.<br />
<br />
==== Main Music Loop <code>$9000</code> ====<br />
<br />
Checks that the music disable flag is off, then runs several SFX routines.<br />
After the SFX routines, the main music routine runs. After all this, various<br />
music related memory locations are cleared.<br />
<br />
==== Configure Pulse1 Channel <code>$9031</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4000</code> and <code>$4001</code><br />
respectively.<br />
<br />
==== Configure Pulse2 Channel <code>$9038</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4004</code> and <code>$4005</code><br />
respectively.<br />
<br />
==== Play Note Pulse1 <code>$9042</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 1 channel.<br />
<br />
==== Play Note <code>$9044</code> ====<br />
<br />
Called by the various play note routines. Takes a pitch index in register a and<br />
uses register x as a channel selector. For the pulse channels, this routine<br />
also saves the lower 8 bits of the APU timer register to <code>$E6</code> or <code>$E7</code> which<br />
are used for a vibrato effect.<br />
<br />
==== Play Note Pulse2 <code>$9067</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 2 channel.<br />
<br />
==== Play Note Triangle <code>$906B</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the triangle channel.<br />
<br />
==== Get Note Duration <code>$906F</code> ====<br />
<br />
Takes note data in register a and looks up the duration. The original note<br />
data is saved in register x and the result of the duration lookup is put in<br />
register a. The duration lookup is offset by the tempo stored in <code>$E5</code>.<br />
<br />
==== Vibrato Pulse1 <code>$9089</code> ====<br />
<br />
Applies a vibrato effect on the pulse 1 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato Pulse2 <code>$9097</code> ====<br />
<br />
Applies a vibrato effect on the pulse 2 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato <code>$909E</code> ====<br />
<br />
Takes the duration of the note remaining in register a, the low bits of the APU<br />
timer in register y, and the channel to use in register x. This is called by<br />
the other vibrato routines after setting x appropriately.<br />
<br />
Uses the <code>$04</code> bit of the duration to either add or subtract 2 from the low<br />
timer bits. Only the low bits are used because writing to the high bits resets<br />
the phase of the channel which can cause clicks. None of the notes from the<br />
pitch LUT are close enough to the boundary for the change to require the high<br />
bits to change anyway, so this works out fine.<br />
<br />
==== Play E9 SFX <code>$920B</code> ====<br />
<br />
Plays the sound effect requested in <code>$E9</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EF SFX <code>$92F4</code> ====<br />
<br />
Plays the sound effect requested in <code>$EF</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EE SFX <code>$9408</code> ====<br />
<br />
Plays the sound effect requested in <code>$EE</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Noise <code>$959D</code> ====<br />
<br />
Configures the APU noise registers to make a noise burst. Takes configuration<br />
for registers <code>$400F</code>, <code>$400E</code>, and <code>$400C</code> in registers y, x, and a.<br />
<br />
==== Crumble Bridge SFX <code>$956C</code> ====<br />
<br />
Starts playing the sound effect for a crumble bridge crumbling. This uses both<br />
the noise and the triangle channels so it sets flags to disable the music on<br />
those channels. Continues with SFX Noise Decay.<br />
<br />
==== SFX Noise Decay <code>$9587</code> ====<br />
<br />
Counts down the timer in <code>$07F5</code> and turns off the noise when it reaches 0.<br />
Also clears the flag for the ED sound effect in <code>$07FD</code>.<br />
<br />
==== Play ED SFX <code>$95A7</code> ====<br />
<br />
Plays the sound effect request in <code>$ED</code> or continues the sound effect saved in<br />
<code>$07FD</code>. Existing sound effects which are higher than the current sound effect<br />
will be ignored. If the same sound effect is requested that is already playing,<br />
it will restart the sound effect except for <code>$80</code> which gives priority to<br />
continuing. When the sound is continued instead of newly played, the decay<br />
routine will be called instead.<br />
<br />
; <code>$02</code><br />
: Crumble Bridge<br />
; <code>$04</code> and <code>$10</code><br />
: Crumble Block / Enemy Hurt<br />
; <code>$20</code> and <code>$80</code><br />
: Sword Strike<br />
; <code>$40</code><br />
: Very short noise burst, probably unused. Doesn't store the effect, and doesn't have an associated decay.<br />
<br />
==== Crumble Block / Enemy Hurt SFX <code>$95E6</code> ====<br />
<br />
Starts playing the sound of a block breaking or an enemy getting hurt.<br />
<br />
==== Crumble Block / Enemy Hurt SFX Decay <code>$95EE</code> ====<br />
<br />
Looks up noise register values based on the timer and the sound effect value.<br />
Crumble Block samples are at <code>$912C</code> while Enemy Hurt is at <code>$9123</code>. Continues<br />
on to Play Noise Samples.<br />
<br />
==== Play Noise Samples <code>$9612</code> ====<br />
<br />
Takes a sample value in register a. The low four bits of this are used to set<br />
the noise period via APU register <code>$400E</code>. The high four bits are used to set<br />
the noise volume via APU register <code>$400C</code>.<br />
<br />
Continues on the SFX Noise Decay process.<br />
<br />
==== Sword Strike SFX <code>$9604</code> ====<br />
<br />
Starts playing the sound of swinging your sword. This looks up samples based on<br />
the duration left at <code>$90E8</code> and plays them via Play Noise Samples.<br />
<br />
==== Play EC SFX <code>$990B</code> ====<br />
<br />
Plays the sound effect requested in <code>$EC</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Music <code>$9B18</code> ====<br />
<br />
Plays the music for the game.<br />
<br />
Runs Load Song if a new song is requested in <code>$EB</code>. Otherwise, runs Play Notes<br />
if the current song is set in <code>$07FB</code>. If neither of these is true, do nothing.<br />
<br />
==== Next Song <code>$9B24</code> ====<br />
<br />
Checks if the previous song should loop. If not, calls Mute All and returns.<br />
<br />
If the previous song was <code>$01</code> (the "intro" to the main theme), sets the next<br />
song to <code>$02</code> (the main theme loop).<br />
<br />
If the previous song was <code>$10</code> (the item get / level up fanfare), sets the<br />
current song from <code>$07DB</code>. Otherwise, leaves the current song the same as the<br />
previous song.<br />
<br />
Proceeds to Load Song.<br />
<br />
==== Mute All <code>$9B3B</code> ====<br />
<br />
Clears the current song at <code>$07FB</code> and sets the APU registers to mute the volume<br />
on both pulse channels, the triangle channel, and the noise channel.<br />
<br />
==== Load Song <code>$9B61</code> ====<br />
<br />
Takes a song id in register a and preps some variables for that song.<br />
<br />
If the song is <code>$10</code> (item get / level up fanfare) then it first saves the<br />
previous song to <code>$07FB</code> if it is less than <code>$10</code> so that the previous music<br />
will resume after the fanfare.<br />
<br />
Sets the phrase counter at <code>$E3</code> to 0 and the song offset at <code>$E2</code> based on the<br />
song id. Song ids are a bit field, and the song offset is the position of the<br />
lowest bit in the song id for indexing into the song table.<br />
<br />
Proceeds to Load Song Data.<br />
<br />
==== Load Song Data <code>$9B80</code> ====<br />
<br />
Loads the music variables based on the current world and current song offset.<br />
<br />
There are four blocks of code that are basically the same, for each of the four<br />
different music tables. Each one just uses a different position for the tables<br />
to load.<br />
<br />
Based on the current world in <code>$0707</code> it loads data from these offsets:<br />
<br />
<code>$00</code><br />
: Overworld music - <code>$9B87</code><br />
<code>$01</code> or <code>$02</code><br />
: Town music - <code>$9BC6</code><br />
<code>$03</code> or <code>$04</code><br />
: Palace music - <code>$9C05</code><br />
<code>$05</code> or higher<br />
: Great Palace music - <code>$9C42</code><br />
<br />
First, uses the song offset in <code>$E2</code> to index into the song table at the base<br />
offset given above.<br />
<br />
The phrase counter at <code>$E3</code> is added to that and used as in index again to<br />
retrieve the current phrase offset. If the current phrase offset is <code>$00</code> that<br />
means the song is over and the process goes back to the Next Song routine.<br />
<br />
Otherwise, the following structure is read at the base offset above + phrase<br />
offset just calculated.<br />
<br />
* <code>$E5</code> Tempo<br />
* <code>$E0</code> Note Data Low<br />
* <code>$E1</code> Note Data High<br />
* <code>$07E9</code> Bass Note Pointer<br />
* <code>$07EA</code> Harmony Note Pointer<br />
* <code>$07E8</code> Drum Note Pointer<br />
<br />
After this, the drum loop start point at <code>$E4</code> is also set to the same value as<br />
the drum note pointer. The melody note pointer at <code>$07EB</code> is set to <code>$00</code>, and<br />
all the durations (melody at <code>$07E7</code>, harmony at <code>$07E6</code>, bass at <code>$07E5</code>, and<br />
drums at <code>$07E4</code>) are set to <code>$01</code>.<br />
<br />
Proceeds to Play Notes.<br />
<br />
==== Play Notes ====<br />
<br />
This routine is broken into four major and similar sections: one each for<br />
melody, harmony, bass, and drums. The general process is as follows:<br />
<br />
decrement duration<br />
if duration == 0 {<br />
load next note<br />
increment note pointer<br />
set duration for note<br />
if no overriding sound effect {<br />
play note on appropriate channel<br />
}<br />
}<br />
<br />
Some channels have unique processing at different points in this. For example,<br />
the melody note data is null terminated, so if the loaded note in <code>$00</code> then the<br />
routine will jump to Load Song Data instead to go to the next phrase. If the<br />
drums channel gets a <code>$00</code> note it will reset the drums note pointer to the<br />
drums loop start and repeat the phrase. The bass and harmony channels don't<br />
have this looping behavior. This means that if the bass or harmony channels<br />
aren't long enough, the engine will happily just play whatever data comes next<br />
in the ROM.<br />
<br />
The melody is played on pulse 2 channel, the harmony on pulse 1 (which gets<br />
subverted by sound effects that need just one pulse channel), the bass on the<br />
triangle channel, and the drums on the noise channel.<br />
<br />
For the pulse channels, after the note is played, the envelope counter for that<br />
channel (<code>$07E2</code> for pulse 1, <code>$07E3</code> for pulse 2) is set. Normally the<br />
envelope is set to <code>$2F</code> but song <code>$40</code> (crystal fanfare and final boss music)<br />
sets it to <code>$18</code> instead. The envelope is not set if no note was played because<br />
the pitch index was <code>$02</code> which indicates a rest.<br />
<br />
Also for the pulse channels, after the above pseudocode, the vibrato and<br />
enveloping happens as long as there is no overriding sound effect. The envelope<br />
works by checking the envelope counter set previously and decrementing it. The<br />
counter value is halved and used to look up the envelope value in the LUT at<br />
<code>$9135</code>. These values are written directly to APU register <code>$4000</code> or <code>$4004</code><br />
depending on the channel.<br />
<br />
The bass channel has one special handling as well. The APU register <code>$4008</code> is<br />
set differently based on the current song id. For song <code>$10</code> (item get / level<br />
up fanfare) the register is set to <code>$60</code> but all other songs use <code>$1f</code>.<br />
<br />
The noise channel is not affect at all by the pitch. Any pitch value that is<br />
non zero will play a burst of noise.</div>Bentglasstubehttp://wiki.bindingforce.net/index.php?title=Music_Engine_Description&diff=333Music Engine Description2021-09-26T04:32:06Z<p>Bentglasstube: Small formatting cleanup</p>
<hr />
<div>There are two separate music engines in Zelda 2. Both are in bank 6 (along with<br />
the song data). The music engine for the title screen resides at $8000 and the<br />
engine for the rest of the game is at $9000. Each of these engines is called<br />
once per frame during the appropriate part of the game.<br />
<br />
== Title Music Engine ==<br />
<br />
'''TODO''' document further.<br />
<br />
== Main Music Engine ==<br />
<br />
The main loop for starts at bank 6 $9000<br />
<br />
=== Data Tables ===<br />
<br />
There are several data tables used by the music engine.<br />
<br />
==== Pulse Envelope ====<br />
<br />
This table is used to set the volume of the pulse channels over time. The index<br />
used starts at a certain value and decrements, so the table is in reverse order.<br />
The index is halved before use, so each value lasts two frames.<br />
<br />
{| class="wikitable"<br />
|+ Pulse Envelope <code>$9135</code><br />
|90||91||91||91||92||92||92||92<br />
|-<br />
|93||93||94||94||94||95||95||95<br />
|-<br />
|96||96||96||97||97||97||98||98<br />
|}<br />
<br />
==== Duration LUT ====<br />
<br />
This table is used to determine the duration of a note. The note data is stored<br />
with 5 bits of pitch information and 3 bits of duration, as such:<br />
<br />
D1 D0 P4 P3 P2 P1 P0 D2<br />
<br />
The Get Note Duration routine shifts things around to get the D bits into the<br />
three least significant bits and masks it before use. This value is then added<br />
to the tempo value in <code>$E5</code> which is always a multiple of 8 to index<br />
into the following table:<br />
<br />
{| class="wikitable"<br />
|+Duration LUT <code>$914D</code><br />
|'''00'''||04||0C||08||10||18||20||05||06<br />
|-<br />
|'''08'''||04||0F||09||12||1B||24||06||06<br />
|-<br />
|'''10'''||05||0F||0A||14||1E||28||07||06<br />
|-<br />
|'''18'''||06||12||0C||18||24||30||08||10<br />
|-<br />
|'''20'''||07||15||0E||1C||2A||38||13||12<br />
|-<br />
|'''28'''||07||15||0E||1C||2A||38||XX||XX<br />
|}<br />
<br />
The last two values in each row seem a bit strange, as they are not nice<br />
multiples of the first entry which is usually thought of as the length of an<br />
eighth note. The last row has garbage values in those positions as that is the<br />
start of another data table, so they are not even listed here.<br />
<br />
'''TODO''' Check what values are used in vanilla.<br />
<br />
==== Pitch LUT ====<br />
<br />
This table is used to detemine the pitch of a note. The note data is stored as<br />
described above, and the fact that the least significant bit is masked out is<br />
advantageous since the pulse channels can use 11 bits of timer data, so each<br />
entry in this table is actually two bytes wide.<br />
<br />
Rather than show the raw bytes here, it's more useful to show the rough note<br />
that those values represent. If the raw values are interesting to you, check<br />
the ROM for them. It's worth noting that some of the higher notes are several<br />
cents off from the listed note.<br />
<br />
{| class="wikitable"<br />
|+Pitch LUT <code>$918F</code><br />
| || 00|| 02|| 04|| 06|| 08|| 0a|| 0c|| 0e<br />
|-<br />
|00|| C3||---|| E3|| G3||G#3|| A3||A#3|| B3<br />
|-<br />
|10|| C4||C#4|| D4||D#4|| E4|| F4||F#4|| G4<br />
|-<br />
|20||G#4|| A4||A#4|| B4|| C5||C#5|| D5||D#5<br />
|-<br />
|30|| E5|| F5||F#5|| G5|| A5||A#5|| B5||C#3<br />
|-<br />
|40|| D3||D#3|| F3||F#3||G#5|| C6||C#6|| D6<br />
|-<br />
|50||D#6|| E6|| F6||F#6|| G6||G#6|| A6||A#6<br />
|-<br />
|60|| B6|| C7||C#7|| D7||D#7|| E7|| F7||F#7<br />
|-<br />
|70|| G7||G#7|| A7||A#7|| B7|| C8<br />
|}<br />
<br />
Note that although the table goes through <code>$7A</code> values above<br />
<code>$3E</code> aren't usable due to the 5 bit limit for pitch data.<br />
<br />
Value <code>$02</code> represents a rest.<br />
<br />
==== Noise Samples ====<br />
<br />
Several sound effects use the same routine to load "samples" for the noise<br />
channel to play. These values have the noise volume in the high nybble and the<br />
noise period in the low nybble.<br />
<br />
$90E8 - Sword slash<br />
$9123 - Enemy hurt<br />
$912C - Crumble block<br />
<br />
=== Variables ===<br />
<br />
This is just a dump of RAM addresses used by the music engine and a short<br />
description of what they are.<br />
<br />
$00E0 - Current phrase note data address (low byte)<br />
$00E1 - Current phrase note data address (high byte)<br />
$00E2 - Song offset, converted from song id to be an index instead of a bit field<br />
$00E3 - Current phrase index<br />
$00E4 - Drums loop start<br />
$00E5 - Tempo<br />
$00E6 - Pulse 1 low bits (used for vibrato effect)<br />
$00E7 - Pulse 2 low bits (used for vibrato effect)<br />
$00E8 - Pitch storage, temporary<br />
$00E9 - Play sound effect<br />
$00EA - Disable music<br />
$00EB - Request new song<br />
$00EC - Play sound effect<br />
$00ED - Play sound effect<br />
$00EE - Play sound effect<br />
$00EF - Play sound effect<br />
<br />
$0707 - Current world<br />
$075F - Queued song, loaded after screen transitions<br />
$07DB - Song to resume after fanfare<br />
$07DF - ??? Likely sound effect flag for pulse 1 channel override<br />
<br />
$07E0 - ??? Likely sound effect flag for noise channel<br />
$07E2 - Pulse 2 envelope index<br />
$07E3 - Pulse 1 envelope index<br />
$07E4 - Drums current note duration<br />
$07E5 - Bass current note duration<br />
$07E6 - Harmony current note duration<br />
$07E7 - Melody current note duration<br />
$07E8 - Drums next note index<br />
$07E9 - Bass next note index<br />
$07EA - Harmony next note index<br />
$07EB - Melody next note index<br />
<br />
$07F5 - Sound FX counter<br />
<br />
$07FB - Current song<br />
$07FD - Current SFX (ED)<br />
$07FE - ??? Likely sound effect flag for pulse 2 channel override<br />
$07FF - ??? Likely sound effect flag for pulse 1 channel override<br />
</code><br />
<br />
=== Routines ===<br />
<br />
This is a non-exhaustive list of the routines in bank 6 involving the playing of<br />
music and sound effects. Each routine also lists its address so you can search<br />
in a disassembly for the actual code for that routine if these descriptions<br />
aren't clear.<br />
<br />
==== Main Music Loop <code>$9000</code> ====<br />
<br />
Checks that the music disable flag is off, then runs several SFX routines.<br />
After the SFX routines, the main music routine runs. After all this, various<br />
music related memory locations are cleared.<br />
<br />
==== Configure Pulse1 Channel <code>$9031</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4000</code> and <code>$4001</code><br />
respectively.<br />
<br />
==== Configure Pulse2 Channel <code>$9038</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4004</code> and <code>$4005</code><br />
respectively.<br />
<br />
==== Play Note Pulse1 <code>$9042</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 1 channel.<br />
<br />
==== Play Note <code>$9044</code> ====<br />
<br />
Called by the various play note routines. Takes a pitch index in register a and<br />
uses register x as a channel selector. For the pulse channels, this routine<br />
also saves the lower 8 bits of the APU timer register to <code>$E6</code> or <code>$E7</code> which<br />
are used for a vibrato effect.<br />
<br />
==== Play Note Pulse2 <code>$9067</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 2 channel.<br />
<br />
==== Play Note Triangle <code>$906B</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the triangle channel.<br />
<br />
==== Get Note Duration <code>$906F</code> ====<br />
<br />
Takes note data in register a and looks up the duration. The original note<br />
data is saved in register x and the result of the duration lookup is put in<br />
register a. The duration lookup is offset by the tempo stored in <code>$E5</code>.<br />
<br />
==== Vibrato Pulse1 <code>$9089</code> ====<br />
<br />
Applies a vibrato effect on the pulse 1 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato Pulse2 <code>$9097</code> ====<br />
<br />
Applies a vibrato effect on the pulse 2 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato <code>$909E</code> ====<br />
<br />
Takes the duration of the note remaining in register a, the low bits of the APU<br />
timer in register y, and the channel to use in register x. This is called by<br />
the other vibrato routines after setting x appropriately.<br />
<br />
Uses the <code>$04</code> bit of the duration to either add or subtract 2 from the low<br />
timer bits. Only the low bits are used because writing to the high bits resets<br />
the phase of the channel which can cause clicks. None of the notes from the<br />
pitch LUT are close enough to the boundary for the change to require the high<br />
bits to change anyway, so this works out fine.<br />
<br />
==== Play E9 SFX <code>$920B</code> ====<br />
<br />
Plays the sound effect requested in <code>$E9</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EF SFX <code>$92F4</code> ====<br />
<br />
Plays the sound effect requested in <code>$EF</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EE SFX <code>$9408</code> ====<br />
<br />
Plays the sound effect requested in <code>$EE</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Noise <code>$959D</code> ====<br />
<br />
Configures the APU noise registers to make a noise burst. Takes configuration<br />
for registers <code>$400F</code>, <code>$400E</code>, and <code>$400C</code> in registers y, x, and a.<br />
<br />
==== Crumble Bridge SFX <code>$956C</code> ====<br />
<br />
Starts playing the sound effect for a crumble bridge crumbling. This uses both<br />
the noise and the triangle channels so it sets flags to disable the music on<br />
those channels. Continues with SFX Noise Decay.<br />
<br />
==== SFX Noise Decay <code>$9587</code> ====<br />
<br />
Counts down the timer in <code>$07F5</code> and turns off the noise when it reaches 0.<br />
Also clears the flag for the ED sound effect in <code>$07FD</code>.<br />
<br />
==== Play ED SFX <code>$95A7</code> ====<br />
<br />
Plays the sound effect request in <code>$ED</code> or continues the sound effect saved in<br />
<code>$07FD</code>. Existing sound effects which are higher than the current sound effect<br />
will be ignored. If the same sound effect is requested that is already playing,<br />
it will restart the sound effect except for <code>$80</code> which gives priority to<br />
continuing. When the sound is continued instead of newly played, the decay<br />
routine will be called instead.<br />
<br />
; <code>$02</code><br />
: Crumble Bridge<br />
; <code>$04</code> and <code>$10</code><br />
: Crumble Block / Enemy Hurt<br />
; <code>$20</code> and <code>$80</code><br />
: Sword Strike<br />
; <code>$40</code><br />
: Very short noise burst, probably unused. Doesn't store the effect, and doesn't have an associated decay.<br />
<br />
==== Crumble Block / Enemy Hurt SFX <code>$95E6</code> ====<br />
<br />
Starts playing the sound of a block breaking or an enemy getting hurt.<br />
<br />
==== Crumble Block / Enemy Hurt SFX Decay <code>$95EE</code> ====<br />
<br />
Looks up noise register values based on the timer and the sound effect value.<br />
Crumble Block samples are at <code>$912C</code> while Enemy Hurt is at <code>$9123</code>. Continues<br />
on to Play Noise Samples.<br />
<br />
==== Play Noise Samples <code>$9612</code> ====<br />
<br />
Takes a sample value in register a. The low four bits of this are used to set<br />
the noise period via APU register <code>$400E</code>. The high four bits are used to set<br />
the noise volume via APU register <code>$400C</code>.<br />
<br />
Continues on the SFX Noise Decay process.<br />
<br />
==== Sword Strike SFX <code>$9604</code> ====<br />
<br />
Starts playing the sound of swinging your sword. This looks up samples based on<br />
the duration left at <code>$90E8</code> and plays them via Play Noise Samples.<br />
<br />
==== Play EC SFX <code>$990B</code> ====<br />
<br />
Plays the sound effect requested in <code>$EC</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Music <code>$9B18</code> ====<br />
<br />
Plays the music for the game.<br />
<br />
Runs Load Song if a new song is requested in <code>$EB</code>. Otherwise, runs Play Notes<br />
if the current song is set in <code>$07FB</code>. If neither of these is true, do nothing.<br />
<br />
==== Next Song <code>$9B24</code> ====<br />
<br />
Checks if the previous song should loop. If not, calls Mute All and returns.<br />
<br />
If the previous song was <code>$01</code> (the "intro" to the main theme), sets the next<br />
song to <code>$02</code> (the main theme loop).<br />
<br />
If the previous song was <code>$10</code> (the item get / level up fanfare), sets the<br />
current song from <code>$07DB</code>. Otherwise, leaves the current song the same as the<br />
previous song.<br />
<br />
Proceeds to Load Song.<br />
<br />
==== Mute All <code>$9B3B</code> ====<br />
<br />
Clears the current song at <code>$07FB</code> and sets the APU registers to mute the volume<br />
on both pulse channels, the triangle channel, and the noise channel.<br />
<br />
==== Load Song <code>$9B61</code> ====<br />
<br />
Takes a song id in register a and preps some variables for that song.<br />
<br />
If the song is <code>$10</code> (item get / level up fanfare) then it first saves the<br />
previous song to <code>$07FB</code> if it is less than <code>$10</code> so that the previous music<br />
will resume after the fanfare.<br />
<br />
Sets the phrase counter at <code>$E3</code> to 0 and the song offset at <code>$E2</code> based on the<br />
song id. Song ids are a bit field, and the song offset is the position of the<br />
lowest bit in the song id for indexing into the song table.<br />
<br />
Proceeds to Load Song Data.<br />
<br />
==== Load Song Data <code>$9B80</code> ====<br />
<br />
Loads the music variables based on the current world and current song offset.<br />
<br />
There are four blocks of code that are basically the same, for each of the four<br />
different music tables. Each one just uses a different position for the tables<br />
to load.<br />
<br />
Based on the current world in <code>$0707</code> it loads data from these offsets:<br />
<br />
<code>$00</code><br />
: Overworld music - <code>$9B87</code><br />
<code>$01</code> or <code>$02</code><br />
: Town music - <code>$9BC6</code><br />
<code>$03</code> or <code>$04</code><br />
: Palace music - <code>$9C05</code><br />
<code>$05</code> or higher<br />
: Great Palace music - <code>$9C42</code><br />
<br />
First, uses the song offset in <code>$E2</code> to index into the song table at the base<br />
offset given above.<br />
<br />
The phrase counter at <code>$E3</code> is added to that and used as in index again to<br />
retrieve the current phrase offset. If the current phrase offset is <code>$00</code> that<br />
means the song is over and the process goes back to the Next Song routine.<br />
<br />
Otherwise, the following structure is read at the base offset above + phrase<br />
offset just calculated.<br />
<br />
* <code>$E5</code> Tempo<br />
* <code>$E0</code> Note Data Low<br />
* <code>$E1</code> Note Data High<br />
* <code>$07E9</code> Bass Note Pointer<br />
* <code>$07EA</code> Harmony Note Pointer<br />
* <code>$07E8</code> Drum Note Pointer<br />
<br />
After this, the drum loop start point at <code>$E4</code> is also set to the same value as<br />
the drum note pointer. The melody note pointer at <code>$07EB</code> is set to <code>$00</code>, and<br />
all the durations (melody at <code>$07E7</code>, harmony at <code>$07E6</code>, bass at <code>$07E5</code>, and<br />
drums at <code>$07E4</code>) are set to <code>$01</code>.<br />
<br />
Proceeds to Play Notes.<br />
<br />
==== Play Notes ====<br />
<br />
This routine is broken into four major and similar sections: one each for<br />
melody, harmony, bass, and drums. The general process is as follows:<br />
<br />
decrement duration<br />
if duration == 0 {<br />
load next note<br />
increment note pointer<br />
set duration for note<br />
if no overriding sound effect {<br />
play note on appropriate channel<br />
}<br />
}<br />
<br />
Some channels have unique processing at different points in this. For example,<br />
the melody note data is null terminated, so if the loaded note in <code>$00</code> then the<br />
routine will jump to Load Song Data instead to go to the next phrase. If the<br />
drums channel gets a <code>$00</code> note it will reset the drums note pointer to the<br />
drums loop start and repeat the phrase. The bass and harmony channels don't<br />
have this looping behavior. This means that if the bass or harmony channels<br />
aren't long enough, the engine will happily just play whatever data comes next<br />
in the ROM.<br />
<br />
The melody is played on pulse 2 channel, the harmony on pulse 1 (which gets<br />
subverted by sound effects that need just one pulse channel), the bass on the<br />
triangle channel, and the drums on the noise channel.<br />
<br />
For the pulse channels, after the note is played, the envelope counter for that<br />
channel (<code>$07E2</code> for pulse 1, <code>$07E3</code> for pulse 2) is set. Normally the<br />
envelope is set to <code>$2F</code> but song <code>$40</code> (crystal fanfare and final boss music)<br />
sets it to <code>$18</code> instead. The envelope is not set if no note was played because<br />
the pitch index was <code>$02</code> which indicates a rest.<br />
<br />
Also for the pulse channels, after the above pseudocode, the vibrato and<br />
enveloping happens as long as there is no overriding sound effect. The envelope<br />
works by checking the envelope counter set previously and decrementing it. The<br />
counter value is halved and used to look up the envelope value in the LUT at<br />
<code>$9135</code>. These values are written directly to APU register <code>$4000</code> or <code>$4004</code><br />
depending on the channel.<br />
<br />
The bass channel has one special handling as well. The APU register <code>$4008</code> is<br />
set differently based on the current song id. For song <code>$10</code> (item get / level<br />
up fanfare) the register is set to <code>$60</code> but all other songs use <code>$1f</code>.<br />
<br />
The noise channel is not affect at all by the pitch. Any pitch value that is<br />
non zero will play a burst of noise.</div>Bentglasstubehttp://wiki.bindingforce.net/index.php?title=Music_Engine_Description&diff=332Music Engine Description2021-09-26T04:28:09Z<p>Bentglasstube: Add more data tables and some information on variables used.</p>
<hr />
<div>There are two separate music engines in Zelda 2. Both are in bank 6 (along with<br />
the song data). The music engine for the title screen resides at $8000 and the<br />
engine for the rest of the game is at $9000. Each of these engines is called<br />
once per frame during the appropriate part of the game.<br />
<br />
== Title Music Engine ==<br />
<br />
'''TODO''' document further.<br />
<br />
== Main Music Engine ==<br />
<br />
The main loop for starts at bank 6 $9000<br />
<br />
=== Data Tables ===<br />
<br />
There are several data tables used by the music engine.<br />
<br />
==== Pulse Envelope ====<br />
<br />
This table is used to set the volume of the pulse channels over time. The index<br />
used starts at a certain value and decrements, so the table is in reverse order.<br />
The index is halved before use, so each value lasts two frames.<br />
<br />
{| class="wikitable"<br />
|+ Pulse Envelope <code>$9135</code><br />
|90||91||91||91||92||92||92||92<br />
|-<br />
|93||93||94||94||94||95||95||95<br />
|-<br />
|96||96||96||97||97||97||98||98<br />
|}<br />
<br />
==== Duration LUT ====<br />
<br />
This table is used to determine the duration of a note. The note data is stored<br />
with 5 bits of pitch information and 3 bits of duration, as such:<br />
<br />
{| class="wikitable"<br />
|D1||D0||P4||P3||P2||P1||P0||D2<br />
|}<br />
<br />
The Get Note Duration routine shifts things around to get the D bits into the<br />
three least significant bits and masks it before use. This value is then added<br />
to the tempo value in <code>$E5</code> which is always a multiple of 8 to index<br />
into the following table:<br />
<br />
{| class="wikitable"<br />
|+Duration LUT <code>$914D</code><br />
|'''00'''||04||0C||08||10||18||20||05||06<br />
|-<br />
|'''08'''||04||0F||09||12||1B||24||06||06<br />
|-<br />
|'''10'''||05||0F||0A||14||1E||28||07||06<br />
|-<br />
|'''18'''||06||12||0C||18||24||30||08||10<br />
|-<br />
|'''20'''||07||15||0E||1C||2A||38||13||12<br />
|-<br />
|'''28'''||07||15||0E||1C||2A||38||XX||XX<br />
|}<br />
<br />
The last two values in each row seem a bit strange, as they are not nice<br />
multiples of the first entry which is usually thought of as the length of an<br />
eighth note. The last row has garbage values in those positions as that is the<br />
start of another data table, so they are not even listed here.<br />
<br />
'''TODO''' Check what values are used in vanilla.<br />
<br />
==== Pitch LUT ====<br />
<br />
This table is used to detemine the pitch of a note. The note data is stored as<br />
described above, and the fact that the least significant bit is masked out is<br />
advantageous since the pulse channels can use 11 bits of timer data, so each<br />
entry in this table is actually two bytes wide.<br />
<br />
Rather than show the raw bytes here, it's more useful to show the rough note<br />
that those values represent. If the raw values are interesting to you, check<br />
the ROM for them. It's worth noting that some of the higher notes are several<br />
cents off from the listed note.<br />
<br />
{| class="wikitable"<br />
|+Pitch LUT <code>$918F</code><br />
| || 00|| 02|| 04|| 06|| 08|| 0a|| 0c|| 0e<br />
|-<br />
|00|| C3||---|| E3|| G3||G#3|| A3||A#3|| B3<br />
|-<br />
|10|| C4||C#4|| D4||D#4|| E4|| F4||F#4|| G4<br />
|-<br />
|20||G#4|| A4||A#4|| B4|| C5||C#5|| D5||D#5<br />
|-<br />
|30|| E5|| F5||F#5|| G5|| A5||A#5|| B5||C#3<br />
|-<br />
|40|| D3||D#3|| F3||F#3||G#5|| C6||C#6|| D6<br />
|-<br />
|50||D#6|| E6|| F6||F#6|| G6||G#6|| A6||A#6<br />
|-<br />
|60|| B6|| C7||C#7|| D7||D#7|| E7|| F7||F#7<br />
|-<br />
|70|| G7||G#7|| A7||A#7|| B7|| C8<br />
|}<br />
<br />
Note that although the table goes through <code>$7A</code> values above<br />
<code>$3E</code> aren't usable due to the 5 bit limit for pitch data.<br />
<br />
Value <code>$02</code> represents a rest.<br />
<br />
==== Noise Samples ====<br />
<br />
Several sound effects use the same routine to load "samples" for the noise<br />
channel to play. These values have the noise volume in the high nybble and the<br />
noise period in the low nybble.<br />
<br />
$90E8 - Sword slash<br />
$9123 - Enemy hurt<br />
$912C - Crumble block<br />
<br />
=== Variables ===<br />
<br />
This is just a dump of RAM addresses used by the music engine and a short<br />
description of what they are.<br />
<br />
$00E0 - Current phrase note data address (low byte)<br />
$00E1 - Current phrase note data address (high byte)<br />
$00E2 - Song offset, converted from song id to be an index instead of a bit field<br />
$00E3 - Current phrase index<br />
$00E4 - Drums loop start<br />
$00E5 - Tempo<br />
$00E6 - Pulse 1 low bits (used for vibrato effect)<br />
$00E7 - Pulse 2 low bits (used for vibrato effect)<br />
$00E8 - Pitch storage, temporary<br />
$00E9 - Play sound effect<br />
$00EA - Disable music<br />
$00EB - Request new song<br />
$00EC - Play sound effect<br />
$00ED - Play sound effect<br />
$00EE - Play sound effect<br />
$00EF - Play sound effect<br />
<br />
$0707 - Current world<br />
$075F - Queued song, loaded after screen transitions<br />
$07DB - Song to resume after fanfare<br />
$07DF - ??? Likely sound effect flag for pulse 1 channel override<br />
<br />
$07E0 - ??? Likely sound effect flag for noise channel<br />
$07E2 - Pulse 2 envelope index<br />
$07E3 - Pulse 1 envelope index<br />
$07E4 - Drums current note duration<br />
$07E5 - Bass current note duration<br />
$07E6 - Harmony current note duration<br />
$07E7 - Melody current note duration<br />
$07E8 - Drums next note index<br />
$07E9 - Bass next note index<br />
$07EA - Harmony next note index<br />
$07EB - Melody next note index<br />
<br />
$07F5 - Sound FX counter<br />
<br />
$07FB - Current song<br />
$07FD - Current SFX (ED)<br />
$07FE - ??? Likely sound effect flag for pulse 2 channel override<br />
$07FF - ??? Likely sound effect flag for pulse 1 channel override<br />
</code><br />
<br />
=== Routines ===<br />
<br />
This is a non-exhaustive list of the routines in bank 6 involving the playing of<br />
music and sound effects. Each routine also lists its address so you can search<br />
in a disassembly for the actual code for that routine if these descriptions<br />
aren't clear.<br />
<br />
==== Main Music Loop <code>$9000</code> ====<br />
<br />
Checks that the music disable flag is off, then runs several SFX routines.<br />
After the SFX routines, the main music routine runs. After all this, various<br />
music related memory locations are cleared.<br />
<br />
==== Configure Pulse1 Channel <code>$9031</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4000</code> and <code>$4001</code><br />
respectively.<br />
<br />
==== Configure Pulse2 Channel <code>$9038</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4004</code> and <code>$4005</code><br />
respectively.<br />
<br />
==== Play Note Pulse1 <code>$9042</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 1 channel.<br />
<br />
==== Play Note <code>$9044</code> ====<br />
<br />
Called by the various play note routines. Takes a pitch index in register a and<br />
uses register x as a channel selector. For the pulse channels, this routine<br />
also saves the lower 8 bits of the APU timer register to <code>$E6</code> or <code>$E7</code> which<br />
are used for a vibrato effect.<br />
<br />
==== Play Note Pulse2 <code>$9067</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 2 channel.<br />
<br />
==== Play Note Triangle <code>$906B</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the triangle channel.<br />
<br />
==== Get Note Duration <code>$906F</code> ====<br />
<br />
Takes note data in register a and looks up the duration. The original note<br />
data is saved in register x and the result of the duration lookup is put in<br />
register a. The duration lookup is offset by the tempo stored in <code>$E5</code>.<br />
<br />
==== Vibrato Pulse1 <code>$9089</code> ====<br />
<br />
Applies a vibrato effect on the pulse 1 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato Pulse2 <code>$9097</code> ====<br />
<br />
Applies a vibrato effect on the pulse 2 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato <code>$909E</code> ====<br />
<br />
Takes the duration of the note remaining in register a, the low bits of the APU<br />
timer in register y, and the channel to use in register x. This is called by<br />
the other vibrato routines after setting x appropriately.<br />
<br />
Uses the <code>$04</code> bit of the duration to either add or subtract 2 from the low<br />
timer bits. Only the low bits are used because writing to the high bits resets<br />
the phase of the channel which can cause clicks. None of the notes from the<br />
pitch LUT are close enough to the boundary for the change to require the high<br />
bits to change anyway, so this works out fine.<br />
<br />
==== Play E9 SFX <code>$920B</code> ====<br />
<br />
Plays the sound effect requested in <code>$E9</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EF SFX <code>$92F4</code> ====<br />
<br />
Plays the sound effect requested in <code>$EF</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EE SFX <code>$9408</code> ====<br />
<br />
Plays the sound effect requested in <code>$EE</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Noise <code>$959D</code> ====<br />
<br />
Configures the APU noise registers to make a noise burst. Takes configuration<br />
for registers <code>$400F</code>, <code>$400E</code>, and <code>$400C</code> in registers y, x, and a.<br />
<br />
==== Crumble Bridge SFX <code>$956C</code> ====<br />
<br />
Starts playing the sound effect for a crumble bridge crumbling. This uses both<br />
the noise and the triangle channels so it sets flags to disable the music on<br />
those channels. Continues with SFX Noise Decay.<br />
<br />
==== SFX Noise Decay <code>$9587</code> ====<br />
<br />
Counts down the timer in <code>$07F5</code> and turns off the noise when it reaches 0.<br />
Also clears the flag for the ED sound effect in <code>$07FD</code>.<br />
<br />
==== Play ED SFX <code>$95A7</code> ====<br />
<br />
Plays the sound effect request in <code>$ED</code> or continues the sound effect saved in<br />
<code>$07FD</code>. Existing sound effects which are higher than the current sound effect<br />
will be ignored. If the same sound effect is requested that is already playing,<br />
it will restart the sound effect except for <code>$80</code> which gives priority to<br />
continuing. When the sound is continued instead of newly played, the decay<br />
routine will be called instead.<br />
<br />
; <code>$02</code><br />
: Crumble Bridge<br />
; <code>$04</code> and <code>$10</code><br />
: Crumble Block / Enemy Hurt<br />
; <code>$20</code> and <code>$80</code><br />
: Sword Strike<br />
; <code>$40</code><br />
: Very short noise burst, probably unused. Doesn't store the effect, and doesn't have an associated decay.<br />
<br />
==== Crumble Block / Enemy Hurt SFX <code>$95E6</code> ====<br />
<br />
Starts playing the sound of a block breaking or an enemy getting hurt.<br />
<br />
==== Crumble Block / Enemy Hurt SFX Decay <code>$95EE</code> ====<br />
<br />
Looks up noise register values based on the timer and the sound effect value.<br />
Crumble Block samples are at <code>$912C</code> while Enemy Hurt is at <code>$9123</code>. Continues<br />
on to Play Noise Samples.<br />
<br />
==== Play Noise Samples <code>$9612</code> ====<br />
<br />
Takes a sample value in register a. The low four bits of this are used to set<br />
the noise period via APU register <code>$400E</code>. The high four bits are used to set<br />
the noise volume via APU register <code>$400C</code>.<br />
<br />
Continues on the SFX Noise Decay process.<br />
<br />
==== Sword Strike SFX <code>$9604</code> ====<br />
<br />
Starts playing the sound of swinging your sword. This looks up samples based on<br />
the duration left at <code>$90E8</code> and plays them via Play Noise Samples.<br />
<br />
==== Play EC SFX <code>$990B</code> ====<br />
<br />
Plays the sound effect requested in <code>$EC</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Music <code>$9B18</code> ====<br />
<br />
Plays the music for the game.<br />
<br />
Runs Load Song if a new song is requested in <code>$EB</code>. Otherwise, runs Play Notes<br />
if the current song is set in <code>$07FB</code>. If neither of these is true, do nothing.<br />
<br />
==== Next Song <code>$9B24</code> ====<br />
<br />
Checks if the previous song should loop. If not, calls Mute All and returns.<br />
<br />
If the previous song was <code>$01</code> (the "intro" to the main theme), sets the next<br />
song to <code>$02</code> (the main theme loop).<br />
<br />
If the previous song was <code>$10</code> (the item get / level up fanfare), sets the<br />
current song from <code>$07DB</code>. Otherwise, leaves the current song the same as the<br />
previous song.<br />
<br />
Proceeds to Load Song.<br />
<br />
==== Mute All <code>$9B3B</code> ====<br />
<br />
Clears the current song at <code>$07FB</code> and sets the APU registers to mute the volume<br />
on both pulse channels, the triangle channel, and the noise channel.<br />
<br />
==== Load Song <code>$9B61</code> ====<br />
<br />
Takes a song id in register a and preps some variables for that song.<br />
<br />
If the song is <code>$10</code> (item get / level up fanfare) then it first saves the<br />
previous song to <code>$07FB</code> if it is less than <code>$10</code> so that the previous music<br />
will resume after the fanfare.<br />
<br />
Sets the phrase counter at <code>$E3</code> to 0 and the song offset at <code>$E2</code> based on the<br />
song id. Song ids are a bit field, and the song offset is the position of the<br />
lowest bit in the song id for indexing into the song table.<br />
<br />
Proceeds to Load Song Data.<br />
<br />
==== Load Song Data <code>$9B80</code> ====<br />
<br />
Loads the music variables based on the current world and current song offset.<br />
<br />
There are four blocks of code that are basically the same, for each of the four<br />
different music tables. Each one just uses a different position for the tables<br />
to load.<br />
<br />
Based on the current world in <code>$0707</code> it loads data from these offsets:<br />
<br />
<code>$00</code><br />
: Overworld music - <code>$9B87</code><br />
<code>$01</code> or <code>$02</code><br />
: Town music - <code>$9BC6</code><br />
<code>$03</code> or <code>$04</code><br />
: Palace music - <code>$9C05</code><br />
<code>$05</code> or higher<br />
: Great Palace music - <code>$9C42</code><br />
<br />
First, uses the song offset in <code>$E2</code> to index into the song table at the base<br />
offset given above.<br />
<br />
The phrase counter at <code>$E3</code> is added to that and used as in index again to<br />
retrieve the current phrase offset. If the current phrase offset is <code>$00</code> that<br />
means the song is over and the process goes back to the Next Song routine.<br />
<br />
Otherwise, the following structure is read at the base offset above + phrase<br />
offset just calculated.<br />
<br />
* <code>$E5</code> Tempo<br />
* <code>$E0</code> Note Data Low<br />
* <code>$E1</code> Note Data High<br />
* <code>$07E9</code> Bass Note Pointer<br />
* <code>$07EA</code> Harmony Note Pointer<br />
* <code>$07E8</code> Drum Note Pointer<br />
<br />
After this, the drum loop start point at <code>$E4</code> is also set to the same value as<br />
the drum note pointer. The melody note pointer at <code>$07EB</code> is set to <code>$00</code>, and<br />
all the durations (melody at <code>$07E7</code>, harmony at <code>$07E6</code>, bass at <code>$07E5</code>, and<br />
drums at <code>$07E4</code>) are set to <code>$01</code>.<br />
<br />
Proceeds to Play Notes.<br />
<br />
==== Play Notes ====<br />
<br />
This routine is broken into four major and similar sections: one each for<br />
melody, harmony, bass, and drums. The general process is as follows:<br />
<br />
decrement duration<br />
if duration == 0 {<br />
load next note<br />
increment note pointer<br />
set duration for note<br />
if no overriding sound effect {<br />
play note on appropriate channel<br />
}<br />
}<br />
<br />
Some channels have unique processing at different points in this. For example,<br />
the melody note data is null terminated, so if the loaded note in <code>$00</code> then the<br />
routine will jump to Load Song Data instead to go to the next phrase. If the<br />
drums channel gets a <code>$00</code> note it will reset the drums note pointer to the<br />
drums loop start and repeat the phrase. The bass and harmony channels don't<br />
have this looping behavior. This means that if the bass or harmony channels<br />
aren't long enough, the engine will happily just play whatever data comes next<br />
in the ROM.<br />
<br />
The melody is played on pulse 2 channel, the harmony on pulse 1 (which gets<br />
subverted by sound effects that need just one pulse channel), the bass on the<br />
triangle channel, and the drums on the noise channel.<br />
<br />
For the pulse channels, after the note is played, the envelope counter for that<br />
channel (<code>$07E2</code> for pulse 1, <code>$07E3</code> for pulse 2) is set. Normally the<br />
envelope is set to <code>$2F</code> but song <code>$40</code> (crystal fanfare and final boss music)<br />
sets it to <code>$18</code> instead. The envelope is not set if no note was played because<br />
the pitch index was <code>$02</code> which indicates a rest.<br />
<br />
Also for the pulse channels, after the above pseudocode, the vibrato and<br />
enveloping happens as long as there is no overriding sound effect. The envelope<br />
works by checking the envelope counter set previously and decrementing it. The<br />
counter value is halved and used to look up the envelope value in the LUT at<br />
<code>$9135</code>. These values are written directly to APU register <code>$4000</code> or <code>$4004</code><br />
depending on the channel.<br />
<br />
The bass channel has one special handling as well. The APU register <code>$4008</code> is<br />
set differently based on the current song id. For song <code>$10</code> (item get / level<br />
up fanfare) the register is set to <code>$60</code> but all other songs use <code>$1f</code>.<br />
<br />
The noise channel is not affect at all by the pitch. Any pitch value that is<br />
non zero will play a burst of noise.</div>Bentglasstubehttp://wiki.bindingforce.net/index.php?title=Music_Engine_Description&diff=331Music Engine Description2021-09-26T04:22:58Z<p>Bentglasstube: /* Load Song Data $9B80 */</p>
<hr />
<div>There are two separate music engines in Zelda 2. Both are in bank 6 (along with<br />
the song data). The music engine for the title screen resides at $8000 and the<br />
engine for the rest of the game is at $9000. Each of these engines is called<br />
once per frame during the appropriate part of the game.<br />
<br />
== Title Music Engine ==<br />
<br />
'''TODO''' document further.<br />
<br />
== Main Music Engine ==<br />
<br />
The main loop for starts at bank 6 $9000<br />
<br />
=== Data Tables ===<br />
<br />
There are several data tables used by the music engine.<br />
<br />
==== Pulse Envelope ====<br />
<br />
This table is used to set the volume of the pulse channels over time. The index<br />
used starts at a certain value and decrements, so the table is in reverse order.<br />
The index is halved before use, so each value lasts two frames.<br />
<br />
{| class="wikitable"<br />
|+ Pulse Envelope <code>$9135</code><br />
|90||91||91||91||92||92||92||92<br />
|-<br />
|93||93||94||94||94||95||95||95<br />
|-<br />
|96||96||96||97||97||97||98||98<br />
|}<br />
<br />
==== Duration LUT ====<br />
<br />
This table is used to determine the duration of a note. The note data is stored<br />
with 5 bits of pitch information and 3 bits of duration, as such:<br />
<br />
{| class="wikitable"<br />
|D1||D0||P4||P3||P2||P1||P0||D2<br />
|}<br />
<br />
The Get Note Duration routine shifts things around to get the D bits into the<br />
three least significant bits and masks it before use. This value is then added<br />
to the tempo value in <code>$E5</code> which is always a multiple of 8 to index<br />
into the following table:<br />
<br />
{| class="wikitable"<br />
|+Duration LUT <code>$914D</code><br />
|'''00'''||04||0C||08||10||18||20||05||06<br />
|-<br />
|'''08'''||04||0F||09||12||1B||24||06||06<br />
|-<br />
|'''10'''||05||0F||0A||14||1E||28||07||06<br />
|-<br />
|'''18'''||06||12||0C||18||24||30||08||10<br />
|-<br />
|'''20'''||07||15||0E||1C||2A||38||13||12<br />
|-<br />
|'''28'''||07||15||0E||1C||2A||38<br />
|}<br />
<br />
The last two values in each row seem a bit strange, as they are not nice<br />
multiples of the first entry which is usually thought of as the length of an<br />
eighth note. The last row has garbage values in those positions as that is the<br />
start of another data table, so they are not even listed here.<br />
<br />
'''TODO''' Check what values are used in vanilla.<br />
<br />
==== Pitch LUT ====<br />
<br />
This table is used to detemine the pitch of a note. The note data is stored as<br />
described above, and the fact that the least significant bit is masked out is<br />
advantageous since the pulse channels can use 11 bits of timer data, so each<br />
entry in this table is actually two bytes wide.<br />
<br />
Rather than show the raw bytes here, it's more useful to show the rough note<br />
that those values represent. If the raw values are interesting to you, check<br />
the ROM for them. It's worth noting that some of the higher notes are several<br />
cents off from the listed note.<br />
<br />
{| class="wikitable"<br />
|+Pitch LUT <code>$918F</code><br />
| || 00|| 02|| 04|| 06|| 08|| 0a|| 0c|| 0e<br />
|-<br />
|00|| C3||---|| E3|| G3||G#3|| A3||A#3|| B3<br />
|-<br />
|10|| C4||C#4|| D4||D#4|| E4|| F4||F#4|| G4<br />
|-<br />
|20||G#4|| A4||A#4|| B4|| C5||C#5|| D5||D#5<br />
|-<br />
|30|| E5|| F5||F#5|| G5|| A5||A#5|| B5||C#3<br />
|-<br />
|40|| D3||D#3|| F3||F#3||G#5|| C6||C#6|| D6<br />
|-<br />
|50||D#6|| E6|| F6||F#6|| G6||G#6|| A6||A#6<br />
|-<br />
|60|| B6|| C7||C#7|| D7||D#7|| E7|| F7||F#7<br />
|-<br />
|70|| G7||G#7|| A7||A#7|| B7|| C8<br />
|}<br />
<br />
Note that although the table goes through <code>$7A</code> values above<br />
<code>$3E</code> aren't usable due to the 5 bit limit for pitch data.<br />
<br />
Value <code>$02</code> represents a rest.<br />
<br />
=== Routines ===<br />
<br />
This is a non-exhaustive list of the routines in bank 6 involving the playing of<br />
music and sound effects. Each routine also lists its address so you can search<br />
in a disassembly for the actual code for that routine if these descriptions<br />
aren't clear.<br />
<br />
==== Main Music Loop <code>$9000</code> ====<br />
<br />
Checks that the music disable flag is off, then runs several SFX routines.<br />
After the SFX routines, the main music routine runs. After all this, various<br />
music related memory locations are cleared.<br />
<br />
==== Configure Pulse1 Channel <code>$9031</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4000</code> and <code>$4001</code><br />
respectively.<br />
<br />
==== Configure Pulse2 Channel <code>$9038</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4004</code> and <code>$4005</code><br />
respectively.<br />
<br />
==== Play Note Pulse1 <code>$9042</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 1 channel.<br />
<br />
==== Play Note <code>$9044</code> ====<br />
<br />
Called by the various play note routines. Takes a pitch index in register a and<br />
uses register x as a channel selector. For the pulse channels, this routine<br />
also saves the lower 8 bits of the APU timer register to <code>$E6</code> or <code>$E7</code> which<br />
are used for a vibrato effect.<br />
<br />
==== Play Note Pulse2 <code>$9067</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 2 channel.<br />
<br />
==== Play Note Triangle <code>$906B</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the triangle channel.<br />
<br />
==== Get Note Duration <code>$906F</code> ====<br />
<br />
Takes note data in register a and looks up the duration. The original note<br />
data is saved in register x and the result of the duration lookup is put in<br />
register a. The duration lookup is offset by the tempo stored in <code>$E5</code>.<br />
<br />
==== Vibrato Pulse1 <code>$9089</code> ====<br />
<br />
Applies a vibrato effect on the pulse 1 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato Pulse2 <code>$9097</code> ====<br />
<br />
Applies a vibrato effect on the pulse 2 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato <code>$909E</code> ====<br />
<br />
Takes the duration of the note remaining in register a, the low bits of the APU<br />
timer in register y, and the channel to use in register x. This is called by<br />
the other vibrato routines after setting x appropriately.<br />
<br />
Uses the <code>$04</code> bit of the duration to either add or subtract 2 from the low<br />
timer bits. Only the low bits are used because writing to the high bits resets<br />
the phase of the channel which can cause clicks. None of the notes from the<br />
pitch LUT are close enough to the boundary for the change to require the high<br />
bits to change anyway, so this works out fine.<br />
<br />
==== Play E9 SFX <code>$920B</code> ====<br />
<br />
Plays the sound effect requested in <code>$E9</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EF SFX <code>$92F4</code> ====<br />
<br />
Plays the sound effect requested in <code>$EF</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EE SFX <code>$9408</code> ====<br />
<br />
Plays the sound effect requested in <code>$EE</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Noise <code>$959D</code> ====<br />
<br />
Configures the APU noise registers to make a noise burst. Takes configuration<br />
for registers <code>$400F</code>, <code>$400E</code>, and <code>$400C</code> in registers y, x, and a.<br />
<br />
==== Crumble Bridge SFX <code>$956C</code> ====<br />
<br />
Starts playing the sound effect for a crumble bridge crumbling. This uses both<br />
the noise and the triangle channels so it sets flags to disable the music on<br />
those channels. Continues with SFX Noise Decay.<br />
<br />
==== SFX Noise Decay <code>$9587</code> ====<br />
<br />
Counts down the timer in <code>$07F5</code> and turns off the noise when it reaches 0.<br />
Also clears the flag for the ED sound effect in <code>$07FD</code>.<br />
<br />
==== Play ED SFX <code>$95A7</code> ====<br />
<br />
Plays the sound effect request in <code>$ED</code> or continues the sound effect saved in<br />
<code>$07FD</code>. Existing sound effects which are higher than the current sound effect<br />
will be ignored. If the same sound effect is requested that is already playing,<br />
it will restart the sound effect except for <code>$80</code> which gives priority to<br />
continuing. When the sound is continued instead of newly played, the decay<br />
routine will be called instead.<br />
<br />
; <code>$02</code><br />
: Crumble Bridge<br />
; <code>$04</code> and <code>$10</code><br />
: Crumble Block / Enemy Hurt<br />
; <code>$20</code> and <code>$80</code><br />
: Sword Strike<br />
; <code>$40</code><br />
: Very short noise burst, probably unused. Doesn't store the effect, and doesn't have an associated decay.<br />
<br />
==== Crumble Block / Enemy Hurt SFX <code>$95E6</code> ====<br />
<br />
Starts playing the sound of a block breaking or an enemy getting hurt.<br />
<br />
==== Crumble Block / Enemy Hurt SFX Decay <code>$95EE</code> ====<br />
<br />
Looks up noise register values based on the timer and the sound effect value.<br />
Crumble Block samples are at <code>$912C</code> while Enemy Hurt is at <code>$9123</code>. Continues<br />
on to Play Noise Samples.<br />
<br />
==== Play Noise Samples <code>$9612</code> ====<br />
<br />
Takes a sample value in register a. The low four bits of this are used to set<br />
the noise period via APU register <code>$400E</code>. The high four bits are used to set<br />
the noise volume via APU register <code>$400C</code>.<br />
<br />
Continues on the SFX Noise Decay process.<br />
<br />
==== Sword Strike SFX <code>$9604</code> ====<br />
<br />
Starts playing the sound of swinging your sword. This looks up samples based on<br />
the duration left at <code>$90e8</code> and plays them via Play Noise Samples.<br />
<br />
==== Play EC SFX <code>$990B</code> ====<br />
<br />
Plays the sound effect requested in <code>$EC</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Music <code>$9B18</code> ====<br />
<br />
Plays the music for the game.<br />
<br />
Runs Load Song if a new song is requested in <code>$EB</code>. Otherwise, runs Play Notes<br />
if the current song is set in <code>$07FB</code>. If neither of these is true, do nothing.<br />
<br />
==== Next Song <code>$9B24</code> ====<br />
<br />
Checks if the previous song should loop. If not, calls Mute All and returns.<br />
<br />
If the previous song was <code>$01</code> (the "intro" to the main theme), sets the next<br />
song to <code>$02</code> (the main theme loop).<br />
<br />
If the previous song was <code>$10</code> (the item get / level up fanfare), sets the<br />
current song from <code>$07DB</code>. Otherwise, leaves the current song the same as the<br />
previous song.<br />
<br />
Proceeds to Load Song.<br />
<br />
==== Mute All <code>$9B3B</code> ====<br />
<br />
Clears the current song at <code>$07FB</code> and sets the APU registers to mute the volume<br />
on both pulse channels, the triangle channel, and the noise channel.<br />
<br />
==== Load Song <code>$9B61</code> ====<br />
<br />
Takes a song id in register a and preps some variables for that song.<br />
<br />
If the song is <code>$10</code> (item get / level up fanfare) then it first saves the<br />
previous song to <code>$07FB</code> if it is less than <code>$10</code> so that the previous music<br />
will resume after the fanfare.<br />
<br />
Sets the phrase counter at <code>$E3</code> to 0 and the song offset at <code>$E2</code> based on the<br />
song id. Song ids are a bit field, and the song offset is the position of the<br />
lowest bit in the song id for indexing into the song table.<br />
<br />
Proceeds to Load Song Data.<br />
<br />
==== Load Song Data <code>$9B80</code> ====<br />
<br />
Loads the music variables based on the current world and current song offset.<br />
<br />
There are four blocks of code that are basically the same, for each of the four<br />
different music tables. Each one just uses a different position for the tables<br />
to load.<br />
<br />
Based on the current world in <code>$0707</code> it loads data from these offsets:<br />
<br />
<code>$00</code><br />
: Overworld music - <code>$9B87</code><br />
<code>$01</code> or <code>$02</code><br />
: Town music - <code>$9BC6</code><br />
<code>$03</code> or <code>$04</code><br />
: Palace music - <code>$9C05</code><br />
<code>$05</code> or higher<br />
: Great Palace music - <code>$9C42</code><br />
<br />
First, uses the song offset in <code>$E2</code> to index into the song table at the base<br />
offset given above.<br />
<br />
The phrase counter at <code>$E3</code> is added to that and used as in index again to<br />
retrieve the current phrase offset. If the current phrase offset is <code>$00</code> that<br />
means the song is over and the process goes back to the Next Song routine.<br />
<br />
Otherwise, the following structure is read at the base offset above + phrase<br />
offset just calculated.<br />
<br />
* <code>$E5</code> Tempo<br />
* <code>$E0</code> Note Data Low<br />
* <code>$E1</code> Note Data High<br />
* <code>$07E9</code> Bass Note Pointer<br />
* <code>$07EA</code> Harmony Note Pointer<br />
* <code>$07E8</code> Drum Note Pointer<br />
<br />
After this, the drum loop start point at <code>$E4</code> is also set to the same value as<br />
the drum note pointer. The melody note pointer at <code>$07EB</code> is set to <code>$00</code>, and<br />
all the durations (melody at <code>$07E7</code>, harmony at <code>$07E6</code>, bass at <code>$07E5</code>, and<br />
drums at <code>$07E4</code>) are set to <code>$01</code>.<br />
<br />
Proceeds to Play Notes.<br />
<br />
==== Play Notes ====<br />
<br />
This routine is broken into four major and similar sections: one each for<br />
melody, harmony, bass, and drums. The general process is as follows:<br />
<br />
decrement duration<br />
if duration == 0 {<br />
load next note<br />
increment note pointer<br />
set duration for note<br />
if no overriding sound effect {<br />
play note on appropriate channel<br />
}<br />
}<br />
<br />
Some channels have unique processing at different points in this. For example,<br />
the melody note data is null terminated, so if the loaded note in <code>$00</code> then the<br />
routine will jump to Load Song Data instead to go to the next phrase. If the<br />
drums channel gets a <code>$00</code> note it will reset the drums note pointer to the<br />
drums loop start and repeat the phrase. The bass and harmony channels don't<br />
have this looping behavior. This means that if the bass or harmony channels<br />
aren't long enough, the engine will happily just play whatever data comes next<br />
in the ROM.<br />
<br />
The melody is played on pulse 2 channel, the harmony on pulse 1 (which gets<br />
subverted by sound effects that need just one pulse channel), the bass on the<br />
triangle channel, and the drums on the noise channel.<br />
<br />
For the pulse channels, after the note is played, the envelope counter for that<br />
channel (<code>$07E2</code> for pulse 1, <code>$07E3</code> for pulse 2) is set. Normally the<br />
envelope is set to <code>$2F</code> but song <code>$40</code> (crystal fanfare and final boss music)<br />
sets it to <code>$18</code> instead. The envelope is not set if no note was played because<br />
the pitch index was <code>$02</code> which indicates a rest.<br />
<br />
Also for the pulse channels, after the above pseudocode, the vibrato and<br />
enveloping happens as long as there is no overriding sound effect. The envelope<br />
works by checking the envelope counter set previously and decrementing it. The<br />
counter value is halved and used to look up the envelope value in the LUT at<br />
<code>$9135</code>. These values are written directly to APU register <code>$4000</code> or <code>$4004</code><br />
depending on the channel.<br />
<br />
The bass channel has one special handling as well. The APU register <code>$4008</code> is<br />
set differently based on the current song id. For song <code>$10</code> (item get / level<br />
up fanfare) the register is set to <code>$60</code> but all other songs use <code>$1f</code>.<br />
<br />
The noise channel is not affect at all by the pitch. Any pitch value that is<br />
non zero will play a burst of noise.</div>Bentglasstubehttp://wiki.bindingforce.net/index.php?title=Music_Engine_Description&diff=330Music Engine Description2021-09-26T04:22:44Z<p>Bentglasstube: /* Play Notes */</p>
<hr />
<div>There are two separate music engines in Zelda 2. Both are in bank 6 (along with<br />
the song data). The music engine for the title screen resides at $8000 and the<br />
engine for the rest of the game is at $9000. Each of these engines is called<br />
once per frame during the appropriate part of the game.<br />
<br />
== Title Music Engine ==<br />
<br />
'''TODO''' document further.<br />
<br />
== Main Music Engine ==<br />
<br />
The main loop for starts at bank 6 $9000<br />
<br />
=== Data Tables ===<br />
<br />
There are several data tables used by the music engine.<br />
<br />
==== Pulse Envelope ====<br />
<br />
This table is used to set the volume of the pulse channels over time. The index<br />
used starts at a certain value and decrements, so the table is in reverse order.<br />
The index is halved before use, so each value lasts two frames.<br />
<br />
{| class="wikitable"<br />
|+ Pulse Envelope <code>$9135</code><br />
|90||91||91||91||92||92||92||92<br />
|-<br />
|93||93||94||94||94||95||95||95<br />
|-<br />
|96||96||96||97||97||97||98||98<br />
|}<br />
<br />
==== Duration LUT ====<br />
<br />
This table is used to determine the duration of a note. The note data is stored<br />
with 5 bits of pitch information and 3 bits of duration, as such:<br />
<br />
{| class="wikitable"<br />
|D1||D0||P4||P3||P2||P1||P0||D2<br />
|}<br />
<br />
The Get Note Duration routine shifts things around to get the D bits into the<br />
three least significant bits and masks it before use. This value is then added<br />
to the tempo value in <code>$E5</code> which is always a multiple of 8 to index<br />
into the following table:<br />
<br />
{| class="wikitable"<br />
|+Duration LUT <code>$914D</code><br />
|'''00'''||04||0C||08||10||18||20||05||06<br />
|-<br />
|'''08'''||04||0F||09||12||1B||24||06||06<br />
|-<br />
|'''10'''||05||0F||0A||14||1E||28||07||06<br />
|-<br />
|'''18'''||06||12||0C||18||24||30||08||10<br />
|-<br />
|'''20'''||07||15||0E||1C||2A||38||13||12<br />
|-<br />
|'''28'''||07||15||0E||1C||2A||38<br />
|}<br />
<br />
The last two values in each row seem a bit strange, as they are not nice<br />
multiples of the first entry which is usually thought of as the length of an<br />
eighth note. The last row has garbage values in those positions as that is the<br />
start of another data table, so they are not even listed here.<br />
<br />
'''TODO''' Check what values are used in vanilla.<br />
<br />
==== Pitch LUT ====<br />
<br />
This table is used to detemine the pitch of a note. The note data is stored as<br />
described above, and the fact that the least significant bit is masked out is<br />
advantageous since the pulse channels can use 11 bits of timer data, so each<br />
entry in this table is actually two bytes wide.<br />
<br />
Rather than show the raw bytes here, it's more useful to show the rough note<br />
that those values represent. If the raw values are interesting to you, check<br />
the ROM for them. It's worth noting that some of the higher notes are several<br />
cents off from the listed note.<br />
<br />
{| class="wikitable"<br />
|+Pitch LUT <code>$918F</code><br />
| || 00|| 02|| 04|| 06|| 08|| 0a|| 0c|| 0e<br />
|-<br />
|00|| C3||---|| E3|| G3||G#3|| A3||A#3|| B3<br />
|-<br />
|10|| C4||C#4|| D4||D#4|| E4|| F4||F#4|| G4<br />
|-<br />
|20||G#4|| A4||A#4|| B4|| C5||C#5|| D5||D#5<br />
|-<br />
|30|| E5|| F5||F#5|| G5|| A5||A#5|| B5||C#3<br />
|-<br />
|40|| D3||D#3|| F3||F#3||G#5|| C6||C#6|| D6<br />
|-<br />
|50||D#6|| E6|| F6||F#6|| G6||G#6|| A6||A#6<br />
|-<br />
|60|| B6|| C7||C#7|| D7||D#7|| E7|| F7||F#7<br />
|-<br />
|70|| G7||G#7|| A7||A#7|| B7|| C8<br />
|}<br />
<br />
Note that although the table goes through <code>$7A</code> values above<br />
<code>$3E</code> aren't usable due to the 5 bit limit for pitch data.<br />
<br />
Value <code>$02</code> represents a rest.<br />
<br />
=== Routines ===<br />
<br />
This is a non-exhaustive list of the routines in bank 6 involving the playing of<br />
music and sound effects. Each routine also lists its address so you can search<br />
in a disassembly for the actual code for that routine if these descriptions<br />
aren't clear.<br />
<br />
==== Main Music Loop <code>$9000</code> ====<br />
<br />
Checks that the music disable flag is off, then runs several SFX routines.<br />
After the SFX routines, the main music routine runs. After all this, various<br />
music related memory locations are cleared.<br />
<br />
==== Configure Pulse1 Channel <code>$9031</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4000</code> and <code>$4001</code><br />
respectively.<br />
<br />
==== Configure Pulse2 Channel <code>$9038</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4004</code> and <code>$4005</code><br />
respectively.<br />
<br />
==== Play Note Pulse1 <code>$9042</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 1 channel.<br />
<br />
==== Play Note <code>$9044</code> ====<br />
<br />
Called by the various play note routines. Takes a pitch index in register a and<br />
uses register x as a channel selector. For the pulse channels, this routine<br />
also saves the lower 8 bits of the APU timer register to <code>$E6</code> or <code>$E7</code> which<br />
are used for a vibrato effect.<br />
<br />
==== Play Note Pulse2 <code>$9067</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 2 channel.<br />
<br />
==== Play Note Triangle <code>$906B</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the triangle channel.<br />
<br />
==== Get Note Duration <code>$906F</code> ====<br />
<br />
Takes note data in register a and looks up the duration. The original note<br />
data is saved in register x and the result of the duration lookup is put in<br />
register a. The duration lookup is offset by the tempo stored in <code>$E5</code>.<br />
<br />
==== Vibrato Pulse1 <code>$9089</code> ====<br />
<br />
Applies a vibrato effect on the pulse 1 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato Pulse2 <code>$9097</code> ====<br />
<br />
Applies a vibrato effect on the pulse 2 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato <code>$909E</code> ====<br />
<br />
Takes the duration of the note remaining in register a, the low bits of the APU<br />
timer in register y, and the channel to use in register x. This is called by<br />
the other vibrato routines after setting x appropriately.<br />
<br />
Uses the <code>$04</code> bit of the duration to either add or subtract 2 from the low<br />
timer bits. Only the low bits are used because writing to the high bits resets<br />
the phase of the channel which can cause clicks. None of the notes from the<br />
pitch LUT are close enough to the boundary for the change to require the high<br />
bits to change anyway, so this works out fine.<br />
<br />
==== Play E9 SFX <code>$920B</code> ====<br />
<br />
Plays the sound effect requested in <code>$E9</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EF SFX <code>$92F4</code> ====<br />
<br />
Plays the sound effect requested in <code>$EF</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EE SFX <code>$9408</code> ====<br />
<br />
Plays the sound effect requested in <code>$EE</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Noise <code>$959D</code> ====<br />
<br />
Configures the APU noise registers to make a noise burst. Takes configuration<br />
for registers <code>$400F</code>, <code>$400E</code>, and <code>$400C</code> in registers y, x, and a.<br />
<br />
==== Crumble Bridge SFX <code>$956C</code> ====<br />
<br />
Starts playing the sound effect for a crumble bridge crumbling. This uses both<br />
the noise and the triangle channels so it sets flags to disable the music on<br />
those channels. Continues with SFX Noise Decay.<br />
<br />
==== SFX Noise Decay <code>$9587</code> ====<br />
<br />
Counts down the timer in <code>$07F5</code> and turns off the noise when it reaches 0.<br />
Also clears the flag for the ED sound effect in <code>$07FD</code>.<br />
<br />
==== Play ED SFX <code>$95A7</code> ====<br />
<br />
Plays the sound effect request in <code>$ED</code> or continues the sound effect saved in<br />
<code>$07FD</code>. Existing sound effects which are higher than the current sound effect<br />
will be ignored. If the same sound effect is requested that is already playing,<br />
it will restart the sound effect except for <code>$80</code> which gives priority to<br />
continuing. When the sound is continued instead of newly played, the decay<br />
routine will be called instead.<br />
<br />
; <code>$02</code><br />
: Crumble Bridge<br />
; <code>$04</code> and <code>$10</code><br />
: Crumble Block / Enemy Hurt<br />
; <code>$20</code> and <code>$80</code><br />
: Sword Strike<br />
; <code>$40</code><br />
: Very short noise burst, probably unused. Doesn't store the effect, and doesn't have an associated decay.<br />
<br />
==== Crumble Block / Enemy Hurt SFX <code>$95E6</code> ====<br />
<br />
Starts playing the sound of a block breaking or an enemy getting hurt.<br />
<br />
==== Crumble Block / Enemy Hurt SFX Decay <code>$95EE</code> ====<br />
<br />
Looks up noise register values based on the timer and the sound effect value.<br />
Crumble Block samples are at <code>$912C</code> while Enemy Hurt is at <code>$9123</code>. Continues<br />
on to Play Noise Samples.<br />
<br />
==== Play Noise Samples <code>$9612</code> ====<br />
<br />
Takes a sample value in register a. The low four bits of this are used to set<br />
the noise period via APU register <code>$400E</code>. The high four bits are used to set<br />
the noise volume via APU register <code>$400C</code>.<br />
<br />
Continues on the SFX Noise Decay process.<br />
<br />
==== Sword Strike SFX <code>$9604</code> ====<br />
<br />
Starts playing the sound of swinging your sword. This looks up samples based on<br />
the duration left at <code>$90e8</code> and plays them via Play Noise Samples.<br />
<br />
==== Play EC SFX <code>$990B</code> ====<br />
<br />
Plays the sound effect requested in <code>$EC</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Music <code>$9B18</code> ====<br />
<br />
Plays the music for the game.<br />
<br />
Runs Load Song if a new song is requested in <code>$EB</code>. Otherwise, runs Play Notes<br />
if the current song is set in <code>$07FB</code>. If neither of these is true, do nothing.<br />
<br />
==== Next Song <code>$9B24</code> ====<br />
<br />
Checks if the previous song should loop. If not, calls Mute All and returns.<br />
<br />
If the previous song was <code>$01</code> (the "intro" to the main theme), sets the next<br />
song to <code>$02</code> (the main theme loop).<br />
<br />
If the previous song was <code>$10</code> (the item get / level up fanfare), sets the<br />
current song from <code>$07DB</code>. Otherwise, leaves the current song the same as the<br />
previous song.<br />
<br />
Proceeds to Load Song.<br />
<br />
==== Mute All <code>$9B3B</code> ====<br />
<br />
Clears the current song at <code>$07FB</code> and sets the APU registers to mute the volume<br />
on both pulse channels, the triangle channel, and the noise channel.<br />
<br />
==== Load Song <code>$9B61</code> ====<br />
<br />
Takes a song id in register a and preps some variables for that song.<br />
<br />
If the song is <code>$10</code> (item get / level up fanfare) then it first saves the<br />
previous song to <code>$07FB</code> if it is less than <code>$10</code> so that the previous music<br />
will resume after the fanfare.<br />
<br />
Sets the phrase counter at <code>$E3</code> to 0 and the song offset at <code>$E2</code> based on the<br />
song id. Song ids are a bit field, and the song offset is the position of the<br />
lowest bit in the song id for indexing into the song table.<br />
<br />
Proceeds to Load Song Data.<br />
<br />
==== Load Song Data <code>$9B80</code> ====<br />
<br />
Loads the music variables based on the current world and current song offset.<br />
<br />
There are four blocks of code that are basically the same, for each of the four<br />
different music tables. Each one just uses a different position for the tables<br />
to load.<br />
<br />
Based on the current world in <code>$0707</code> it loads data from these offsets:<br />
<br />
<code>$00</code><br />
: Overworld music - <code>$9B87</code><br />
<code>$01</code> or <code>$02</code><br />
: Town music - <code>$9BC6</code><br />
<code>$03</code> or <code>$04</code><br />
: Palace music - <code>$9C05</code><br />
<code>$05</code> or higher<br />
: Great Palace music - <code>$9C42</code><br />
<br />
First, uses the song offset in <code>$E2</code> to index into the song table at the base<br />
offset given above.<br />
<br />
The phrase counter at <code>$E3</code> is added to that and used as in index again to<br />
retrieve the current phrase offset. If the current phrase offset is <code>$00</code> that<br />
means the song is over and the process goes back to the Next Song routine.<br />
<br />
Otherwise, the following structure is read at the base offset above + phrase<br />
offset just calculated.<br />
<br />
* <code>$E5</code> Tempo<br />
* <code>$E0</code> Note Data Low<br />
* <code>$E1</code> Note Data High<br />
* <code>$07E9</code> Bass Note Pointer<br />
* <code>$07EA</code> Harmony Note Pointer<br />
* <code>$07E8</code> Drum Note Pointer<br />
<br />
After this, the drum loop start point at <code>$E4</code> is also set to the same value as<br />
the drum note pointer. The melody note pointer at <code>$07EB</code> is set to <code>$00</code>, and<br />
all the durations (melody at <code>$07E7</code>, harmony at <code>$07E6</code>, bass at <code>$07E5</code>, and<br />
drums at <code>$07E4</code>) are set to <code>$01</code>.<br />
<br />
Proceeds to Play Notes.<br />
<br />
==== Play Notes ====<br />
<br />
This routine is broken into four major and similar sections: one each for<br />
melody, harmony, bass, and drums. The general process is as follows:<br />
<br />
decrement duration<br />
if duration == 0 {<br />
load next note<br />
increment note pointer<br />
set duration for note<br />
if no overriding sound effect {<br />
play note on appropriate channel<br />
}<br />
}<br />
<br />
Some channels have unique processing at different points in this. For example,<br />
the melody note data is null terminated, so if the loaded note in <code>$00</code> then the<br />
routine will jump to Load Song Data instead to go to the next phrase. If the<br />
drums channel gets a <code>$00</code> note it will reset the drums note pointer to the<br />
drums loop start and repeat the phrase. The bass and harmony channels don't<br />
have this looping behavior. This means that if the bass or harmony channels<br />
aren't long enough, the engine will happily just play whatever data comes next<br />
in the ROM.<br />
<br />
The melody is played on pulse 2 channel, the harmony on pulse 1 (which gets<br />
subverted by sound effects that need just one pulse channel), the bass on the<br />
triangle channel, and the drums on the noise channel.<br />
<br />
For the pulse channels, after the note is played, the envelope counter for that<br />
channel (<code>$07E2</code> for pulse 1, <code>$07E3</code> for pulse 2) is set. Normally the<br />
envelope is set to <code>$2F</code> but song <code>$40</code> (crystal fanfare and final boss music)<br />
sets it to <code>$18</code> instead. The envelope is not set if no note was played because<br />
the pitch index was <code>$02</code> which indicates a rest.<br />
<br />
Also for the pulse channels, after the above pseudocode, the vibrato and<br />
enveloping happens as long as there is no overriding sound effect. The envelope<br />
works by checking the envelope counter set previously and decrementing it. The<br />
counter value is halved and used to look up the envelope value in the LUT at<br />
<code>$9135</code>. These values are written directly to APU register <code>$4000</code> or <code>$4004</code><br />
depending on the channel.<br />
<br />
The bass channel has one special handling as well. The APU register <code>$4008</code> is<br />
set differently based on the current song id. For song <code>$10</code> (item get / level<br />
up fanfare) the register is set to <code>$60</code> but all other songs use <code>$1f</code>.<br />
<br />
The noise channel is not affect at all by the pitch. Any pitch value that is<br />
non zero will play a burst of noise.</div>Bentglasstubehttp://wiki.bindingforce.net/index.php?title=Music_Engine_Description&diff=329Music Engine Description2021-09-26T04:08:53Z<p>Bentglasstube: /* Pitch LUT */ capitalize note names</p>
<hr />
<div>There are two separate music engines in Zelda 2. Both are in bank 6 (along with<br />
the song data). The music engine for the title screen resides at $8000 and the<br />
engine for the rest of the game is at $9000. Each of these engines is called<br />
once per frame during the appropriate part of the game.<br />
<br />
== Title Music Engine ==<br />
<br />
'''TODO''' document further.<br />
<br />
== Main Music Engine ==<br />
<br />
The main loop for starts at bank 6 $9000<br />
<br />
=== Data Tables ===<br />
<br />
There are several data tables used by the music engine.<br />
<br />
==== Pulse Envelope ====<br />
<br />
This table is used to set the volume of the pulse channels over time. The index<br />
used starts at a certain value and decrements, so the table is in reverse order.<br />
The index is halved before use, so each value lasts two frames.<br />
<br />
{| class="wikitable"<br />
|+ Pulse Envelope <code>$9135</code><br />
|90||91||91||91||92||92||92||92<br />
|-<br />
|93||93||94||94||94||95||95||95<br />
|-<br />
|96||96||96||97||97||97||98||98<br />
|}<br />
<br />
==== Duration LUT ====<br />
<br />
This table is used to determine the duration of a note. The note data is stored<br />
with 5 bits of pitch information and 3 bits of duration, as such:<br />
<br />
{| class="wikitable"<br />
|D1||D0||P4||P3||P2||P1||P0||D2<br />
|}<br />
<br />
The Get Note Duration routine shifts things around to get the D bits into the<br />
three least significant bits and masks it before use. This value is then added<br />
to the tempo value in <code>$E5</code> which is always a multiple of 8 to index<br />
into the following table:<br />
<br />
{| class="wikitable"<br />
|+Duration LUT <code>$914D</code><br />
|'''00'''||04||0C||08||10||18||20||05||06<br />
|-<br />
|'''08'''||04||0F||09||12||1B||24||06||06<br />
|-<br />
|'''10'''||05||0F||0A||14||1E||28||07||06<br />
|-<br />
|'''18'''||06||12||0C||18||24||30||08||10<br />
|-<br />
|'''20'''||07||15||0E||1C||2A||38||13||12<br />
|-<br />
|'''28'''||07||15||0E||1C||2A||38<br />
|}<br />
<br />
The last two values in each row seem a bit strange, as they are not nice<br />
multiples of the first entry which is usually thought of as the length of an<br />
eighth note. The last row has garbage values in those positions as that is the<br />
start of another data table, so they are not even listed here.<br />
<br />
'''TODO''' Check what values are used in vanilla.<br />
<br />
==== Pitch LUT ====<br />
<br />
This table is used to detemine the pitch of a note. The note data is stored as<br />
described above, and the fact that the least significant bit is masked out is<br />
advantageous since the pulse channels can use 11 bits of timer data, so each<br />
entry in this table is actually two bytes wide.<br />
<br />
Rather than show the raw bytes here, it's more useful to show the rough note<br />
that those values represent. If the raw values are interesting to you, check<br />
the ROM for them. It's worth noting that some of the higher notes are several<br />
cents off from the listed note.<br />
<br />
{| class="wikitable"<br />
|+Pitch LUT <code>$918F</code><br />
| || 00|| 02|| 04|| 06|| 08|| 0a|| 0c|| 0e<br />
|-<br />
|00|| C3||---|| E3|| G3||G#3|| A3||A#3|| B3<br />
|-<br />
|10|| C4||C#4|| D4||D#4|| E4|| F4||F#4|| G4<br />
|-<br />
|20||G#4|| A4||A#4|| B4|| C5||C#5|| D5||D#5<br />
|-<br />
|30|| E5|| F5||F#5|| G5|| A5||A#5|| B5||C#3<br />
|-<br />
|40|| D3||D#3|| F3||F#3||G#5|| C6||C#6|| D6<br />
|-<br />
|50||D#6|| E6|| F6||F#6|| G6||G#6|| A6||A#6<br />
|-<br />
|60|| B6|| C7||C#7|| D7||D#7|| E7|| F7||F#7<br />
|-<br />
|70|| G7||G#7|| A7||A#7|| B7|| C8<br />
|}<br />
<br />
Note that although the table goes through <code>$7A</code> values above<br />
<code>$3E</code> aren't usable due to the 5 bit limit for pitch data.<br />
<br />
Value <code>$02</code> represents a rest.<br />
<br />
=== Routines ===<br />
<br />
This is a non-exhaustive list of the routines in bank 6 involving the playing of<br />
music and sound effects. Each routine also lists its address so you can search<br />
in a disassembly for the actual code for that routine if these descriptions<br />
aren't clear.<br />
<br />
==== Main Music Loop <code>$9000</code> ====<br />
<br />
Checks that the music disable flag is off, then runs several SFX routines.<br />
After the SFX routines, the main music routine runs. After all this, various<br />
music related memory locations are cleared.<br />
<br />
==== Configure Pulse1 Channel <code>$9031</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4000</code> and <code>$4001</code><br />
respectively.<br />
<br />
==== Configure Pulse2 Channel <code>$9038</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4004</code> and <code>$4005</code><br />
respectively.<br />
<br />
==== Play Note Pulse1 <code>$9042</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 1 channel.<br />
<br />
==== Play Note <code>$9044</code> ====<br />
<br />
Called by the various play note routines. Takes a pitch index in register a and<br />
uses register x as a channel selector. For the pulse channels, this routine<br />
also saves the lower 8 bits of the APU timer register to <code>$E6</code> or <code>$E7</code> which<br />
are used for a vibrato effect.<br />
<br />
==== Play Note Pulse2 <code>$9067</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 2 channel.<br />
<br />
==== Play Note Triangle <code>$906B</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the triangle channel.<br />
<br />
==== Get Note Duration <code>$906F</code> ====<br />
<br />
Takes note data in register a and looks up the duration. The original note<br />
data is saved in register x and the result of the duration lookup is put in<br />
register a. The duration lookup is offset by the tempo stored in <code>$E5</code>.<br />
<br />
==== Vibrato Pulse1 <code>$9089</code> ====<br />
<br />
Applies a vibrato effect on the pulse 1 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato Pulse2 <code>$9097</code> ====<br />
<br />
Applies a vibrato effect on the pulse 2 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato <code>$909E</code> ====<br />
<br />
Takes the duration of the note remaining in register a, the low bits of the APU<br />
timer in register y, and the channel to use in register x. This is called by<br />
the other vibrato routines after setting x appropriately.<br />
<br />
Uses the <code>$04</code> bit of the duration to either add or subtract 2 from the low<br />
timer bits. Only the low bits are used because writing to the high bits resets<br />
the phase of the channel which can cause clicks. None of the notes from the<br />
pitch LUT are close enough to the boundary for the change to require the high<br />
bits to change anyway, so this works out fine.<br />
<br />
==== Play E9 SFX <code>$920B</code> ====<br />
<br />
Plays the sound effect requested in <code>$E9</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EF SFX <code>$92F4</code> ====<br />
<br />
Plays the sound effect requested in <code>$EF</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EE SFX <code>$9408</code> ====<br />
<br />
Plays the sound effect requested in <code>$EE</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Noise <code>$959D</code> ====<br />
<br />
Configures the APU noise registers to make a noise burst. Takes configuration<br />
for registers <code>$400F</code>, <code>$400E</code>, and <code>$400C</code> in registers y, x, and a.<br />
<br />
==== Crumble Bridge SFX <code>$956C</code> ====<br />
<br />
Starts playing the sound effect for a crumble bridge crumbling. This uses both<br />
the noise and the triangle channels so it sets flags to disable the music on<br />
those channels. Continues with SFX Noise Decay.<br />
<br />
==== SFX Noise Decay <code>$9587</code> ====<br />
<br />
Counts down the timer in <code>$07F5</code> and turns off the noise when it reaches 0.<br />
Also clears the flag for the ED sound effect in <code>$07FD</code>.<br />
<br />
==== Play ED SFX <code>$95A7</code> ====<br />
<br />
Plays the sound effect request in <code>$ED</code> or continues the sound effect saved in<br />
<code>$07FD</code>. Existing sound effects which are higher than the current sound effect<br />
will be ignored. If the same sound effect is requested that is already playing,<br />
it will restart the sound effect except for <code>$80</code> which gives priority to<br />
continuing. When the sound is continued instead of newly played, the decay<br />
routine will be called instead.<br />
<br />
; <code>$02</code><br />
: Crumble Bridge<br />
; <code>$04</code> and <code>$10</code><br />
: Crumble Block / Enemy Hurt<br />
; <code>$20</code> and <code>$80</code><br />
: Sword Strike<br />
; <code>$40</code><br />
: Very short noise burst, probably unused. Doesn't store the effect, and doesn't have an associated decay.<br />
<br />
==== Crumble Block / Enemy Hurt SFX <code>$95E6</code> ====<br />
<br />
Starts playing the sound of a block breaking or an enemy getting hurt.<br />
<br />
==== Crumble Block / Enemy Hurt SFX Decay <code>$95EE</code> ====<br />
<br />
Looks up noise register values based on the timer and the sound effect value.<br />
Crumble Block samples are at <code>$912C</code> while Enemy Hurt is at <code>$9123</code>. Continues<br />
on to Play Noise Samples.<br />
<br />
==== Play Noise Samples <code>$9612</code> ====<br />
<br />
Takes a sample value in register a. The low four bits of this are used to set<br />
the noise period via APU register <code>$400E</code>. The high four bits are used to set<br />
the noise volume via APU register <code>$400C</code>.<br />
<br />
Continues on the SFX Noise Decay process.<br />
<br />
==== Sword Strike SFX <code>$9604</code> ====<br />
<br />
Starts playing the sound of swinging your sword. This looks up samples based on<br />
the duration left at <code>$90e8</code> and plays them via Play Noise Samples.<br />
<br />
==== Play EC SFX <code>$990B</code> ====<br />
<br />
Plays the sound effect requested in <code>$EC</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Music <code>$9B18</code> ====<br />
<br />
Plays the music for the game.<br />
<br />
Runs Load Song if a new song is requested in <code>$EB</code>. Otherwise, runs Play Notes<br />
if the current song is set in <code>$07FB</code>. If neither of these is true, do nothing.<br />
<br />
==== Next Song <code>$9B24</code> ====<br />
<br />
Checks if the previous song should loop. If not, calls Mute All and returns.<br />
<br />
If the previous song was <code>$01</code> (the "intro" to the main theme), sets the next<br />
song to <code>$02</code> (the main theme loop).<br />
<br />
If the previous song was <code>$10</code> (the item get / level up fanfare), sets the<br />
current song from <code>$07DB</code>. Otherwise, leaves the current song the same as the<br />
previous song.<br />
<br />
Proceeds to Load Song.<br />
<br />
==== Mute All <code>$9B3B</code> ====<br />
<br />
Clears the current song at <code>$07FB</code> and sets the APU registers to mute the volume<br />
on both pulse channels, the triangle channel, and the noise channel.<br />
<br />
==== Load Song <code>$9B61</code> ====<br />
<br />
Takes a song id in register a and preps some variables for that song.<br />
<br />
If the song is <code>$10</code> (item get / level up fanfare) then it first saves the<br />
previous song to <code>$07FB</code> if it is less than <code>$10</code> so that the previous music<br />
will resume after the fanfare.<br />
<br />
Sets the phrase counter at <code>$E3</code> to 0 and the song offset at <code>$E2</code> based on the<br />
song id. Song ids are a bit field, and the song offset is the position of the<br />
lowest bit in the song id for indexing into the song table.<br />
<br />
Proceeds to Load Song Data.<br />
<br />
==== Load Song Data <code>$9B80</code> ====<br />
<br />
Loads the music variables based on the current world and current song offset.<br />
<br />
There are four blocks of code that are basically the same, for each of the four<br />
different music tables. Each one just uses a different position for the tables<br />
to load.<br />
<br />
Based on the current world in <code>$0707</code> it loads data from these offsets:<br />
<br />
<code>$00</code><br />
: Overworld music - <code>$9B87</code><br />
<code>$01</code> or <code>$02</code><br />
: Town music - <code>$9BC6</code><br />
<code>$03</code> or <code>$04</code><br />
: Palace music - <code>$9C05</code><br />
<code>$05</code> or higher<br />
: Great Palace music - <code>$9C42</code><br />
<br />
First, uses the song offset in <code>$E2</code> to index into the song table at the base<br />
offset given above.<br />
<br />
The phrase counter at <code>$E3</code> is added to that and used as in index again to<br />
retrieve the current phrase offset. If the current phrase offset is <code>$00</code> that<br />
means the song is over and the process goes back to the Next Song routine.<br />
<br />
Otherwise, the following structure is read at the base offset above + phrase<br />
offset just calculated.<br />
<br />
* <code>$E5</code> Tempo<br />
* <code>$E0</code> Note Data Low<br />
* <code>$E1</code> Note Data High<br />
* <code>$07E9</code> Bass Note Pointer<br />
* <code>$07EA</code> Harmony Note Pointer<br />
* <code>$07E8</code> Drum Note Pointer<br />
<br />
After this, the drum loop start point at <code>$E4</code> is also set to the same value as<br />
the drum note pointer. The melody note pointer at <code>$07EB</code> is set to <code>$00</code>, and<br />
all the durations (melody at <code>$07E7</code>, harmony at <code>$07E6</code>, bass at <code>$07E5</code>, and<br />
drums at <code>$07E4</code>) are set to <code>$01</code>.<br />
<br />
Proceeds to Play Notes.<br />
<br />
==== Play Notes ====<br />
<br />
This routine is broken into four major and similar sections: one each for<br />
melody, harmony, bass, and drums. The general process is as follows:<br />
<br />
decrement duration<br />
if duration == 0 {<br />
load next note<br />
increment note pointer<br />
<br />
set duration for note<br />
if no overriding sound effect {<br />
play note on appropriate channel<br />
}<br />
}<br />
<br />
Some channels have unique processing at different points in this. For example,<br />
the melody note data is null terminated, so if the loaded note in <code>$00</code> then the<br />
routine will jump to Load Song Data instead to go to the next phrase. If the<br />
drums channel gets a <code>$00</code> note it will reset the drums note pointer to the<br />
drums loop start and repeat the phrase. The bass and harmony channels don't<br />
have this looping behavior. This means that if the bass or harmony channels<br />
aren't long enough, the engine will happily just play whatever data comes next<br />
in the ROM.<br />
<br />
The melody is played on pulse 2 channel, the harmony on pulse 1 (which gets<br />
subverted by sound effects that need just one pulse channel), the bass on the<br />
triangle channel, and the drums on the noise channel.<br />
<br />
For the pulse channels, after the note is played, the envelope counter for that<br />
channel (<code>$07E2</code> for pulse 1, <code>$07E3</code> for pulse 2) is set. Normally the<br />
envelope is set to <code>$2F</code> but song <code>$40</code> (crystal fanfare and final boss music)<br />
sets it to <code>$18</code> instead. The envelope is not set if no note was played because<br />
the pitch index was <code>$02</code> which indicates a rest.<br />
<br />
Also for the pulse channels, after the above pseudocode, the vibrato and<br />
enveloping happens as long as there is no overriding sound effect. The envelope<br />
works by checking the envelope counter set previously and decrementing it. The<br />
counter value is halved and used to look up the envelope value in the LUT at<br />
<code>$9135</code>. These values are written directly to APU register <code>$4000</code> or <code>$4004</code><br />
depending on the channel.<br />
<br />
The bass channel has one special handling as well. The APU register <code>$4008</code> is<br />
set differently based on the current song id. For song <code>$10</code> (item get / level<br />
up fanfare) the register is set to <code>$60</code> but all other songs use <code>$1f</code>.<br />
<br />
The noise channel is not affect at all by the pitch. Any pitch value that is<br />
non zero will play a burst of noise.</div>Bentglasstubehttp://wiki.bindingforce.net/index.php?title=Music_Engine_Description&diff=328Music Engine Description2021-09-26T04:08:01Z<p>Bentglasstube: Add information about the pitch LUT.</p>
<hr />
<div>There are two separate music engines in Zelda 2. Both are in bank 6 (along with<br />
the song data). The music engine for the title screen resides at $8000 and the<br />
engine for the rest of the game is at $9000. Each of these engines is called<br />
once per frame during the appropriate part of the game.<br />
<br />
== Title Music Engine ==<br />
<br />
'''TODO''' document further.<br />
<br />
== Main Music Engine ==<br />
<br />
The main loop for starts at bank 6 $9000<br />
<br />
=== Data Tables ===<br />
<br />
There are several data tables used by the music engine.<br />
<br />
==== Pulse Envelope ====<br />
<br />
This table is used to set the volume of the pulse channels over time. The index<br />
used starts at a certain value and decrements, so the table is in reverse order.<br />
The index is halved before use, so each value lasts two frames.<br />
<br />
{| class="wikitable"<br />
|+ Pulse Envelope <code>$9135</code><br />
|90||91||91||91||92||92||92||92<br />
|-<br />
|93||93||94||94||94||95||95||95<br />
|-<br />
|96||96||96||97||97||97||98||98<br />
|}<br />
<br />
==== Duration LUT ====<br />
<br />
This table is used to determine the duration of a note. The note data is stored<br />
with 5 bits of pitch information and 3 bits of duration, as such:<br />
<br />
{| class="wikitable"<br />
|D1||D0||P4||P3||P2||P1||P0||D2<br />
|}<br />
<br />
The Get Note Duration routine shifts things around to get the D bits into the<br />
three least significant bits and masks it before use. This value is then added<br />
to the tempo value in <code>$E5</code> which is always a multiple of 8 to index<br />
into the following table:<br />
<br />
{| class="wikitable"<br />
|+Duration LUT <code>$914D</code><br />
|'''00'''||04||0C||08||10||18||20||05||06<br />
|-<br />
|'''08'''||04||0F||09||12||1B||24||06||06<br />
|-<br />
|'''10'''||05||0F||0A||14||1E||28||07||06<br />
|-<br />
|'''18'''||06||12||0C||18||24||30||08||10<br />
|-<br />
|'''20'''||07||15||0E||1C||2A||38||13||12<br />
|-<br />
|'''28'''||07||15||0E||1C||2A||38<br />
|}<br />
<br />
The last two values in each row seem a bit strange, as they are not nice<br />
multiples of the first entry which is usually thought of as the length of an<br />
eighth note. The last row has garbage values in those positions as that is the<br />
start of another data table, so they are not even listed here.<br />
<br />
'''TODO''' Check what values are used in vanilla.<br />
<br />
==== Pitch LUT ====<br />
<br />
This table is used to detemine the pitch of a note. The note data is stored as<br />
described above, and the fact that the least significant bit is masked out is<br />
advantageous since the pulse channels can use 11 bits of timer data, so each<br />
entry in this table is actually two bytes wide.<br />
<br />
Rather than show the raw bytes here, it's more useful to show the rough note<br />
that those values represent. If the raw values are interesting to you, check<br />
the ROM for them. It's worth noting that some of the higher notes are several<br />
cents off from the listed note.<br />
<br />
{| class="wikitable"<br />
|+Pitch LUT <code>$918F</code><br />
| || 00|| 02|| 04|| 06|| 08|| 0a|| 0c|| 0e<br />
|-<br />
|00|| c3||---|| e3|| g3||g#3|| a3||a#3|| b3<br />
|-<br />
|10|| c4||c#4|| d4||d#4|| e4|| f4||f#4|| g4<br />
|-<br />
|20||g#4|| a4||a#4|| b4|| c5||c#5|| d5||d#5<br />
|-<br />
|30|| e5|| f5||f#5|| g5|| a5||a#5|| b5||c#3<br />
|-<br />
|40|| d3||d#3|| f3||f#3||g#5|| c6||c#6|| d6<br />
|-<br />
|50||d#6|| e6|| f6||f#6|| g6||g#6|| a6||a#6<br />
|-<br />
|60|| b6|| c7||c#7|| d7||d#7|| e7|| f7||f#7<br />
|-<br />
|70|| g7||g#7|| a7||a#7|| b7|| c8<br />
|}<br />
<br />
Note that although the table goes through <code>$7A</code> values above<br />
<code>$3E</code> aren't usable due to the 5 bit limit for pitch data.<br />
<br />
Value <code>$02</code> represents a rest.<br />
<br />
=== Routines ===<br />
<br />
This is a non-exhaustive list of the routines in bank 6 involving the playing of<br />
music and sound effects. Each routine also lists its address so you can search<br />
in a disassembly for the actual code for that routine if these descriptions<br />
aren't clear.<br />
<br />
==== Main Music Loop <code>$9000</code> ====<br />
<br />
Checks that the music disable flag is off, then runs several SFX routines.<br />
After the SFX routines, the main music routine runs. After all this, various<br />
music related memory locations are cleared.<br />
<br />
==== Configure Pulse1 Channel <code>$9031</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4000</code> and <code>$4001</code><br />
respectively.<br />
<br />
==== Configure Pulse2 Channel <code>$9038</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4004</code> and <code>$4005</code><br />
respectively.<br />
<br />
==== Play Note Pulse1 <code>$9042</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 1 channel.<br />
<br />
==== Play Note <code>$9044</code> ====<br />
<br />
Called by the various play note routines. Takes a pitch index in register a and<br />
uses register x as a channel selector. For the pulse channels, this routine<br />
also saves the lower 8 bits of the APU timer register to <code>$E6</code> or <code>$E7</code> which<br />
are used for a vibrato effect.<br />
<br />
==== Play Note Pulse2 <code>$9067</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 2 channel.<br />
<br />
==== Play Note Triangle <code>$906B</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the triangle channel.<br />
<br />
==== Get Note Duration <code>$906F</code> ====<br />
<br />
Takes note data in register a and looks up the duration. The original note<br />
data is saved in register x and the result of the duration lookup is put in<br />
register a. The duration lookup is offset by the tempo stored in <code>$E5</code>.<br />
<br />
==== Vibrato Pulse1 <code>$9089</code> ====<br />
<br />
Applies a vibrato effect on the pulse 1 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato Pulse2 <code>$9097</code> ====<br />
<br />
Applies a vibrato effect on the pulse 2 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato <code>$909E</code> ====<br />
<br />
Takes the duration of the note remaining in register a, the low bits of the APU<br />
timer in register y, and the channel to use in register x. This is called by<br />
the other vibrato routines after setting x appropriately.<br />
<br />
Uses the <code>$04</code> bit of the duration to either add or subtract 2 from the low<br />
timer bits. Only the low bits are used because writing to the high bits resets<br />
the phase of the channel which can cause clicks. None of the notes from the<br />
pitch LUT are close enough to the boundary for the change to require the high<br />
bits to change anyway, so this works out fine.<br />
<br />
==== Play E9 SFX <code>$920B</code> ====<br />
<br />
Plays the sound effect requested in <code>$E9</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EF SFX <code>$92F4</code> ====<br />
<br />
Plays the sound effect requested in <code>$EF</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EE SFX <code>$9408</code> ====<br />
<br />
Plays the sound effect requested in <code>$EE</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Noise <code>$959D</code> ====<br />
<br />
Configures the APU noise registers to make a noise burst. Takes configuration<br />
for registers <code>$400F</code>, <code>$400E</code>, and <code>$400C</code> in registers y, x, and a.<br />
<br />
==== Crumble Bridge SFX <code>$956C</code> ====<br />
<br />
Starts playing the sound effect for a crumble bridge crumbling. This uses both<br />
the noise and the triangle channels so it sets flags to disable the music on<br />
those channels. Continues with SFX Noise Decay.<br />
<br />
==== SFX Noise Decay <code>$9587</code> ====<br />
<br />
Counts down the timer in <code>$07F5</code> and turns off the noise when it reaches 0.<br />
Also clears the flag for the ED sound effect in <code>$07FD</code>.<br />
<br />
==== Play ED SFX <code>$95A7</code> ====<br />
<br />
Plays the sound effect request in <code>$ED</code> or continues the sound effect saved in<br />
<code>$07FD</code>. Existing sound effects which are higher than the current sound effect<br />
will be ignored. If the same sound effect is requested that is already playing,<br />
it will restart the sound effect except for <code>$80</code> which gives priority to<br />
continuing. When the sound is continued instead of newly played, the decay<br />
routine will be called instead.<br />
<br />
; <code>$02</code><br />
: Crumble Bridge<br />
; <code>$04</code> and <code>$10</code><br />
: Crumble Block / Enemy Hurt<br />
; <code>$20</code> and <code>$80</code><br />
: Sword Strike<br />
; <code>$40</code><br />
: Very short noise burst, probably unused. Doesn't store the effect, and doesn't have an associated decay.<br />
<br />
==== Crumble Block / Enemy Hurt SFX <code>$95E6</code> ====<br />
<br />
Starts playing the sound of a block breaking or an enemy getting hurt.<br />
<br />
==== Crumble Block / Enemy Hurt SFX Decay <code>$95EE</code> ====<br />
<br />
Looks up noise register values based on the timer and the sound effect value.<br />
Crumble Block samples are at <code>$912C</code> while Enemy Hurt is at <code>$9123</code>. Continues<br />
on to Play Noise Samples.<br />
<br />
==== Play Noise Samples <code>$9612</code> ====<br />
<br />
Takes a sample value in register a. The low four bits of this are used to set<br />
the noise period via APU register <code>$400E</code>. The high four bits are used to set<br />
the noise volume via APU register <code>$400C</code>.<br />
<br />
Continues on the SFX Noise Decay process.<br />
<br />
==== Sword Strike SFX <code>$9604</code> ====<br />
<br />
Starts playing the sound of swinging your sword. This looks up samples based on<br />
the duration left at <code>$90e8</code> and plays them via Play Noise Samples.<br />
<br />
==== Play EC SFX <code>$990B</code> ====<br />
<br />
Plays the sound effect requested in <code>$EC</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Music <code>$9B18</code> ====<br />
<br />
Plays the music for the game.<br />
<br />
Runs Load Song if a new song is requested in <code>$EB</code>. Otherwise, runs Play Notes<br />
if the current song is set in <code>$07FB</code>. If neither of these is true, do nothing.<br />
<br />
==== Next Song <code>$9B24</code> ====<br />
<br />
Checks if the previous song should loop. If not, calls Mute All and returns.<br />
<br />
If the previous song was <code>$01</code> (the "intro" to the main theme), sets the next<br />
song to <code>$02</code> (the main theme loop).<br />
<br />
If the previous song was <code>$10</code> (the item get / level up fanfare), sets the<br />
current song from <code>$07DB</code>. Otherwise, leaves the current song the same as the<br />
previous song.<br />
<br />
Proceeds to Load Song.<br />
<br />
==== Mute All <code>$9B3B</code> ====<br />
<br />
Clears the current song at <code>$07FB</code> and sets the APU registers to mute the volume<br />
on both pulse channels, the triangle channel, and the noise channel.<br />
<br />
==== Load Song <code>$9B61</code> ====<br />
<br />
Takes a song id in register a and preps some variables for that song.<br />
<br />
If the song is <code>$10</code> (item get / level up fanfare) then it first saves the<br />
previous song to <code>$07FB</code> if it is less than <code>$10</code> so that the previous music<br />
will resume after the fanfare.<br />
<br />
Sets the phrase counter at <code>$E3</code> to 0 and the song offset at <code>$E2</code> based on the<br />
song id. Song ids are a bit field, and the song offset is the position of the<br />
lowest bit in the song id for indexing into the song table.<br />
<br />
Proceeds to Load Song Data.<br />
<br />
==== Load Song Data <code>$9B80</code> ====<br />
<br />
Loads the music variables based on the current world and current song offset.<br />
<br />
There are four blocks of code that are basically the same, for each of the four<br />
different music tables. Each one just uses a different position for the tables<br />
to load.<br />
<br />
Based on the current world in <code>$0707</code> it loads data from these offsets:<br />
<br />
<code>$00</code><br />
: Overworld music - <code>$9B87</code><br />
<code>$01</code> or <code>$02</code><br />
: Town music - <code>$9BC6</code><br />
<code>$03</code> or <code>$04</code><br />
: Palace music - <code>$9C05</code><br />
<code>$05</code> or higher<br />
: Great Palace music - <code>$9C42</code><br />
<br />
First, uses the song offset in <code>$E2</code> to index into the song table at the base<br />
offset given above.<br />
<br />
The phrase counter at <code>$E3</code> is added to that and used as in index again to<br />
retrieve the current phrase offset. If the current phrase offset is <code>$00</code> that<br />
means the song is over and the process goes back to the Next Song routine.<br />
<br />
Otherwise, the following structure is read at the base offset above + phrase<br />
offset just calculated.<br />
<br />
* <code>$E5</code> Tempo<br />
* <code>$E0</code> Note Data Low<br />
* <code>$E1</code> Note Data High<br />
* <code>$07E9</code> Bass Note Pointer<br />
* <code>$07EA</code> Harmony Note Pointer<br />
* <code>$07E8</code> Drum Note Pointer<br />
<br />
After this, the drum loop start point at <code>$E4</code> is also set to the same value as<br />
the drum note pointer. The melody note pointer at <code>$07EB</code> is set to <code>$00</code>, and<br />
all the durations (melody at <code>$07E7</code>, harmony at <code>$07E6</code>, bass at <code>$07E5</code>, and<br />
drums at <code>$07E4</code>) are set to <code>$01</code>.<br />
<br />
Proceeds to Play Notes.<br />
<br />
==== Play Notes ====<br />
<br />
This routine is broken into four major and similar sections: one each for<br />
melody, harmony, bass, and drums. The general process is as follows:<br />
<br />
decrement duration<br />
if duration == 0 {<br />
load next note<br />
increment note pointer<br />
<br />
set duration for note<br />
if no overriding sound effect {<br />
play note on appropriate channel<br />
}<br />
}<br />
<br />
Some channels have unique processing at different points in this. For example,<br />
the melody note data is null terminated, so if the loaded note in <code>$00</code> then the<br />
routine will jump to Load Song Data instead to go to the next phrase. If the<br />
drums channel gets a <code>$00</code> note it will reset the drums note pointer to the<br />
drums loop start and repeat the phrase. The bass and harmony channels don't<br />
have this looping behavior. This means that if the bass or harmony channels<br />
aren't long enough, the engine will happily just play whatever data comes next<br />
in the ROM.<br />
<br />
The melody is played on pulse 2 channel, the harmony on pulse 1 (which gets<br />
subverted by sound effects that need just one pulse channel), the bass on the<br />
triangle channel, and the drums on the noise channel.<br />
<br />
For the pulse channels, after the note is played, the envelope counter for that<br />
channel (<code>$07E2</code> for pulse 1, <code>$07E3</code> for pulse 2) is set. Normally the<br />
envelope is set to <code>$2F</code> but song <code>$40</code> (crystal fanfare and final boss music)<br />
sets it to <code>$18</code> instead. The envelope is not set if no note was played because<br />
the pitch index was <code>$02</code> which indicates a rest.<br />
<br />
Also for the pulse channels, after the above pseudocode, the vibrato and<br />
enveloping happens as long as there is no overriding sound effect. The envelope<br />
works by checking the envelope counter set previously and decrementing it. The<br />
counter value is halved and used to look up the envelope value in the LUT at<br />
<code>$9135</code>. These values are written directly to APU register <code>$4000</code> or <code>$4004</code><br />
depending on the channel.<br />
<br />
The bass channel has one special handling as well. The APU register <code>$4008</code> is<br />
set differently based on the current song id. For song <code>$10</code> (item get / level<br />
up fanfare) the register is set to <code>$60</code> but all other songs use <code>$1f</code>.<br />
<br />
The noise channel is not affect at all by the pitch. Any pitch value that is<br />
non zero will play a burst of noise.</div>Bentglasstubehttp://wiki.bindingforce.net/index.php?title=Music_Engine_Description&diff=327Music Engine Description2021-09-26T03:53:30Z<p>Bentglasstube: Embolden TODOs</p>
<hr />
<div>There are two separate music engines in Zelda 2. Both are in bank 6 (along with<br />
the song data). The music engine for the title screen resides at $8000 and the<br />
engine for the rest of the game is at $9000. Each of these engines is called<br />
once per frame during the appropriate part of the game.<br />
<br />
== Title Music Engine ==<br />
<br />
'''TODO''' document further.<br />
<br />
== Main Music Engine ==<br />
<br />
The main loop for starts at bank 6 $9000<br />
<br />
=== Data Tables ===<br />
<br />
There are several data tables used by the music engine.<br />
<br />
==== Pulse Envelope ====<br />
<br />
This table is used to set the volume of the pulse channels over time. The index<br />
used starts at a certain value and decrements, so the table is in reverse order.<br />
The index is halved before use, so each value lasts two frames.<br />
<br />
{| class="wikitable"<br />
|+ Pulse Envelope <code>$9135</code><br />
|90||91||91||91||92||92||92||92<br />
|-<br />
|93||93||94||94||94||95||95||95<br />
|-<br />
|96||96||96||97||97||97||98||98<br />
|}<br />
<br />
==== Duration LUT ====<br />
<br />
This table is used to determine the duration of a note. The note data is stored<br />
with 5 bits of pitch information and 3 bits of duration, as such:<br />
<br />
{| class="wikitable"<br />
|D1||D0||P4||P3||P2||P1||P0||D2<br />
|}<br />
<br />
The Get Note Duration routine shifts things around to get the D bits into the<br />
three least significant bits and masks it before use. This value is then added<br />
to the tempo value in <code>$E5</code> which is always a multiple of 8 to index<br />
into the following table:<br />
<br />
{| class="wikitable"<br />
|+Duration LUT <code>$914D</code><br />
|'''00'''||04||0C||08||10||18||20||05||06<br />
|-<br />
|'''08'''||04||0F||09||12||1B||24||06||06<br />
|-<br />
|'''10'''||05||0F||0A||14||1E||28||07||06<br />
|-<br />
|'''18'''||06||12||0C||18||24||30||08||10<br />
|-<br />
|'''20'''||07||15||0E||1C||2A||38||13||12<br />
|-<br />
|'''28'''||07||15||0E||1C||2A||38||XX||XX<br />
|}<br />
<br />
The last two values in each row seem a bit strange, as they are not nice<br />
multiples of the first entry which is usually thought of as the length of an<br />
eighth note. The last row has garbage values in those positions as that is the<br />
start of another data table, so they are not even listed here.<br />
<br />
'''TODO''' Check what values are used in vanilla.<br />
<br />
=== Routines ===<br />
<br />
This is a non-exhaustive list of the routines in bank 6 involving the playing of<br />
music and sound effects. Each routine also lists its address so you can search<br />
in a disassembly for the actual code for that routine if these descriptions<br />
aren't clear.<br />
<br />
==== Main Music Loop <code>$9000</code> ====<br />
<br />
Checks that the music disable flag is off, then runs several SFX routines.<br />
After the SFX routines, the main music routine runs. After all this, various<br />
music related memory locations are cleared.<br />
<br />
==== Configure Pulse1 Channel <code>$9031</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4000</code> and <code>$4001</code><br />
respectively.<br />
<br />
==== Configure Pulse2 Channel <code>$9038</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4004</code> and <code>$4005</code><br />
respectively.<br />
<br />
==== Play Note Pulse1 <code>$9042</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 1 channel.<br />
<br />
==== Play Note <code>$9044</code> ====<br />
<br />
Called by the various play note routines. Takes a pitch index in register a and<br />
uses register x as a channel selector. For the pulse channels, this routine<br />
also saves the lower 8 bits of the APU timer register to <code>$E6</code> or <code>$E7</code> which<br />
are used for a vibrato effect.<br />
<br />
==== Play Note Pulse2 <code>$9067</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 2 channel.<br />
<br />
==== Play Note Triangle <code>$906B</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the triangle channel.<br />
<br />
==== Get Note Duration <code>$906F</code> ====<br />
<br />
Takes note data in register a and looks up the duration. The original note<br />
data is saved in register x and the result of the duration lookup is put in<br />
register a. The duration lookup is offset by the tempo stored in <code>$E5</code>.<br />
<br />
==== Vibrato Pulse1 <code>$9089</code> ====<br />
<br />
Applies a vibrato effect on the pulse 1 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato Pulse2 <code>$9097</code> ====<br />
<br />
Applies a vibrato effect on the pulse 2 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato <code>$909E</code> ====<br />
<br />
Takes the duration of the note remaining in register a, the low bits of the APU<br />
timer in register y, and the channel to use in register x. This is called by<br />
the other vibrato routines after setting x appropriately.<br />
<br />
Uses the <code>$04</code> bit of the duration to either add or subtract 2 from the low<br />
timer bits. Only the low bits are used because writing to the high bits resets<br />
the phase of the channel which can cause clicks. None of the notes from the<br />
pitch LUT are close enough to the boundary for the change to require the high<br />
bits to change anyway, so this works out fine.<br />
<br />
==== Play E9 SFX <code>$920B</code> ====<br />
<br />
Plays the sound effect requested in <code>$E9</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EF SFX <code>$92F4</code> ====<br />
<br />
Plays the sound effect requested in <code>$EF</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play EE SFX <code>$9408</code> ====<br />
<br />
Plays the sound effect requested in <code>$EE</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Noise <code>$959D</code> ====<br />
<br />
Configures the APU noise registers to make a noise burst. Takes configuration<br />
for registers <code>$400F</code>, <code>$400E</code>, and <code>$400C</code> in registers y, x, and a.<br />
<br />
==== Crumble Bridge SFX <code>$956C</code> ====<br />
<br />
Starts playing the sound effect for a crumble bridge crumbling. This uses both<br />
the noise and the triangle channels so it sets flags to disable the music on<br />
those channels. Continues with SFX Noise Decay.<br />
<br />
==== SFX Noise Decay <code>$9587</code> ====<br />
<br />
Counts down the timer in <code>$07F5</code> and turns off the noise when it reaches 0.<br />
Also clears the flag for the ED sound effect in <code>$07FD</code>.<br />
<br />
==== Play ED SFX <code>$95A7</code> ====<br />
<br />
Plays the sound effect request in <code>$ED</code> or continues the sound effect saved in<br />
<code>$07FD</code>. Existing sound effects which are higher than the current sound effect<br />
will be ignored. If the same sound effect is requested that is already playing,<br />
it will restart the sound effect except for <code>$80</code> which gives priority to<br />
continuing. When the sound is continued instead of newly played, the decay<br />
routine will be called instead.<br />
<br />
; <code>$02</code><br />
: Crumble Bridge<br />
; <code>$04</code> and <code>$10</code><br />
: Crumble Block / Enemy Hurt<br />
; <code>$20</code> and <code>$80</code><br />
: Sword Strike<br />
; <code>$40</code><br />
: Very short noise burst, probably unused. Doesn't store the effect, and doesn't have an associated decay.<br />
<br />
==== Crumble Block / Enemy Hurt SFX <code>$95E6</code> ====<br />
<br />
Starts playing the sound of a block breaking or an enemy getting hurt.<br />
<br />
==== Crumble Block / Enemy Hurt SFX Decay <code>$95EE</code> ====<br />
<br />
Looks up noise register values based on the timer and the sound effect value.<br />
Crumble Block samples are at <code>$912C</code> while Enemy Hurt is at <code>$9123</code>. Continues<br />
on to Play Noise Samples.<br />
<br />
==== Play Noise Samples <code>$9612</code> ====<br />
<br />
Takes a sample value in register a. The low four bits of this are used to set<br />
the noise period via APU register <code>$400E</code>. The high four bits are used to set<br />
the noise volume via APU register <code>$400C</code>.<br />
<br />
Continues on the SFX Noise Decay process.<br />
<br />
==== Sword Strike SFX <code>$9604</code> ====<br />
<br />
Starts playing the sound of swinging your sword. This looks up samples based on<br />
the duration left at <code>$90e8</code> and plays them via Play Noise Samples.<br />
<br />
==== Play EC SFX <code>$990B</code> ====<br />
<br />
Plays the sound effect requested in <code>$EC</code>.<br />
<br />
'''TODO''' document further.<br />
<br />
==== Play Music <code>$9B18</code> ====<br />
<br />
Plays the music for the game.<br />
<br />
Runs Load Song if a new song is requested in <code>$EB</code>. Otherwise, runs Play Notes<br />
if the current song is set in <code>$07FB</code>. If neither of these is true, do nothing.<br />
<br />
==== Next Song <code>$9B24</code> ====<br />
<br />
Checks if the previous song should loop. If not, calls Mute All and returns.<br />
<br />
If the previous song was <code>$01</code> (the "intro" to the main theme), sets the next<br />
song to <code>$02</code> (the main theme loop).<br />
<br />
If the previous song was <code>$10</code> (the item get / level up fanfare), sets the<br />
current song from <code>$07DB</code>. Otherwise, leaves the current song the same as the<br />
previous song.<br />
<br />
Proceeds to Load Song.<br />
<br />
==== Mute All <code>$9B3B</code> ====<br />
<br />
Clears the current song at <code>$07FB</code> and sets the APU registers to mute the volume<br />
on both pulse channels, the triangle channel, and the noise channel.<br />
<br />
==== Load Song <code>$9B61</code> ====<br />
<br />
Takes a song id in register a and preps some variables for that song.<br />
<br />
If the song is <code>$10</code> (item get / level up fanfare) then it first saves the<br />
previous song to <code>$07FB</code> if it is less than <code>$10</code> so that the previous music<br />
will resume after the fanfare.<br />
<br />
Sets the phrase counter at <code>$E3</code> to 0 and the song offset at <code>$E2</code> based on the<br />
song id. Song ids are a bit field, and the song offset is the position of the<br />
lowest bit in the song id for indexing into the song table.<br />
<br />
Proceeds to Load Song Data.<br />
<br />
==== Load Song Data <code>$9B80</code> ====<br />
<br />
Loads the music variables based on the current world and current song offset.<br />
<br />
There are four blocks of code that are basically the same, for each of the four<br />
different music tables. Each one just uses a different position for the tables<br />
to load.<br />
<br />
Based on the current world in <code>$0707</code> it loads data from these offsets:<br />
<br />
<code>$00</code><br />
: Overworld music - <code>$9B87</code><br />
<code>$01</code> or <code>$02</code><br />
: Town music - <code>$9BC6</code><br />
<code>$03</code> or <code>$04</code><br />
: Palace music - <code>$9C05</code><br />
<code>$05</code> or higher<br />
: Great Palace music - <code>$9C42</code><br />
<br />
First, uses the song offset in <code>$E2</code> to index into the song table at the base<br />
offset given above.<br />
<br />
The phrase counter at <code>$E3</code> is added to that and used as in index again to<br />
retrieve the current phrase offset. If the current phrase offset is <code>$00</code> that<br />
means the song is over and the process goes back to the Next Song routine.<br />
<br />
Otherwise, the following structure is read at the base offset above + phrase<br />
offset just calculated.<br />
<br />
* <code>$E5</code> Tempo<br />
* <code>$E0</code> Note Data Low<br />
* <code>$E1</code> Note Data High<br />
* <code>$07E9</code> Bass Note Pointer<br />
* <code>$07EA</code> Harmony Note Pointer<br />
* <code>$07E8</code> Drum Note Pointer<br />
<br />
After this, the drum loop start point at <code>$E4</code> is also set to the same value as<br />
the drum note pointer. The melody note pointer at <code>$07EB</code> is set to <code>$00</code>, and<br />
all the durations (melody at <code>$07E7</code>, harmony at <code>$07E6</code>, bass at <code>$07E5</code>, and<br />
drums at <code>$07E4</code>) are set to <code>$01</code>.<br />
<br />
Proceeds to Play Notes.<br />
<br />
==== Play Notes ====<br />
<br />
This routine is broken into four major and similar sections: one each for<br />
melody, harmony, bass, and drums. The general process is as follows:<br />
<br />
decrement duration<br />
if duration == 0 {<br />
load next note<br />
increment note pointer<br />
<br />
set duration for note<br />
if no overriding sound effect {<br />
play note on appropriate channel<br />
}<br />
}<br />
<br />
Some channels have unique processing at different points in this. For example,<br />
the melody note data is null terminated, so if the loaded note in <code>$00</code> then the<br />
routine will jump to Load Song Data instead to go to the next phrase. If the<br />
drums channel gets a <code>$00</code> note it will reset the drums note pointer to the<br />
drums loop start and repeat the phrase. The bass and harmony channels don't<br />
have this looping behavior. This means that if the bass or harmony channels<br />
aren't long enough, the engine will happily just play whatever data comes next<br />
in the ROM.<br />
<br />
The melody is played on pulse 2 channel, the harmony on pulse 1 (which gets<br />
subverted by sound effects that need just one pulse channel), the bass on the<br />
triangle channel, and the drums on the noise channel.<br />
<br />
For the pulse channels, after the note is played, the envelope counter for that<br />
channel (<code>$07E2</code> for pulse 1, <code>$07E3</code> for pulse 2) is set. Normally the<br />
envelope is set to <code>$2F</code> but song <code>$40</code> (crystal fanfare and final boss music)<br />
sets it to <code>$18</code> instead. The envelope is not set if no note was played because<br />
the pitch index was <code>$02</code> which indicates a rest.<br />
<br />
Also for the pulse channels, after the above pseudocode, the vibrato and<br />
enveloping happens as long as there is no overriding sound effect. The envelope<br />
works by checking the envelope counter set previously and decrementing it. The<br />
counter value is halved and used to look up the envelope value in the LUT at<br />
<code>$9135</code>. These values are written directly to APU register <code>$4000</code> or <code>$4004</code><br />
depending on the channel.<br />
<br />
The bass channel has one special handling as well. The APU register <code>$4008</code> is<br />
set differently based on the current song id. For song <code>$10</code> (item get / level<br />
up fanfare) the register is set to <code>$60</code> but all other songs use <code>$1f</code>.<br />
<br />
The noise channel is not affect at all by the pitch. Any pitch value that is<br />
non zero will play a burst of noise.</div>Bentglasstubehttp://wiki.bindingforce.net/index.php?title=Music_Engine_Description&diff=326Music Engine Description2021-09-26T03:52:04Z<p>Bentglasstube: Add section for data tables</p>
<hr />
<div>There are two separate music engines in Zelda 2. Both are in bank 6 (along with<br />
the song data). The music engine for the title screen resides at $8000 and the<br />
engine for the rest of the game is at $9000. Each of these engines is called<br />
once per frame during the appropriate part of the game.<br />
<br />
== Title Music Engine ==<br />
<br />
TODO document further.<br />
<br />
== Main Music Engine ==<br />
<br />
The main loop for starts at bank 6 $9000<br />
<br />
=== Data Tables ===<br />
<br />
There are several data tables used by the music engine.<br />
<br />
==== Pulse Envelope ====<br />
<br />
This table is used to set the volume of the pulse channels over time. The index<br />
used starts at a certain value and decrements, so the table is in reverse order.<br />
The index is halved before use, so each value lasts two frames.<br />
<br />
{| class="wikitable"<br />
|+ Pulse Envelope <code>$9135</code><br />
|90||91||91||91||92||92||92||92<br />
|-<br />
|93||93||94||94||94||95||95||95<br />
|-<br />
|96||96||96||97||97||97||98||98<br />
|}<br />
<br />
==== Duration LUT ====<br />
<br />
This table is used to determine the duration of a note. The note data is stored<br />
with 5 bits of pitch information and 3 bits of duration, as such:<br />
<br />
{| class="wikitable"<br />
|D1||D0||P4||P3||P2||P1||P0||D2<br />
|}<br />
<br />
The Get Note Duration routine shifts things around to get the D bits into the<br />
three least significant bits and masks it before use. This value is then added<br />
to the tempo value in <code>$E5</code> which is always a multiple of 8 to index<br />
into the following table:<br />
<br />
{| class="wikitable"<br />
|+Duration LUT <code>$914D</code><br />
|'''00'''||04||0C||08||10||18||20||05||06<br />
|-<br />
|'''08'''||04||0F||09||12||1B||24||06||06<br />
|-<br />
|'''10'''||05||0F||0A||14||1E||28||07||06<br />
|-<br />
|'''18'''||06||12||0C||18||24||30||08||10<br />
|-<br />
|'''20'''||07||15||0E||1C||2A||38||13||12<br />
|-<br />
|'''28'''||07||15||0E||1C||2A||38||XX||XX<br />
|}<br />
<br />
The last two values in each row seem a bit strange, as they are not nice<br />
multiples of the first entry which is usually thought of as the length of an<br />
eighth note. The last row has garbage values in those positions as that is the<br />
start of another data table, so they are not even listed here.<br />
<br />
'''TODO''' Check what values are used in vanilla.<br />
<br />
=== Routines ===<br />
<br />
This is a non-exhaustive list of the routines in bank 6 involving the playing of<br />
music and sound effects. Each routine also lists its address so you can search<br />
in a disassembly for the actual code for that routine if these descriptions<br />
aren't clear.<br />
<br />
==== Main Music Loop <code>$9000</code> ====<br />
<br />
Checks that the music disable flag is off, then runs several SFX routines.<br />
After the SFX routines, the main music routine runs. After all this, various<br />
music related memory locations are cleared.<br />
<br />
==== Configure Pulse1 Channel <code>$9031</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4000</code> and <code>$4001</code><br />
respectively.<br />
<br />
==== Configure Pulse2 Channel <code>$9038</code> ====<br />
<br />
Takes registers x and y and configures the APU registers <code>$4004</code> and <code>$4005</code><br />
respectively.<br />
<br />
==== Play Note Pulse1 <code>$9042</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 1 channel.<br />
<br />
==== Play Note <code>$9044</code> ====<br />
<br />
Called by the various play note routines. Takes a pitch index in register a and<br />
uses register x as a channel selector. For the pulse channels, this routine<br />
also saves the lower 8 bits of the APU timer register to <code>$E6</code> or <code>$E7</code> which<br />
are used for a vibrato effect.<br />
<br />
==== Play Note Pulse2 <code>$9067</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 2 channel.<br />
<br />
==== Play Note Triangle <code>$906B</code> ====<br />
<br />
Takes a pitch index in register a and plays the note on the triangle channel.<br />
<br />
==== Get Note Duration <code>$906F</code> ====<br />
<br />
Takes note data in register a and looks up the duration. The original note<br />
data is saved in register x and the result of the duration lookup is put in<br />
register a. The duration lookup is offset by the tempo stored in <code>$E5</code>.<br />
<br />
==== Vibrato Pulse1 <code>$9089</code> ====<br />
<br />
Applies a vibrato effect on the pulse 1 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato Pulse2 <code>$9097</code> ====<br />
<br />
Applies a vibrato effect on the pulse 2 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
==== Vibrato <code>$909E</code> ====<br />
<br />
Takes the duration of the note remaining in register a, the low bits of the APU<br />
timer in register y, and the channel to use in register x. This is called by<br />
the other vibrato routines after setting x appropriately.<br />
<br />
Uses the <code>$04</code> bit of the duration to either add or subtract 2 from the low<br />
timer bits. Only the low bits are used because writing to the high bits resets<br />
the phase of the channel which can cause clicks. None of the notes from the<br />
pitch LUT are close enough to the boundary for the change to require the high<br />
bits to change anyway, so this works out fine.<br />
<br />
==== Play E9 SFX <code>$920B</code> ====<br />
<br />
Plays the sound effect requested in <code>$E9</code>.<br />
<br />
TODO document further.<br />
<br />
==== Play EF SFX <code>$92F4</code> ====<br />
<br />
Plays the sound effect requested in <code>$EF</code>.<br />
<br />
TODO document further.<br />
<br />
==== Play EE SFX <code>$9408</code> ====<br />
<br />
Plays the sound effect requested in <code>$EE</code>.<br />
<br />
TODO document further.<br />
<br />
==== Play Noise <code>$959D</code> ====<br />
<br />
Configures the APU noise registers to make a noise burst. Takes configuration<br />
for registers <code>$400F</code>, <code>$400E</code>, and <code>$400C</code> in registers y, x, and a.<br />
<br />
==== Crumble Bridge SFX <code>$956C</code> ====<br />
<br />
Starts playing the sound effect for a crumble bridge crumbling. This uses both<br />
the noise and the triangle channels so it sets flags to disable the music on<br />
those channels. Continues with SFX Noise Decay.<br />
<br />
==== SFX Noise Decay <code>$9587</code> ====<br />
<br />
Counts down the timer in <code>$07F5</code> and turns off the noise when it reaches 0.<br />
Also clears the flag for the ED sound effect in <code>$07FD</code>.<br />
<br />
==== Play ED SFX <code>$95A7</code> ====<br />
<br />
Plays the sound effect request in <code>$ED</code> or continues the sound effect saved in<br />
<code>$07FD</code>. Existing sound effects which are higher than the current sound effect<br />
will be ignored. If the same sound effect is requested that is already playing,<br />
it will restart the sound effect except for <code>$80</code> which gives priority to<br />
continuing. When the sound is continued instead of newly played, the decay<br />
routine will be called instead.<br />
<br />
; <code>$02</code><br />
: Crumble Bridge<br />
; <code>$04</code> and <code>$10</code><br />
: Crumble Block / Enemy Hurt<br />
; <code>$20</code> and <code>$80</code><br />
: Sword Strike<br />
; <code>$40</code><br />
: Very short noise burst, probably unused. Doesn't store the effect, and doesn't have an associated decay.<br />
<br />
==== Crumble Block / Enemy Hurt SFX <code>$95E6</code> ====<br />
<br />
Starts playing the sound of a block breaking or an enemy getting hurt.<br />
<br />
==== Crumble Block / Enemy Hurt SFX Decay <code>$95EE</code> ====<br />
<br />
Looks up noise register values based on the timer and the sound effect value.<br />
Crumble Block samples are at <code>$912C</code> while Enemy Hurt is at <code>$9123</code>. Continues<br />
on to Play Noise Samples.<br />
<br />
==== Play Noise Samples <code>$9612</code> ====<br />
<br />
Takes a sample value in register a. The low four bits of this are used to set<br />
the noise period via APU register <code>$400E</code>. The high four bits are used to set<br />
the noise volume via APU register <code>$400C</code>.<br />
<br />
Continues on the SFX Noise Decay process.<br />
<br />
==== Sword Strike SFX <code>$9604</code> ====<br />
<br />
Starts playing the sound of swinging your sword. This looks up samples based on<br />
the duration left at <code>$90e8</code> and plays them via Play Noise Samples.<br />
<br />
==== Play EC SFX <code>$990B</code> ====<br />
<br />
Plays the sound effect requested in <code>$EC</code>.<br />
<br />
TODO document further.<br />
<br />
==== Play Music <code>$9B18</code> ====<br />
<br />
Plays the music for the game.<br />
<br />
Runs Load Song if a new song is requested in <code>$EB</code>. Otherwise, runs Play Notes<br />
if the current song is set in <code>$07FB</code>. If neither of these is true, do nothing.<br />
<br />
==== Next Song <code>$9B24</code> ====<br />
<br />
Checks if the previous song should loop. If not, calls Mute All and returns.<br />
<br />
If the previous song was <code>$01</code> (the "intro" to the main theme), sets the next<br />
song to <code>$02</code> (the main theme loop).<br />
<br />
If the previous song was <code>$10</code> (the item get / level up fanfare), sets the<br />
current song from <code>$07DB</code>. Otherwise, leaves the current song the same as the<br />
previous song.<br />
<br />
Proceeds to Load Song.<br />
<br />
==== Mute All <code>$9B3B</code> ====<br />
<br />
Clears the current song at <code>$07FB</code> and sets the APU registers to mute the volume<br />
on both pulse channels, the triangle channel, and the noise channel.<br />
<br />
==== Load Song <code>$9B61</code> ====<br />
<br />
Takes a song id in register a and preps some variables for that song.<br />
<br />
If the song is <code>$10</code> (item get / level up fanfare) then it first saves the<br />
previous song to <code>$07FB</code> if it is less than <code>$10</code> so that the previous music<br />
will resume after the fanfare.<br />
<br />
Sets the phrase counter at <code>$E3</code> to 0 and the song offset at <code>$E2</code> based on the<br />
song id. Song ids are a bit field, and the song offset is the position of the<br />
lowest bit in the song id for indexing into the song table.<br />
<br />
Proceeds to Load Song Data.<br />
<br />
==== Load Song Data <code>$9B80</code> ====<br />
<br />
Loads the music variables based on the current world and current song offset.<br />
<br />
There are four blocks of code that are basically the same, for each of the four<br />
different music tables. Each one just uses a different position for the tables<br />
to load.<br />
<br />
Based on the current world in <code>$0707</code> it loads data from these offsets:<br />
<br />
<code>$00</code><br />
: Overworld music - <code>$9B87</code><br />
<code>$01</code> or <code>$02</code><br />
: Town music - <code>$9BC6</code><br />
<code>$03</code> or <code>$04</code><br />
: Palace music - <code>$9C05</code><br />
<code>$05</code> or higher<br />
: Great Palace music - <code>$9C42</code><br />
<br />
First, uses the song offset in <code>$E2</code> to index into the song table at the base<br />
offset given above.<br />
<br />
The phrase counter at <code>$E3</code> is added to that and used as in index again to<br />
retrieve the current phrase offset. If the current phrase offset is <code>$00</code> that<br />
means the song is over and the process goes back to the Next Song routine.<br />
<br />
Otherwise, the following structure is read at the base offset above + phrase<br />
offset just calculated.<br />
<br />
* <code>$E5</code> Tempo<br />
* <code>$E0</code> Note Data Low<br />
* <code>$E1</code> Note Data High<br />
* <code>$07E9</code> Bass Note Pointer<br />
* <code>$07EA</code> Harmony Note Pointer<br />
* <code>$07E8</code> Drum Note Pointer<br />
<br />
After this, the drum loop start point at <code>$E4</code> is also set to the same value as<br />
the drum note pointer. The melody note pointer at <code>$07EB</code> is set to <code>$00</code>, and<br />
all the durations (melody at <code>$07E7</code>, harmony at <code>$07E6</code>, bass at <code>$07E5</code>, and<br />
drums at <code>$07E4</code>) are set to <code>$01</code>.<br />
<br />
Proceeds to Play Notes.<br />
<br />
==== Play Notes ====<br />
<br />
This routine is broken into four major and similar sections: one each for<br />
melody, harmony, bass, and drums. The general process is as follows:<br />
<br />
decrement duration<br />
if duration == 0 {<br />
load next note<br />
increment note pointer<br />
<br />
set duration for note<br />
if no overriding sound effect {<br />
play note on appropriate channel<br />
}<br />
}<br />
<br />
Some channels have unique processing at different points in this. For example,<br />
the melody note data is null terminated, so if the loaded note in <code>$00</code> then the<br />
routine will jump to Load Song Data instead to go to the next phrase. If the<br />
drums channel gets a <code>$00</code> note it will reset the drums note pointer to the<br />
drums loop start and repeat the phrase. The bass and harmony channels don't<br />
have this looping behavior. This means that if the bass or harmony channels<br />
aren't long enough, the engine will happily just play whatever data comes next<br />
in the ROM.<br />
<br />
The melody is played on pulse 2 channel, the harmony on pulse 1 (which gets<br />
subverted by sound effects that need just one pulse channel), the bass on the<br />
triangle channel, and the drums on the noise channel.<br />
<br />
For the pulse channels, after the note is played, the envelope counter for that<br />
channel (<code>$07E2</code> for pulse 1, <code>$07E3</code> for pulse 2) is set. Normally the<br />
envelope is set to <code>$2F</code> but song <code>$40</code> (crystal fanfare and final boss music)<br />
sets it to <code>$18</code> instead. The envelope is not set if no note was played because<br />
the pitch index was <code>$02</code> which indicates a rest.<br />
<br />
Also for the pulse channels, after the above pseudocode, the vibrato and<br />
enveloping happens as long as there is no overriding sound effect. The envelope<br />
works by checking the envelope counter set previously and decrementing it. The<br />
counter value is halved and used to look up the envelope value in the LUT at<br />
<code>$9135</code>. These values are written directly to APU register <code>$4000</code> or <code>$4004</code><br />
depending on the channel.<br />
<br />
The bass channel has one special handling as well. The APU register <code>$4008</code> is<br />
set differently based on the current song id. For song <code>$10</code> (item get / level<br />
up fanfare) the register is set to <code>$60</code> but all other songs use <code>$1f</code>.<br />
<br />
The noise channel is not affect at all by the pitch. Any pitch value that is<br />
non zero will play a burst of noise.</div>Bentglasstubehttp://wiki.bindingforce.net/index.php?title=Music_Engine_Description&diff=325Music Engine Description2021-09-26T00:42:44Z<p>Bentglasstube: Created page with "There are two separate music engines in Zelda 2. Both are in bank 6 (along with the song data). The music engine for the title screen resides at $8000 and the engine for the..."</p>
<hr />
<div>There are two separate music engines in Zelda 2. Both are in bank 6 (along with<br />
the song data). The music engine for the title screen resides at $8000 and the<br />
engine for the rest of the game is at $9000. Each of these engines is called<br />
once per frame during the appropriate part of the game.<br />
<br />
== Title Music Engine ==<br />
<br />
TODO document further.<br />
<br />
== Main Music Engine ==<br />
<br />
The main loop for starts at bank 6 $9000<br />
<br />
=== Main Music Loop <code>$9000</code> ===<br />
<br />
Checks that the music disable flag is off, then runs several SFX routines.<br />
After the SFX routines, the main music routine runs. After all this, various<br />
music related memory locations are cleared.<br />
<br />
=== Configure Pulse1 Channel <code>$9031</code> ===<br />
<br />
Takes registers x and y and configures the APU registers <code>$4000</code> and <code>$4001</code><br />
respectively.<br />
<br />
=== Configure Pulse2 Channel <code>$9038</code> ===<br />
<br />
Takes registers x and y and configures the APU registers <code>$4004</code> and <code>$4005</code><br />
respectively.<br />
<br />
=== Play Note Pulse1 <code>$9042</code> ===<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 1 channel.<br />
<br />
=== Play Note <code>$9044</code> ===<br />
<br />
Called by the various play note routines. Takes a pitch index in register a and<br />
uses register x as a channel selector. For the pulse channels, this routine<br />
also saves the lower 8 bits of the APU timer register to <code>$E6</code> or <code>$E7</code> which<br />
are used for a vibrato effect.<br />
<br />
=== Play Note Pulse2 <code>$9067</code> ===<br />
<br />
Takes a pitch index in register a and plays the note on the pulse 2 channel.<br />
<br />
=== Play Note Triangle <code>$906B</code> ===<br />
<br />
Takes a pitch index in register a and plays the note on the triangle channel.<br />
<br />
=== Get Note Duration <code>$906F</code> ===<br />
<br />
Takes note data in register a and looks up the duration. The original note<br />
data is saved in register x and the result of the duration lookup is put in<br />
register a. The duration lookup is offset by the tempo stored in <code>$E5</code>.<br />
<br />
=== Vibrato Pulse1 <code>$9089</code> ===<br />
<br />
Applies a vibrato effect on the pulse 1 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
=== Vibrato Pulse2 <code>$9097</code> ===<br />
<br />
Applies a vibrato effect on the pulse 2 channel. Takes the duration of the note<br />
left in register a and the APU timer low bits in register y.<br />
<br />
=== Vibrato <code>$909E</code> ===<br />
<br />
Takes the duration of the note remaining in register a, the low bits of the APU<br />
timer in register y, and the channel to use in register x. This is called by<br />
the other vibrato routines after setting x appropriately.<br />
<br />
Uses the <code>$04</code> bit of the duration to either add or subtract 2 from the low<br />
timer bits. Only the low bits are used because writing to the high bits resets<br />
the phase of the channel which can cause clicks. None of the notes from the<br />
pitch LUT are close enough to the boundary for the change to require the high<br />
bits to change anyway, so this works out fine.<br />
<br />
=== Play E9 SFX <code>$920B</code> ===<br />
<br />
Plays the sound effect requested in <code>$E9</code>.<br />
<br />
TODO document further.<br />
<br />
=== Play EF SFX <code>$92F4</code> ===<br />
<br />
Plays the sound effect requested in <code>$EF</code>.<br />
<br />
TODO document further.<br />
<br />
=== Play EE SFX <code>$9408</code> ===<br />
<br />
Plays the sound effect requested in <code>$EE</code>.<br />
<br />
TODO document further.<br />
<br />
=== Play Noise <code>$959D</code> ===<br />
<br />
Configures the APU noise registers to make a noise burst. Takes configuration<br />
for registers <code>$400F</code>, <code>$400E</code>, and <code>$400C</code> in registers y, x, and a.<br />
<br />
=== Crumble Bridge SFX <code>$956C</code> ===<br />
<br />
Starts playing the sound effect for a crumble bridge crumbling. This uses both<br />
the noise and the triangle channels so it sets flags to disable the music on<br />
those channels. Continues with SFX Noise Decay.<br />
<br />
=== SFX Noise Decay <code>$9587</code> ===<br />
<br />
Counts down the timer in <code>$07F5</code> and turns off the noise when it reaches 0.<br />
Also clears the flag for the ED sound effect in <code>$07FD</code>.<br />
<br />
=== Play ED SFX <code>$95A7</code> ===<br />
<br />
Plays the sound effect request in <code>$ED</code> or continues the sound effect saved in<br />
<code>$07FD</code>. Existing sound effects which are higher than the current sound effect<br />
will be ignored. If the same sound effect is requested that is already playing,<br />
it will restart the sound effect except for <code>$80</code> which gives priority to<br />
continuing. When the sound is continued instead of newly played, the decay<br />
routine will be called instead.<br />
<br />
; <code>$02</code><br />
: Crumble Bridge<br />
; <code>$04</code> and <code>$10</code><br />
: Crumble Block / Enemy Hurt<br />
; <code>$20</code> and <code>$80</code><br />
: Sword Strike<br />
; <code>$40</code><br />
: Very short noise burst, probably unused. Doesn't store the effect, and doesn't have an associated decay.<br />
<br />
=== Crumble Block / Enemy Hurt SFX <code>$95E6</code> ===<br />
<br />
Starts playing the sound of a block breaking or an enemy getting hurt.<br />
<br />
=== Crumble Block / Enemy Hurt SFX Decay <code>$95EE</code> ===<br />
<br />
Looks up noise register values based on the timer and the sound effect value.<br />
Crumble Block samples are at <code>$912C</code> while Enemy Hurt is at <code>$9123</code>. Continues<br />
on to Play Noise Samples.<br />
<br />
=== Play Noise Samples <code>$9612</code> ===<br />
<br />
Takes a sample value in register a. The low four bits of this are used to set<br />
the noise period via APU register <code>$400E</code>. The high four bits are used to set<br />
the noise volume via APU register <code>$400C</code>.<br />
<br />
Continues on the SFX Noise Decay process.<br />
<br />
=== Sword Strike SFX <code>$9604</code> ===<br />
<br />
Starts playing the sound of swinging your sword. This looks up samples based on<br />
the duration left at <code>$90e8</code> and plays them via Play Noise Samples.<br />
<br />
=== Play EC SFX <code>$990B</code> ===<br />
<br />
Plays the sound effect requested in <code>$EC</code>.<br />
<br />
TODO document further.<br />
<br />
=== Play Music <code>$9B18</code> ===<br />
<br />
Plays the music for the game.<br />
<br />
Runs Load Song if a new song is requested in <code>$EB</code>. Otherwise, runs Play Notes<br />
if the current song is set in <code>$07FB</code>. If neither of these is true, do nothing.<br />
<br />
=== Next Song <code>$9B24</code> ===<br />
<br />
Checks if the previous song should loop. If not, calls Mute All and returns.<br />
<br />
If the previous song was <code>$01</code> (the "intro" to the main theme), sets the next<br />
song to <code>$02</code> (the main theme loop).<br />
<br />
If the previous song was <code>$10</code> (the item get / level up fanfare), sets the<br />
current song from <code>$07DB</code>. Otherwise, leaves the current song the same as the<br />
previous song.<br />
<br />
Proceeds to Load Song.<br />
<br />
=== Mute All <code>$9B3B</code> ===<br />
<br />
Clears the current song at <code>$07FB</code> and sets the APU registers to mute the volume<br />
on both pulse channels, the triangle channel, and the noise channel.<br />
<br />
=== Load Song <code>$9B61</code> ===<br />
<br />
Takes a song id in register a and preps some variables for that song.<br />
<br />
If the song is <code>$10</code> (item get / level up fanfare) then it first saves the<br />
previous song to <code>$07FB</code> if it is less than <code>$10</code> so that the previous music<br />
will resume after the fanfare.<br />
<br />
Sets the phrase counter at <code>$E3</code> to 0 and the song offset at <code>$E2</code> based on the<br />
song id. Song ids are a bit field, and the song offset is the position of the<br />
lowest bit in the song id for indexing into the song table.<br />
<br />
Proceeds to Load Song Data.<br />
<br />
=== Load Song Data <code>$9B80</code> ===<br />
<br />
Loads the music variables based on the current world and current song offset.<br />
<br />
There are four blocks of code that are basically the same, for each of the four<br />
different music tables. Each one just uses a different position for the tables<br />
to load.<br />
<br />
Based on the current world in <code>$0707</code> it loads data from these offsets:<br />
<br />
<code>$00</code><br />
: Overworld music - <code>$9B87</code><br />
<code>$01</code> or <code>$02</code><br />
: Town music - <code>$9BC6</code><br />
<code>$03</code> or <code>$04</code><br />
: Palace music - <code>$9C05</code><br />
<code>$05</code> or higher<br />
: Great Palace music - <code>$9C42</code><br />
<br />
First, uses the song offset in <code>$E2</code> to index into the song table at the base<br />
offset given above.<br />
<br />
The phrase counter at <code>$E3</code> is added to that and used as in index again to<br />
retrieve the current phrase offset. If the current phrase offset is <code>$00</code> that<br />
means the song is over and the process goes back to the Next Song routine.<br />
<br />
Otherwise, the following structure is read at the base offset above + phrase<br />
offset just calculated.<br />
<br />
* <code>$E5</code> Tempo<br />
* <code>$E0</code> Note Data Low<br />
* <code>$E1</code> Note Data High<br />
* <code>$07E9</code> Bass Note Pointer<br />
* <code>$07EA</code> Harmony Note Pointer<br />
* <code>$07E8</code> Drum Note Pointer<br />
<br />
After this, the drum loop start point at <code>$E4</code> is also set to the same value as<br />
the drum note pointer. The melody note pointer at <code>$07EB</code> is set to <code>$00</code>, and<br />
all the durations (melody at <code>$07E7</code>, harmony at <code>$07E6</code>, bass at <code>$07E5</code>, and<br />
drums at <code>$07E4</code>) are set to <code>$01</code>.<br />
<br />
Proceeds to Play Notes.<br />
<br />
=== Play Notes ===<br />
<br />
This routine is broken into four major and similar sections: one each for<br />
melody, harmony, bass, and drums. The general process is as follows:<br />
<br />
decrement duration<br />
if duration == 0 {<br />
load next note<br />
increment note pointer<br />
<br />
set duration for note<br />
if no overriding sound effect {<br />
play note on appropriate channel<br />
}<br />
}<br />
<br />
Some channels have unique processing at different points in this. For example,<br />
the melody note data is null terminated, so if the loaded note in <code>$00</code> then the<br />
routine will jump to Load Song Data instead to go to the next phrase. If the<br />
drums channel gets a <code>$00</code> note it will reset the drums note pointer to the<br />
drums loop start and repeat the phrase. The bass and harmony channels don't<br />
have this looping behavior. This means that if the bass or harmony channels<br />
aren't long enough, the engine will happily just play whatever data comes next<br />
in the ROM.<br />
<br />
The melody is played on pulse 2 channel, the harmony on pulse 1 (which gets<br />
subverted by sound effects that need just one pulse channel), the bass on the<br />
triangle channel, and the drums on the noise channel.<br />
<br />
For the pulse channels, after the note is played, the envelope counter for that<br />
channel (<code>$07E2</code> for pulse 1, <code>$07E3</code> for pulse 2) is set. Normally the<br />
envelope is set to <code>$2F</code> but song <code>$40</code> (crystal fanfare and final boss music)<br />
sets it to <code>$18</code> instead. The envelope is not set if no note was played because<br />
the pitch index was <code>$02</code> which indicates a rest.<br />
<br />
Also for the pulse channels, after the above pseudocode, the vibrato and<br />
enveloping happens as long as there is no overriding sound effect. The envelope<br />
works by checking the envelope counter set previously and decrementing it. The<br />
counter value is halved and used to look up the envelope value in the LUT at<br />
<code>$9135</code>. These values are written directly to APU register <code>$4000</code> or <code>$4004</code><br />
depending on the channel.<br />
<br />
The bass channel has one special handling as well. The APU register <code>$4008</code> is<br />
set differently based on the current song id. For song <code>$10</code> (item get / level<br />
up fanfare) the register is set to <code>$60</code> but all other songs use <code>$1f</code>.<br />
<br />
The noise channel is not affect at all by the pitch. Any pitch value that is<br />
non zero will play a burst of noise.</div>Bentglasstubehttp://wiki.bindingforce.net/index.php?title=Main_Page&diff=324Main Page2021-09-26T00:32:55Z<p>Bentglasstube: Add link to music engine description and improve name of section.</p>
<hr />
<div>== Zelda 2 Speedrun Community Wiki ==<br />
<br />
=== Speedrun Help and Info ===<br />
*[[Speedrun Categories]]<br />
*[[Routing Variations]]<br />
*[[Speedrun Tricks and Strats|Tricks and Strats]]<br />
*[[Hyrule|Maps and World Info]]<br />
*[[Overworld Walks]]<br />
*[[Combat Tech]]<br />
*[[Game Data]]<br />
*[[Enemies]]<br />
*[[Items, Spells, and Sword Techniques]]<br />
<br />
<br />
----<br />
<br />
=== Rom Hacking ===<br />
*[[Z2 Randomizer]]<br />
*[[Z2 Hacks]]<br />
*[[Hacking Resources]]<br />
*[[Music Engine Description]]<br />
<br />
<br />
----<br />
<br />
=== Leaderboard pages ===<br />
*[https://www.speedrun.com/zelda_ii_the_adventure_of_link Main Zelda 2 Leaderboard]<br />
*[https://www.speedrun.com/zelda2ce Zelda 2 Category Extensions]<br />
*[https://www.speedrun.com/z2fds The Legend of Zelda 2: Link no Bouken (FDS Zelda 2) Leaderboard]<br />
*[https://www.speedrun.com/z2_ws Winter Solstice]</div>Bentglasstube