On this page
  1. Super Mario Bros.
  2. Pokémon Red and Blue
  3. Super Mario World
  4. Related
  5. Games
  6. References
  7. Sources

A music driver turns song data into register writes. The NES’s audio unit offers two pulse channels with duty settings of 12.5%, 25%, 50%, 75%1, a triangle with a fixed waveform2, a noise channel3, and a sample channel4. A driver called once a frame decides, channel by channel, when each note starts, what period it plays at, and how its volume moves.

Interactive: apu-synth (needs JavaScript)

NES sound, channel by channel
  • Length tableSuper Mario Bros. (1985). Each song times its notes in whole frames from its own row of lengths; the hurry-up tunes take a faster row.5,6,7,8,9The Legend of Zelda (1986). Super Mario Bros.' layout: per-song length rows, big-endian periods.10
  • Fractional tempoSuper Mario World (1990). A 2 ms timer tick adds the tempo to an 8-bit accumulator, and each carry calls the sound engine's step.11Pokémon Red and Blue (1996). A note lasts length × speed × tempo / 256 frames, the remainder carried to the next.12

#Super Mario Bros.

The NMI handler calls the sound engine every frame, and the music handler steps square 2, square 1, the triangle, and the noise channel in that order5. Each channel reads a byte when its counter reaches 0; on square 2 and the triangle a negative byte sets a new length and a positive one plays a note5.

  • Tempo. The song’s header picks a row of the length table, and the overworld theme’s row is 54, 3, 9, 6, 18, 27, 36, 12 frames6. The hurry-up version moves to a faster row6.
  • Pitch. A note byte indexes a table of timer periods7, and a square channel plays period t at fCPU/(16(t+1))13; the triangle plays the same period an octave lower2.
  • Envelope. A square note’s volume follows a table one step per frame: volumes 0, 8, 7, 6, 5, 5, 4, 4, then 0, at 50% duty8.
  • Drums. The noise channel plays three drum sounds, written to its registers as $400C, $400E, $400F: short $1C $03 $18, strong $1C $0C $18, long $1C $03 $589.

#Pokémon Red and Blue

The Game Boy has two pulse channels, a wave channel that plays a wave the program supplies, and noise14. Pokémon’s engine runs once a frame and times notes with a fraction: a note lasts ⌊(ℓsT+f)/256⌋ frames, and the remainder f carries to the next note12.

#Super Mario World

Super Mario World’s sound engine runs on a timer. Each tick adds the song’s tempo byte to an 8-bit accumulator, and each carry calls APU_0BC0, a routine the atlas hasn’t read11.

Games

