From 495d6b0f1bfca3b5dd1d389ba24f4d1399f7d1fd Mon Sep 17 00:00:00 2001 From: Catobat <69204835+Catobat@users.noreply.github.com> Date: Sun, 14 Jun 2026 16:05:47 +0200 Subject: [PATCH] Expand documentation of audio engine --- code/audio.s | 439 +++++++++++++++++++++++++----------------- include/musicMacros.s | 27 ++- include/wram.s | 60 ++++-- 3 files changed, 317 insertions(+), 209 deletions(-) diff --git a/code/audio.s b/code/audio.s index f2b64941..f627796f 100644 --- a/code/audio.s +++ b/code/audio.s @@ -51,7 +51,7 @@ initSound: ld (wSoundFadeDirection),a ld (wSoundFadeCounter),a ld (wSoundDisabled),a - ld (wc023),a + ld (wMusicMuted),a ld a,$8f ld ($ff00+R_NR52),a ld a,$77 @@ -87,14 +87,14 @@ initSound: ;; +; Updates wMusicVolume and wMusicMuted and silences channels 0 and 1 ; @param a Volume (0-3) -; updateMusicVolume: push bc push de push hl push af - call @updateSquareChannelVolumes + call silenceSquareMusicChannels pop af ld (wMusicVolume),a @@ -106,14 +106,15 @@ updateMusicVolume: + ld a,$00 ++ - ld (wc023),a + ld (wMusicMuted),a pop hl pop de pop bc ret ;; -@updateSquareChannelVolumes: +; Silences channels 0 and 1 if enabled +silenceSquareMusicChannels: ; Update square 1's volume ld a,$00 ld (wSoundChannel),a @@ -125,7 +126,7 @@ updateMusicVolume: ld a,(hl) cp $00 jr z,+ - call updateChannelStuff + call silencePlayedSound + ; Update square 2's volume ld a,$01 @@ -138,7 +139,7 @@ updateMusicVolume: ld a,(hl) cp $00 jr z,+ - call updateChannelStuff + call silencePlayedSound + ret @@ -155,11 +156,11 @@ stopSound: ret ;; -func_39_40b9: +silenceAllChannels: ld a,$00 - ld (wSoundChannel),a - call updateChannelStuff + call silencePlayedSound ld a,(wSoundChannel) inc a cp $08 @@ -299,24 +300,25 @@ updateSound: add hl,de ld a,(hl) cp $00 - jr nz,+ + jr nz,@continueSound call doNextChannelCommand jr @nextChannel -+ - call func_39_41c2 + +@continueSound: + call continuePlayingSound @nextChannel: ld a,(wSoundChannel) inc a cp $08 jr nz,@channelLoop - ld a,(wc023) + ld a,(wMusicMuted) cp $01 jr nz,@ret ld a,$02 - ld (wc023),a + ld (wMusicMuted),a @ret: pop hl @@ -325,7 +327,9 @@ updateSound: ret ;; -func_39_41c2: +; Keep playing the current sound +continuePlayingSound: + ; Decrement wait counter ld hl,wChannelWaitCounters ld a,(wSoundChannel) ld e,a @@ -334,11 +338,13 @@ func_39_41c2: ld a,(hl) dec a ld (hl),a + ; Return if noise channel ld a,(wSoundChannel) cp $06 jr nc,@ret - ld hl,wc039 + ; Return if channel uses length timer + ld hl,wChannelFrequencyModeAndLengthTimerEnabled ld a,(wSoundChannel) ld e,a ld d,$00 @@ -346,18 +352,21 @@ func_39_41c2: ld a,(hl) and $40 jr nz,@ret + ld a,(wSoundChannel) cp $05 jr nc,+ - call func_39_464c + call handleEnvelopes + - call func_39_41f3 + call updateSoundFrequencyAndPlay @ret: ret ;; -func_39_41f3: - ld hl,wc03f +; Copies the channel's frequency value from hSoundData3 to wSoundFrequencyL,H after applying sweep and vibrato +updateSoundFrequencyAndPlay: + ; Handle sweep + ld hl,wChannelSweep ld a,(wSoundChannel) ld e,a ld d,$00 @@ -365,7 +374,7 @@ func_39_41f3: ld a,(hl) ld c,a and $7f - jr z,label_39_024 + jr z,@handleVibrato ld a,c and $80 @@ -376,8 +385,9 @@ func_39_41f3: + ld d,$ff ++ + ; Unnecessary, could just do ld a,c like a few lines above push de - ld hl,wc03f + ld hl,wChannelSweep ld a,(wSoundChannel) ld e,a ld d,$00 @@ -407,27 +417,29 @@ func_39_41f3: ld a,h ld ($ff00+c),a inc c -label_39_024: - ld hl,wc045 +@handleVibrato: + ld hl,wChannelVibratoActive ld a,(wSoundChannel) ld e,a ld d,$00 add hl,de ld a,(hl) and $10 - jr nz,label_39_026 + jr nz,@useVibrato - ld hl,wc051 + ; Check vibrato wait counter + ld hl,wChannelVibratoCounters ld a,(wSoundChannel) ld e,a ld d,$00 add hl,de ld a,(hl) cp $00 - jr z,label_39_025 + jr z,@endVibratoWait + ; Still waiting, no vibrato applied yet dec a - ld hl,wc051 + ld hl,wChannelVibratoCounters push af ld a,(wSoundChannel) ld e,a @@ -436,11 +448,11 @@ label_39_024: pop af ld (hl),a ld hl,$0000 - jp func_42d1 + jp @updateSoundFrequencyWithOffset -label_39_025: +@endVibratoWait: ld a,$10 - ld hl,wc045 + ld hl,wChannelVibratoActive push af ld a,(wSoundChannel) ld e,a @@ -448,8 +460,9 @@ label_39_025: add hl,de pop af ld (hl),a + ; Unnecessary, this value is already known to be 0 ld a,$00 - ld hl,wc051 + ld hl,wChannelVibratoCounters push af ld a,(wSoundChannel) ld e,a @@ -457,18 +470,19 @@ label_39_025: add hl,de pop af ld (hl),a -label_39_026: - ld hl,wc051 +@useVibrato: + ld hl,wChannelVibratoCounters ld a,(wSoundChannel) ld e,a ld d,$00 add hl,de ld a,(hl) cp $08 - jr nz,label_39_027 + jr nz,@determineFrequencyOffset + ; Went past the end of vibratoOffsetTable, start over ld a,$00 - ld hl,wc051 + ld hl,wChannelVibratoCounters push af ld a,(wSoundChannel) ld e,a @@ -477,11 +491,13 @@ label_39_026: pop af ld (hl),a ld a,$00 -label_39_027: - ld hl,data_4b40 +@determineFrequencyOffset: + ; Get next raw offset (-2, -1, 0, 1 or 2) + ld hl,vibratoOffsetTable call readWordFromTable push hl - ld hl,wc051 + ; Increment index + ld hl,wChannelVibratoCounters ld a,(wSoundChannel) ld e,a ld d,$00 @@ -489,6 +505,7 @@ label_39_027: ld a,(hl) inc a ld (hl),a + ; Get vibrato intensity (0 if disabled for the channel) ld hl,wChannelVibratos ld a,(wSoundChannel) ld e,a @@ -497,15 +514,14 @@ label_39_027: ld a,(hl) and $0f pop hl - call func_39_4a10 - -;; -func_42d1: + ; Get final offset by multiplying raw offset with intensity + call multiplyHlByA +@updateSoundFrequencyWithOffset: ld a,(wSoundChannel) sla a ld b,a ld a,b - add $f2 + add $f .fail @@ -240,7 +240,7 @@ .db $d0 | \1 .endm -; e0-e7: set envelopes +; e0-e7: set envelopes (for channels 0-3) .macro env .if \1 > $7 .fail @@ -251,8 +251,7 @@ ; e8-ef: same as e0-e7 -; f0: unknown -; Sometimes sets wc039 +; f0: does various things for channels 0-5, sets volume and envelope for channel 7, see audio.s for details .macro cmdf0 .db $f0 \1 .endm @@ -268,7 +267,7 @@ .db $f3 .endm -; f4-f5: duplicates of ff? +; f4-f5: duplicates of ff .macro cmdf4 .db $f4 .endm @@ -276,28 +275,28 @@ .db $f5 .endm -; f6: sets wChannelDutyCycles +; f6: sets wChannelDutyCycles (for channels 0-5) .macro duty .db $f6 \1 .endm -; f7: duplicate of ff? +; f7: duplicate of ff -; f8: sets wc03f (for channels 0-5) +; f8: sets sweep (for channels 0-5) .macro cmdf8 .db $f8 \1 .endm -; f9: sets wChannelVibratos. +; f9: sets wChannelVibratos (for channels 0-5) ; Upper nibble is time to wait until vibrato starts. ; Lower nibble is intensity of vibrato. .macro vibrato .db $f9 \1 .endm -; fa-fc: duplicates of ff? +; fa-fc: duplicates of ff -; fd: sets wc033 +; fd: sets wChannelPitchShift (for channels 0-5) ; Shifts pitch .macro cmdfd .db $fd \1 @@ -309,7 +308,7 @@ .dw \1 .endm -; ff: might mute the channel? +; ff: disables the channel .macro cmdff .db $ff .endm diff --git a/include/wram.s b/include/wram.s index d7ac8fbc..e9e9b44c 100644 --- a/include/wram.s +++ b/include/wram.s @@ -44,16 +44,16 @@ wSoundDisabled: ; $c01b ; All sound processing is disabled when this is nonzero db -wc01c: ; $c01c +wChannel7TriggerOnNextSound: ; $c01c +; Audio command $f0 sets this to $80, which is then written to NR44 on the next standard command db wSoundCmd: ; $c01d db wSoundCmdEnvelope: ; $c01e -; This value goes straight to NR12/NR22 -; In some situations it is also used to mark whether to reset / use the counter -; for the channel (NRx4) +; This value goes straight to NR12/NR22 in updateSquareChannelVolume +; When that function returns, this value is updated with bits 6 and 7 that can go to NR14/NR24 db wSoundFrequencyL: ; $c01f @@ -67,8 +67,11 @@ wMusicVolume: ; $c022 ; Basically the same as hMusicVolume, except this is only used in the music routines. db -wc023: ; $c023 -; Relates to muting channel 3 when wMusicVolume is set to 0? +wMusicMuted: ; $c023 +; When 2, prevents channel 4 from updating related hardware registers +; 0: Music is not muted (equivalent to wMusicVolume != 0) +; 1: Music has just been muted (updateSound function has not completed since then) +; 2: Music has been muted for some time (muted for the entire duration of the most recent updateSound call) db wSoundVolume: ; $c024 @@ -76,42 +79,62 @@ wSoundVolume: ; $c024 ; Bits 0-2: left speaker, 4-6: right speaker (unless I mixed them up) db - -wc025: ; $c025 +wWaveChannelVolume: ; $c025 +; This value goes straight to NR32 if the corresponding channel is active +; Only used for channels 4 and 5 dsb 8 -wc02d: ; $c02d -; This doesn't apply to channels 6 and 7? +wChannelIsPlayingRest: ; $c02d +; Only used for channels 4 and 5 dsb 6 wChannelPitchShift: ; $c033 ; An offset for wSoundFrequencyL,H dsb 6 -wc039: ; $c039 -; c039 might be related to the "counter" bit (NRx4) +wChannelFrequencyModeAndLengthTimerEnabled: ; $c039 +; This does two things: +; If not 0, the standard audio command is not treated as an index into soundFrequencyTable, +; but as the high byte for a frequency value, and the next byte is treated as the lower byte, followed by the length +; For square channels, if bit 6 is set, then that bit also gets set on updates to wSoundCmdEnvelope +; which enables the length timer for the channel (the initial length timer comes from wChannelDutyCycles) dsb 6 -wc03f: ; $c03f -; c03f might be related to sweep +wChannelSweep: ; $c03f +; Offset that keeps shifting the frequency value of a sound over time dsb 6 -wc045: ; $c045 +wChannelVibratoActive: ; $c045 +; When bit 4 is set, the vibrato wait check is skipped and vibrato applied dsb 6 wChannelVibratos: ; $c04b +; Upper nibble is half the number of ticks until vibrato starts +; Lower nibble is the vibrato intensity dsb 6 -wc051: ; $c051 +wChannelVibratoCounters: ; $c051 +; Serves two purposes depending on wChannelVibratoActive: +; Initially for every sound, this is the amount of time left until the vibrato becomes active +; Once the wait is over, this becomes the index into vibratoOffsetTable and is incremented after every use dsb 6 wChannelDutyCycles: ; $c057 +; Written straight to NR11/NR21 for channels 0/1 and 2/3 +; Contains waveform index for channels 4 and 5 dsb 6 -wc05d: ; $c05d +wChannelEnvelopeStates: ; $c05d +; Keeps track of the current envelope state for the current sound +; 0: Initializing envelopes +; 1: Sound playing with start envelope +; 2: Sound playing without envelope (or other type of wait) +; 3: Sound playing with end envelope (envelope could already be finished) dsb 4 -wc061: ; $c061 +wChannelEnvelopeWaitCounters: ; $c061 dsb 4 wChannelEnvelopes: ; $c065 +; Envelope for making sounds fade in dsb 4 wChannelEnvelopes2: ; $c069 +; Envelope for making sounds fade out dsb 4 wChannelsEnabled: ; $c06d @@ -119,6 +142,7 @@ wChannelsEnabled: ; $c06d wChannelWaitCounters: ; $c075 dsb 8 wChannelVolumes: ; $c07d +; Never read for wave channels dsb 8 ; $c085-$c09f unused?