GameYearHowNote
Super Mario Bros.1985Length tableeach song times its notes in whole frames from its own row of lengths; the hurry-up tunes take a faster row
The Legend of Zelda1986Length tableSuper Mario Bros.' layout: per-song length rows, big-endian periods
Super Mario World1990Fractional tempoa 2 ms timer tick adds the tempo to an 8-bit accumulator, and each carry calls the sound engine's step
Pokémon Red and Blue1996Fractional tempoa note lasts length × speed × tempo / 256 frames, the remainder carried to the next
Every claim about this mechanic, by game (50)
Super Mario Bros. 1985The NMI handler calls the sound engine once a frame; its music handler steps square 2, square 1, the triangle, and the noise channel in turn, and each channel counts its note length down by 1 per frame and reads its next byte at 0.Code
A song's header picks an 8-entry row of MusicLengthLookupTbl, and a length code of 0-7 indexes it in frames; the overworld theme's row is 54, 3, 9, 6, 18, 27, 36, 12, a quarter note of 18 frames, and the hurry-up version adds 8 to the row offset for 36, 2, 6, 4, 12, 18, 24, 8.Code
A note byte is an offset into FreqRegLookupTbl, a table of 51 two-byte timer periods that the driver writes to the channel's timer registers; a recreation turns period t into fCPU/(16(t+1)) Hz on a square channel and half that on the triangle.Code
A new area-music square note sets duty and volume byte $82 and an envelope index of 8; each frame the driver writes AreaMusicEnvData[index] to the channel and counts the index down, so the note plays at 50% duty with volumes 0, 8, 7, 6, 5, 5, 4, 4 and then 0 until the next note.Code
The noise channel plays three drum sounds, all at constant volume 12 ($400C = $1C), a short beat at period index 3, a strong beat at period index 12, and a long beat at period index 3 with a longer length-counter load ($58 instead of $18).Code
Super Mario Bros.: The Lost Levels 1986The sound engine (SoundEngine through MusicHandler) is Super Mario Bros.'s with two new sounds in the noise handler: the skid, played on the triangle channel from SkidSfxFreqData, and the wind, played from WindFreqEnvData; both tables sit after the square 2 handler. SoundEngine, Dump_Squ1_Regs, Square1SfxHandler and MusicHandler differ only in their addresses.Code
SM2MAIN's music data is Super Mario Bros.'s less the victory theme: the headers lose VictoryMusHdr and their offsets shift by its five bytes, the residual header bytes differ, and VictoryMusData is gone from between the castle-clear music and the frequency tables, with two of the three unused bytes after it (the ending's music lives in SM2DATA3). The notes of every other song and the frequency, note-length and envelope tables after them are byte for byte the same.Code
1,299 bytes of The Lost Levels' music are Super Mario Bros.'s byte for byte: the last bytes of the music headers and the notes of every song SM2MAIN plays, from the star music (Star_CloudMData) through the ground music's parts, death, castle, game over, time running out, level end, underground, water and the castle-clear music (EndOfCastleMusData).Code
AlternateSoundEngine, the ending's sound engine in SM2DATA3, is a rewrite of Super Mario Bros.'s MusicHandler that keeps its note and length code: it has no event or area music buffers and no time-running-out handling, steps through a list of patterns with PatternNumber, reading each pattern's header from MusicHeaderData, has its own pause and silence code, and plays the ending's music on the disk system's wavetable channel as well as the square, triangle and noise channels, with its own waveform, envelope and modulation tables.Code
The Legend of Zelda 1986The music driver has Super Mario Bros.' layout; a song entry sets a base into a note-length table, a length code's low 3 bits index it, notes index a table of big-endian 16-bit timer periods, and a square note starts with duty byte $82 and sweep byte $7F, the same register values Super Mario Bros. uses.Code
Mega Man 2 1988Mega Man 2's sound engine entry and channel setup are Mega Man's, with two changes: _music_fade_in_out no longer ignores a new fade while one is running, and where Mega Man steps X with INX, four operands use an address plus 1 instead and one writes SQ1_SWEEP plus X. The engine starts at $8000 instead of $9000, so its jump and call addresses differ too.Code
Mega Man 2's per-frame channel update is Mega Man's, except that _break_frame and the end of _pitch_envelope_common address the next APU register as SQ1_SWEEP plus X, where Mega Man steps X with INX and writes SQ1_VOL plus X. The code sits $100A lower, so its jump and call addresses differ too.Code
Mega Man 2's song data reader is Mega Man's, instruction for instruction and with the same RAM, so the two games read the same note and command format. It sits $100C lower: only its jump and call addresses, its command table, and the address of the note table differ.Code
Mega Man 2's note length and pitch tables are Mega Man's but for one pitch: the period of the note the disassembly names nEb1 drops from $059E to $0594, about 12 cents higher (computed). The region also ends with 3 bytes of $FF filler instead of 7.Code
Mega Man 3 1990Both games run their sound driver from the NMI, but Mega Man 3's is new code with a new layout. Mega Man 2 keeps the driver and its songs together in bank 12, queues up to 16 tracks, and works out a note's length as a table value times its channel's tempo byte. Mega Man 3 keeps the code in bank 22 and the data in bank 23, reading bank 24 for data addresses from $C000; it takes sound IDs from an eight-entry ring buffer in the fixed bank, and refuses a sound whose priority byte is lower than the one playing.Code
Super Mario World 1990The engine's main loop waits on timer 0, set to tick every 2 ms; for each tick it adds the song's tempo byte to an 8-bit accumulator, and on a carry out it calls the routine APU_0BC0, unless a flag at audio RAM $0388 is set. That routine wasn't read; the structure suggests it is one step of the music, which would make the tempo set the step rate. The tempo starts at $36, which gives 500 × 54 / 256, about 105 carries a second.Code
Mega Man 4 1991Mega Man 4's sound bank opens with Mega Man 3's entry jumps, multiply, and sound-data read, at the same addresses; only the two bank numbers the read maps differ: the overflow data bank, $18 in Mega Man 3 and $1D in Mega Man 4, and the data bank it restores, $17 and $1F.Code
Mega Man 4's per-frame sound tick is Mega Man 3's sound_driver_update, byte for byte at the same address.Code
Mega Man 4's routine that starts a song or an effect, and takes the stop, pause, fade, and transpose commands, is Mega Man 3's, byte for byte at the same address.Code
Mega Man 4's music track reader is Mega Man 3's (labeled process_sfx_channel there), byte for byte at the same address, so the two games read the same track format.Code
Mega Man 4's note-to-pitch routines are Mega Man 3's, byte for byte at the same address.Code
Mega Man 4's volume envelope and fade code is Mega Man 3's, byte for byte at the same address.Code
Mega Man 4's code that writes each channel's pitch to the APU, with vibrato, detune, and slides, is Mega Man 3's, byte for byte at the same address.Code
Mega Man 4's sound driver tables, through the note period table, are Mega Man 3's at the same addresses; the 37 bytes after it ($8A1B-$8A3F), all zero in Mega Man 3, hold data in Mega Man 4.Code
Mega Man 5 1992Mega Man 5's sound bank, bank $18, opens with Mega Man 4's entry jumps, multiply, and sound-data read at the same addresses; only the two bank numbers the read maps differ: the overflow data bank, $1D in Mega Man 4 and $1A in Mega Man 5, and the data bank it restores, $1F and $19.Code
Mega Man 5's per-frame sound tick is Mega Man 4's, byte for byte at the same address.Code
Mega Man 5's routine that starts a song or an effect, and takes the stop, pause, fade, and transpose commands, is Mega Man 4's, byte for byte at the same address.Code
Mega Man 5's music track reader is Mega Man 4's, byte for byte at the same address.Code
Mega Man 5's note-to-pitch routines is Mega Man 4's, byte for byte at the same address.Code
Mega Man 5's volume envelope and fade code is Mega Man 4's, byte for byte at the same address.Code
Mega Man 5's code that writes each channel's pitch to the APU, with vibrato, detune, and slides, is Mega Man 4's, byte for byte at the same address.Code
Mega Man 5's sound driver tables, through the note period table, are Mega Man 4's at the same addresses. The 37 bytes after it ($8A1B-$8A3F), which hold data in Mega Man 4, are all zero in Mega Man 5, as in Mega Man 3.Code
Mega Man 6 1993Mega Man 6's sound bank, bank $34, opens with Mega Man 5's entry jumps, multiply, and sound-data read at the same addresses; only the two bank numbers the read maps differ: the overflow data bank, $1A in Mega Man 5 and $36 in Mega Man 6, and the data bank it restores, $19 and $35.Code
Mega Man 6's per-frame sound tick is Mega Man 5's at the same address; three call targets differ, because the stream readers they call sit one byte lower in Mega Man 6.Code
Mega Man 6's sound command routine is Mega Man 5's with one change: where Mega Man 5 steps the sound's data pointer by incrementing $C1 and, on a carry, $C2 before copying it to $D0 and $D1, Mega Man 6 carries into X instead, so $C2 is left as it was, and the routine is a byte shorter. Code after it sits one byte lower, and its jumps, calls, and jump-table entries follow.Code
Mega Man 6's music track reader is Mega Man 5's, one byte lower ($8392 against $8393); only its call and jump targets, jump-table entries, and the addresses of the tables it reads differ.Code
Mega Man 6's note-to-period lookup is Mega Man 5's, one byte lower; the only differences are the two operands that address the period table, which sits seven bytes higher in Mega Man 6 ($8960 against $8959).Code
Mega Man 6's volume envelope code is Mega Man 5's, one byte lower; only its jump-table entries, call targets, and the address of the envelope step table, seven bytes higher, differ.Code
Mega Man 6's period output is Mega Man 5's with one step added: after adding the channel's signed offset at $0714 to the period, a period of zero becomes 1. The added 8 bytes push the sound tables seven bytes higher, and the routine's table operands follow.Code
Mega Man 6's sound tables (note lengths, octave offsets, envelope steps, octave thresholds, and the period table) are Mega Man 5's byte for byte, seven bytes higher at $891C; the zero padding after them, up to the song directory at $8A40, is seven bytes shorter.Code
Mega Man 6's sounds $23-$3C, the first 26 after its music, at $B758-$BAC2 of bank $36, are 22 of Mega Man 5's sounds from $1A to $3E plus four new ones ($2A-$2D). The 22 keep Mega Man 5's order, except that its $3E comes in as $2E. Seventeen are byte for byte. In the other five only addresses differ, each moved as far as the sound: one address inside each of four effects, and the four track pointers of $39, a sound with music's priority $00 (Mega Man 5's $30). Mega Man 6 leaves out 12 of Mega Man 5's $1A-$3A: $1F, $21, $23, $2B, $2F, $31-$34, and $36-$38. The Mega Man 5 disassembly's notes name two of the carried sounds, the ricochet ($1E, Mega Man 6's $27) and the hit ($2A, Mega Man 6's $35); the kill sound ($2B) is one of those left out.Verified
Mega Man 6's music $13, 116 bytes at $A19B-$A20E of bank $36, is Mega Man 5's music $11 moved. Only the four track pointers in its header differ, each $625 lower, as far as the song's start moved.Verified
Mega Man 6's instrument table, 71 instruments of 8 bytes at $8B0F, has as many instruments as Mega Man 5's at $8ADB, but only 27 are the same under the same number. The longest such run is nine instruments, $3D-$45 (72 bytes). One more of Mega Man 6's is in Mega Man 5's table under another number.Verified
Pokémon Red and Blue 1996The sound engine runs once a frame from the vertical blank handler. A note lasts ⌊(ℓ⋅s⋅T+f)/256⌋ frames, where ℓ is its length in 16ths, s the channel's note speed, T the song's 16-bit tempo, and f the channel's leftover fraction, which the low byte carries to the next note.Code
generalThe Game Boy has four sound channels, each specialized, with two pulse channels with four fixed duty settings, a wave channel that plays a user-supplied wave, and a noise channel.Wiki
A pulse channel's duty is 12.5%, 25%, 50%, or 75%, and its 8-step waveform is clocked at 1,048,576 Hz divided by 2048−p for an 11-bit period value p, so the tone is 131072/(2048−p) Hz.Wiki
The APU has two pulse channels, each with four duty settings, 12.5%, 25%, 50%, and 25% negated (75%), as 8-step sequences.Wiki
A pulse channel's frequency is f=fCPU/(16(t+1)) for an 11-bit timer period t, with fCPU = 1.789773 MHz on NTSC; periods below 8 silence the channel.Wiki
The triangle channel steps a fixed 32-step sequence, 15 down to 0 and back up, at f=fCPU/(32(t+1)), so it has no duty or volume setting.Wiki
The noise channel clocks a 15-bit shift register at one of 16 periods; in normal mode the sequence is 32,767 steps long, and the periodic mode gives 93- or 31-step loops.Wiki

References

  1. ^The APU has two pulse channels, each with four duty settings, 12.5%, 25%, 50%, and 25% negated (75%), as 8-step sequences.WikiNESdev Wiki, “APU Pulse”
    How we know
    Each of the two NES APU pulse (square) wave channels generate a pulse wave with variable duty.
    lead · archived copy ↗
    1 0 0 1 1 1 1 1 (25% negated)
    Sequencer behavior · archived copy ↗

    Checked against the evidence by its author, an AI model, 2026-10-21.

    Checked by a second AI model, 2026-10-21.

    In the claim ledger

  2. ^ abThe triangle channel steps a fixed 32-step sequence, 15 down to 0 and back up, at f=fCPU/(32(t+1)), so it has no duty or volume setting.WikiNESdev Wiki, “APU Triangle”
    How we know
    The sequencer sends the following looping 32-step sequence of values to the mixer: … f = fCPU ÷ (32 × (tval + 1)) … The triangle channel contains the following: timer, length counter, linear counter, linear counter reload flag, control flag, sequencer.
    lead · archived copy ↗

    Checked against the evidence by its author, an AI model, 2026-10-21.

    Checked by a second AI model, 2026-10-21.

    In the claim ledger

  3. ^The noise channel clocks a 15-bit shift register at one of 16 periods; in normal mode the sequence is 32,767 steps long, and the periodic mode gives 93- or 31-step loops.WikiNESdev Wiki, “APU Noise”
    How we know
    The period determines how many CPU cycles happen between shift register clocks.
    Noise mode and period ($400E, write) · archived copy ↗
    This results in a pseudo-random bit sequence, 32767 steps long when Mode flag is clear, and randomly 93 or 31 steps long otherwise.
    Operation · archived copy ↗

    Checked against the evidence by its author, an AI model, 2026-10-21.

    Checked by a second AI model, 2026-10-21.

    In the claim ledger

  4. ^The delta modulation channel (DMC) plays 1-bit delta-encoded samples from $C000+64A, 16L+1 bytes long, at one of 16 rates; a program can also load its 7-bit output level directly through $4011.WikiNESdev Wiki, “APU DMC”
    How we know
    The NES APU's delta modulation channel (DMC) can output 1-bit delta-encoded samples or can have its 7-bit counter directly loaded, allowing flexible manual sample playback.
    lead · archived copy ↗
    Sample address = %11AAAAAA.AA000000 = $C000 + (A * 64) … Sample length = %LLLL.LLLL0001 = (L * 16) + 1 bytes
    Overview · archived copy ↗
    For example, on NTSC (1.789773 MHz), a rate of 428 gives a frequency of 1789773/428 Hz = 4181.71 Hz.
    Pitch table · archived copy ↗

    Checked against the evidence by its author, an AI model, 2026-10-21.

    Checked by a second AI model, 2026-10-21.

    In the claim ledger

  5. ^ abcThe NMI handler calls the sound engine once a frame; its music handler steps square 2, square 1, the triangle, and the noise channel in turn, and each channel counts its note length down by 1 per frame and reads its next byte at 0.CodeXkeeper0/smb1
    How we know
    115	JSR SoundEngine                              ; play sound
    
    src/prg.asm line 115 at 1cc3c92 · upstream ↗
    691HandleSquare2Music:
    692	DEC Squ2_NoteLenCounter                      ; decrement square 2 note length
    693	BNE MiscSqu2MusicTasks                       ; is it time for more data?  if not, branch to end tasks
    694	LDY MusicOffset_Square2                      ; increment square 2 music offset and fetch data
    695	INC MusicOffset_Square2
    696	LDA (MusicData),y
    697	BEQ EndOfMusicData                           ; if zero, the data is a null terminator
    698	BPL Squ2NoteHandler                          ; if non-negative, data is a note
    
    src/music-engine.asm lines 691–698 at 1cc3c92 · upstream ↗
    763HandleSquare1Music:
    764	LDY MusicOffset_Square1                      ; is there a nonzero offset here?
    765	BEQ HandleTriangleMusic                      ; if not, skip ahead to the triangle channel
    766	DEC Squ1_NoteLenCounter                      ; decrement square 1 note length
    
    src/music-engine.asm lines 763–766 at 1cc3c92 · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-21.

    Checked by a second AI model, 2026-10-21.

    In the claim ledger

  6. ^ abcA song's header picks an 8-entry row of MusicLengthLookupTbl, and a length code of 0-7 indexes it in frames; the overworld theme's row is 54, 3, 9, 6, 18, 27, 36, 12, a quarter note of 18 frames, and the hurry-up version adds 8 to the row offset for 36, 2, 6, 4, 12, 18, 24, 8.CodeXkeeper0/smb1
    How we know
    34; header format is as follows:
    35; 1 byte - length byte offset
    
    src/music-data.asm lines 34–39 at 1cc3c92 · upstream ↗
    662LoadHeader:
    663	LDA MusicHeaderOffsetData,y                  ; load offset for header
    664	TAY
    665	LDA MusicHeaderData,y                        ; now load the header
    666	STA NoteLenLookupTblOfs
    
    src/music-engine.asm lines 662–666 at 1cc3c92 · upstream ↗
    521NoteLenLookupTblOfs   = $f0
    
    src/ram.asm line 521 at 1cc3c92 · upstream ↗
    63GroundLevelPart1Hdr:
    64	.db $18, <GroundM_P1Data, >GroundM_P1Data, $2d, $1c, $b8
    
    src/music-data.asm lines 63–64 at 1cc3c92 · upstream ↗
    377MusicLengthLookupTbl:
    378	.db $05, $0a, $14, $28, $50, $1e, $3c, $02
    379	.db $04, $08, $10, $20, $40, $18, $30, $0c
    380	.db $03, $06, $0c, $18, $30, $12, $24, $08
    381	.db $36, $03, $09, $06, $12, $1b, $24, $0c
    382	.db $24, $02, $06, $04, $0c, $12, $18, $08
    383	.db $12, $01, $03, $02, $06, $09, $0c, $04
    
    src/music-data.asm lines 377–383 at 1cc3c92 · upstream ↗
    925ProcessLengthData:
    926	AND #%00000111                               ; clear all but the three LSBs
    927	CLC
    928	ADC $f0                                      ; add offset loaded from first header byte
    929	ADC NoteLengthTblAdder                       ; add extra if time running out music
    
    src/music-engine.asm lines 925–933 at 1cc3c92 · upstream ↗
    625	CMP #TimeRunningOutMusic                     ; is it time running out music?
    626	BNE FindEventMusicHeader
    627	LDX #$08                                     ; load offset to be added to length byte of header
    
    src/music-engine.asm lines 625–627 at 1cc3c92 · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-25.

    Checked by a second AI model, 2026-10-21.

    Checked by a second AI model, 2026-10-25.

    In the claim ledger

  7. ^ abA note byte is an offset into FreqRegLookupTbl, a table of 51 two-byte timer periods that the driver writes to the channel's timer registers; a recreation turns period t into fCPU/(16(t+1)) Hz on a square channel and half that on the triangle.CodeXkeeper0/smb1 · NESdev Wiki, “APU Pulse” · NESdev Wiki, “APU Triangle”
    How we know
    107Dump_Freq_Regs:
    108	TAY
    109	LDA FreqRegLookupTbl+1,y                     ; use previous contents of A for sound reg offset
    110	BEQ NoTone                                   ; if zero, then do not load
    111	STA SND_REGISTER+2,x                         ; first byte goes into LSB of frequency divider
    112	LDA FreqRegLookupTbl,y                       ; second byte goes into 3 MSB plus extra bit for
    
    src/music-engine.asm lines 107–115 at 1cc3c92 · upstream ↗
    362FreqRegLookupTbl:
    363	.db $00, $88, $00, $2f, $00, $00
    364	.db $02, $a6, $02, $80, $02, $5c, $02, $3a
    ⋮
    375	.db $02, $f9, $02, $cf, $01, $fc, $00, $6a
    
    src/music-data.asm lines 362–375 at 1cc3c92 · upstream ↗
    fpulse = fCPU/(16*(t+1))
    Pulse channel output to mixer · archived copy ↗
    f = fCPU ÷ (32 × (tval + 1))
    lead · archived copy ↗

    Checked against the evidence by its author, an AI model, 2026-10-21.

    Checked by a second AI model, 2026-10-21.

    In the claim ledger

  8. ^ abA new area-music square note sets duty and volume byte $82 and an envelope index of 8; each frame the driver writes AreaMusicEnvData[index] to the channel and counts the index down, so the note plays at 50% duty with volumes 0, 8, 7, 6, 5, 5, 4, 4 and then 0 until the next note.CodeXkeeper0/smb1
    How we know
    934LoadControlRegs:
    ⋮
    944	LDA #$08                                     ; this is the default value for all other music
    ⋮
    949	LDX #$82                                     ; load contents of other sound regs for square 2
    950	LDY #$7f
    
    src/music-engine.asm lines 934–952 at 1cc3c92 · upstream ↗
    754	LDY Squ2_EnvelopeDataCtrl                    ; check for contents saved from LoadControlRegs
    755	BEQ NoDecEnv1
    756	DEC Squ2_EnvelopeDataCtrl                    ; decrement unless already zero
    757NoDecEnv1:
    758	JSR LoadEnvelopeData                         ; do a load of envelope data to replace default
    759	STA SND_SQUARE2_REG                          ; based on offset set by first load unless playing
    
    src/music-engine.asm lines 754–759 at 1cc3c92 · upstream ↗
    388AreaMusicEnvData:
    389	.db $90, $94, $94, $95, $95, $96, $97, $98
    ⋮
    392	.db $90, $91, $92, $92, $93, $93, $93, $94
    
    src/music-data.asm lines 388–392 at 1cc3c92 · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-21.

    Checked by a second AI model, 2026-10-21.

    In the claim ledger

  9. ^ abThe noise channel plays three drum sounds, all at constant volume 12 ($400C = $1C), a short beat at period index 3, a strong beat at period index 12, and a long beat at period index 3 with a longer length-counter load ($58 instead of $18).CodeXkeeper0/smb1
    How we know
    889	LDA #$1c                                     ; short beat data
    890	LDX #$03
    891	LDY #$18
    892	BNE PlayBeat
    ⋮
    894StrongBeat:
    895	LDA #$1c                                     ; strong beat data
    896	LDX #$0c
    897	LDY #$18
    898	BNE PlayBeat
    ⋮
    900LongBeat:
    901	LDA #$1c                                     ; long beat data
    902	LDX #$03
    ⋮
    
    src/music-engine.asm lines 888–913 at 1cc3c92 · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-21.

    Checked by a second AI model, 2026-10-21.

    In the claim ledger

  10. ^ abThe music driver has Super Mario Bros.' layout; a song entry sets a base into a note-length table, a length code's low 3 bits index it, notes index a table of big-endian 16-bit timer periods, and a square note starts with duty byte $82 and sweep byte $7F, the same register values Super Mario Bros. uses.Codealdonunez/zelda1-disassembly · Xkeeper0/smb1
    How we know
    786PrepPhrase:
    787    LDA SongTable-1, Y
    788    TAY
    789    LDA SongTable, Y
    790    STA NoteLengthTableBase
    
    src/Z_00.asm lines 786–790 at 50a1c86 · upstream ↗
    1087GetSongNoteLength:
    1088    AND #$07
    1089    CLC
    1090    ADC NoteLengthTableBase
    1091    TAY
    1092    LDA NoteLengthTable0, Y
    
    src/Z_00.asm lines 1087–1092 at 50a1c86 · upstream ↗
    1112; Big-endian 16-bit period values.
    ⋮
    1114NotePeriodTable:
    1115    .BYTE $00, $23, $00, $6A, $03, $27, $00, $97
    1116    .BYTE $00, $00, $02, $F9, $02, $CF, $02, $A6
    1117    .BYTE $02, $80, $02, $5C, $02, $3A, $02, $1A
    1118    .BYTE $01, $FC, $01, $DF, $01, $C4, $01, $AB
    
    src/Z_00.asm lines 1112–1118 at 50a1c86 · upstream ↗
    1136PrepareCustomSongEnvelope:
    1137    LDA SongEnvelopeSelector
    1138    LDA #$20
    1139    LDX #$82
    1140    LDY #$7F
    
    src/Z_00.asm lines 1136–1140 at 50a1c86 · upstream ↗
    949	LDX #$82                                     ; load contents of other sound regs for square 2
    950	LDY #$7f
    
    src/music-engine.asm lines 949–950 at 1cc3c92 · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-21.

    Checked by a second AI model, 2026-10-21.

    In the claim ledger

  11. ^ abThe engine's main loop waits on timer 0, set to tick every 2 ms; for each tick it adds the song's tempo byte to an 8-bit accumulator, and on a carry out it calls the routine APU_0BC0, unless a flag at audio RAM $0388 is set. That routine wasn't read; the structure suggests it is one step of the music, which would make the tempo set the step rate. The tempo starts at $36, which gives 500 × 54 / 256, about 105 carries a second.CodeSMWDisXrevised
    How we know
    56    MOV A,#$10
    57    MOV.W HW_TIMER0,A                         ; set timer0 freq to 2ms
    58    MOV A,#$36
    59    MOV.B MasterTempo+1,A                     ; set $51 to #$36
    60    MOV A,#$01
    61    MOV.W HW_SPCCONTROL,A                     ; start timer 0
    
    bank_0E.asm lines 56–62 at 30643c7 · upstream ↗
    63APU_Loop:
    64    MOV.W Y,HW_COUNTER0                       ; main loop
    65    BEQ APU_Loop                              ; wait for counter 0 increment;
    ⋮
    68    MUL YA
    69    CLRC
    ⋮
    83  + MOV.B A,MasterTempo+1
    84    POP Y
    85    MUL YA
    86    CLRC
    87    ADC.B A,ARam_49
    88    MOV.B ARam_49,A
    89    BCC APU_058D
    ⋮
    
    bank_0E.asm lines 63–95 at 30643c7 · upstream ↗
    1294    CALL NextVCmd46                           ; vcmd E2: tempo;
    ⋮
    1297    MOV.B MasterTempo+1,A
    1298    MOV.B MasterTempo,#$00
    
    bank_0E.asm lines 1294–1298 at 30643c7 · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-21.

    Revised after a check by a second AI model, 2026-10-21.

    In the claim ledger

  12. ^ abThe sound engine runs once a frame from the vertical blank handler. A note lasts ⌊(ℓ⋅s⋅T+f)/256⌋ frames, where ℓ is its length in 16ths, s the channel's note speed, T the song's 16-bit tempo, and f the channel's leftover fraction, which the low byte carries to the next note.Codepret/pokered
    How we know
    59	cp BANK(Audio1_UpdateMusic)
    60	jr nz, .checkForAudio2
    61.audio1
    62	call Audio1_UpdateMusic
    ⋮
    64.checkForAudio2
    
    home/vblank.asm lines 59–72 at af51989 · upstream ↗
    41	ld hl, wChannelNoteDelayCounters ; delay until next note
    ⋮
    44	cp 1 ; if the delay is 1, play next note
    45	jp z, Audio1_PlayNextNote
    46	dec a ; otherwise, decrease the delay timer
    
    audio/engine_1.asm lines 39–47 at af51989 · upstream ↗
    690Audio1_note_length:
    691	ld a, d
    ⋮
    696	ld e, a  ; store note length (in 16ths)
    ⋮
    698	ld hl, wChannelNoteSpeeds
    ⋮
    702	call Audio1_MultiplyAdd
    ⋮
    706	ld a, [wMusicTempo]
    ⋮
    709	ld e, a
    ⋮
    720	ld e, a
    ⋮
    722	ld a, l ; a = note_length * note_speed
    ⋮
    724	ld hl, wChannelNoteDelayCountersFractionalPart
    ⋮
    727	call Audio1_MultiplyAdd
    ⋮
    729	ld d, h ; de = note_delay_frac_part + (note_length * note_speed * tempo)
    ⋮
    
    audio/engine_1.asm lines 690–737 at af51989 · upstream ↗

    Checked against the evidence by its author, an AI model, 2026-10-21.

    Checked by a second AI model, 2026-10-21.

    In the claim ledger

  13. ^A pulse channel's frequency is f=fCPU/(16(t+1)) for an 11-bit timer period t, with fCPU = 1.789773 MHz on NTSC; periods below 8 silence the channel.WikiNESdev Wiki, “APU Pulse”
    How we know
    fpulse = fCPU/(16*(t+1)) (where fCPU is 1.789773 MHz for NTSC … A period of t < 8, either set explicitly or via a sweep period update, silences the corresponding pulse channel.
    Pulse channel output to mixer · archived copy ↗

    Checked against the evidence by its author, an AI model, 2026-10-21.

    Checked by a second AI model, 2026-10-21.

    In the claim ledger

  14. ^The Game Boy has four sound channels, each specialized, with two pulse channels with four fixed duty settings, a wave channel that plays a user-supplied wave, and a noise channel.WikiPan Docs, “Pan Docs: Audio Overview”
    How we know
    Channels 1 and 2, the “pulse channels”, produce pulse width modulated waves with 4 fixed pulse width settings. Channel 3, the “wave” channel, produces arbitrary user-supplied waves. Channel 4 is the “noise” channel, producing a pseudo-random wave.
    Architecture · archived copy ↗

    Checked against the evidence by its author, an AI model, 2026-10-21.

    Checked by a second AI model, 2026-10-21.

    In the claim ledger

Sources

Code

Secondary