pokered/audio/engine_2.asm

1791 lines
34 KiB
NASM
Raw Normal View History

2014-01-07 03:34:14 +00:00
; The second of three duplicated sound engines.
; This copy has a few differences relating to battle sound effects
; and the low health alarm that plays in battle
2014-01-07 03:34:14 +00:00
2016-06-12 00:24:04 +00:00
Audio2_UpdateMusic::
ld c, CHAN1
2014-01-07 03:34:14 +00:00
.loop
ld b, 0
2015-08-09 05:32:44 +00:00
ld hl, wChannelSoundIDs
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, [hl]
and a
jr z, .nextChannel
ld a, c
cp CHAN5
2014-01-07 03:34:14 +00:00
jr nc, .applyAffects ; if sfx channel
2015-08-09 05:32:44 +00:00
ld a, [wMuteAudioAndPauseMusic]
2014-01-07 03:34:14 +00:00
and a
jr z, .applyAffects
2024-09-24 03:51:44 +00:00
bit BIT_MUTE_AUDIO, a
2014-01-07 03:34:14 +00:00
jr nz, .nextChannel
2024-09-24 03:51:44 +00:00
set BIT_MUTE_AUDIO, a
2015-08-09 05:32:44 +00:00
ld [wMuteAudioAndPauseMusic], a
xor a ; disable all channels' output
ldh [rNR51], a
ldh [rNR30], a
2014-01-07 03:34:14 +00:00
ld a, $80
ldh [rNR30], a
2014-01-07 03:34:14 +00:00
jr .nextChannel
.applyAffects
call Audio2_ApplyMusicAffects
2014-01-07 03:34:14 +00:00
.nextChannel
ld a, c
inc c ; inc channel number
cp CHAN8
2014-01-07 03:34:14 +00:00
jr nz, .loop
ret
; this routine checks flags for music effects currently applied
; to the channel and calls certain functions based on flags.
2016-06-12 00:24:04 +00:00
Audio2_ApplyMusicAffects:
2014-01-07 03:34:14 +00:00
ld b, $0
2015-08-09 05:32:44 +00:00
ld hl, wChannelNoteDelayCounters ; delay until next note
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, [hl]
2020-07-16 17:25:02 +00:00
cp 1 ; if the delay is 1, play next note
jp z, Audio2_PlayNextNote
2014-01-07 03:34:14 +00:00
dec a ; otherwise, decrease the delay timer
ld [hl], a
ld a, c
cp CHAN5
2014-01-07 03:34:14 +00:00
jr nc, .startChecks ; if a sfx channel
ld hl, wChannelSoundIDs + CHAN5
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, [hl]
and a
jr z, .startChecks
ret
.startChecks
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags1
2014-01-07 03:34:14 +00:00
add hl, bc
bit BIT_ROTATE_DUTY_CYCLE, [hl]
2014-01-07 03:34:14 +00:00
jr z, .checkForExecuteMusic
call Audio2_ApplyDutyCyclePattern
2014-01-07 03:34:14 +00:00
.checkForExecuteMusic
ld b, 0
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags2
2014-01-07 03:34:14 +00:00
add hl, bc
bit BIT_EXECUTE_MUSIC, [hl]
jr nz, .checkForPitchSlide
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags1
2014-01-07 03:34:14 +00:00
add hl, bc
bit BIT_NOISE_OR_SFX, [hl]
jr nz, .skipPitchSlideVibrato
.checkForPitchSlide
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags1
2014-01-07 03:34:14 +00:00
add hl, bc
bit BIT_PITCH_SLIDE_ON, [hl]
2014-01-07 03:34:14 +00:00
jr z, .checkVibratoDelay
jp Audio2_ApplyPitchSlide
2014-01-07 03:34:14 +00:00
.checkVibratoDelay
ld hl, wChannelVibratoDelayCounters
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, [hl]
and a ; check if delay is over
jr z, .checkForVibrato
dec [hl] ; otherwise, dec delay
.skipPitchSlideVibrato
2014-01-07 03:34:14 +00:00
ret
.checkForVibrato
ld hl, wChannelVibratoExtents
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, [hl]
and a
jr nz, .vibrato
ret ; no vibrato
.vibrato
ld d, a
2015-08-09 05:32:44 +00:00
ld hl, wChannelVibratoRates
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, [hl]
and $f
and a
jr z, .applyVibrato
dec [hl] ; decrement counter
2014-01-07 03:34:14 +00:00
ret
.applyVibrato
2014-01-07 03:34:14 +00:00
ld a, [hl]
swap [hl]
or [hl]
ld [hl], a ; reload the counter
2015-08-09 05:32:44 +00:00
ld hl, wChannelFrequencyLowBytes
2014-01-07 03:34:14 +00:00
add hl, bc
ld e, [hl] ; get note pitch
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags1
2014-01-07 03:34:14 +00:00
add hl, bc
; This is the only code that sets/resets the vibrato direction bit, so it
; continuously alternates which path it takes.
bit BIT_VIBRATO_DIRECTION, [hl]
jr z, .unset
res BIT_VIBRATO_DIRECTION, [hl]
2014-01-07 03:34:14 +00:00
ld a, d
and $f
ld d, a
ld a, e
sub d
jr nc, .noCarry
ld a, 0
2014-01-07 03:34:14 +00:00
.noCarry
jr .done
.unset
set BIT_VIBRATO_DIRECTION, [hl]
2014-01-07 03:34:14 +00:00
ld a, d
and $f0
swap a
add e
jr nc, .done
ld a, $ff
.done
ld d, a
ld b, REG_FREQUENCY_LO
call Audio2_GetRegisterPointer
2014-01-07 03:34:14 +00:00
ld [hl], d
ret
; this routine executes all music commands that take up no time,
; like tempo changes, duty cycle changes etc. and doesn't return
2014-01-07 03:34:14 +00:00
; until the first note is reached
2016-06-12 00:24:04 +00:00
Audio2_PlayNextNote:
; reload the vibrato delay counter
2015-08-09 05:32:44 +00:00
ld hl, wChannelVibratoDelayCounterReloadValues
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, [hl]
2015-08-09 05:32:44 +00:00
ld hl, wChannelVibratoDelayCounters
2014-01-07 03:34:14 +00:00
add hl, bc
ld [hl], a
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags1
2014-01-07 03:34:14 +00:00
add hl, bc
res BIT_PITCH_SLIDE_ON, [hl]
res BIT_PITCH_SLIDE_DECREASING, [hl]
; --- this section is only present in this copy of the sound engine
2014-01-07 03:34:14 +00:00
ld a, c
cp CHAN5
2014-01-07 03:34:14 +00:00
jr nz, .beginChecks
2024-09-24 03:51:44 +00:00
ld a, [wLowHealthAlarm]
bit BIT_LOW_HEALTH_ALARM, a
2014-01-07 03:34:14 +00:00
ret nz
.beginChecks
; ---
call Audio2_sound_ret
2014-01-07 03:34:14 +00:00
ret
Audio2_sound_ret:
call Audio2_GetNextMusicByte
2014-01-07 03:34:14 +00:00
ld d, a
2020-07-16 17:25:02 +00:00
cp sound_ret_cmd
jp nz, Audio2_sound_call
ld b, 0
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags1
2014-01-07 03:34:14 +00:00
add hl, bc
bit BIT_SOUND_CALL, [hl]
2014-01-07 03:34:14 +00:00
jr nz, .returnFromCall
ld a, c
cp CHAN4
2014-01-07 03:34:14 +00:00
jr nc, .noiseOrSfxChannel
jr .disableChannelOutput
2014-01-07 03:34:14 +00:00
.noiseOrSfxChannel
res BIT_NOISE_OR_SFX, [hl]
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags2
2014-01-07 03:34:14 +00:00
add hl, bc
res BIT_EXECUTE_MUSIC, [hl]
cp CHAN7
jr nz, .skipSfxChannel3
; restart hardware channel 3 (wave channel) output
2014-01-07 03:34:14 +00:00
ld a, $0
ldh [rNR30], a
2014-01-07 03:34:14 +00:00
ld a, $80
ldh [rNR30], a
.skipSfxChannel3
jr nz, .dontDisable
2015-08-09 05:32:44 +00:00
ld a, [wDisableChannelOutputWhenSfxEnds]
2014-01-07 03:34:14 +00:00
and a
jr z, .dontDisable
2014-01-07 03:34:14 +00:00
xor a
2015-08-09 05:32:44 +00:00
ld [wDisableChannelOutputWhenSfxEnds], a
jr .disableChannelOutput
.dontDisable
jr .afterDisable
2014-01-07 03:34:14 +00:00
.returnFromCall
2024-09-24 03:51:44 +00:00
res BIT_SOUND_CALL, [hl]
2014-01-07 03:34:14 +00:00
ld d, $0
ld a, c
add a
ld e, a
2015-08-09 05:32:44 +00:00
ld hl, wChannelCommandPointers
2014-01-07 03:34:14 +00:00
add hl, de
push hl ; store current channel address
2015-08-09 05:32:44 +00:00
ld hl, wChannelReturnAddresses
2014-01-07 03:34:14 +00:00
add hl, de
ld e, l
ld d, h
pop hl
ld a, [de]
ld [hli], a
inc de
ld a, [de]
ld [hl], a ; loads channel address to return to
jp Audio2_sound_ret
.disableChannelOutput
ld hl, Audio2_HWChannelDisableMasks
2014-01-07 03:34:14 +00:00
add hl, bc
ldh a, [rNR51]
2014-01-07 03:34:14 +00:00
and [hl]
ldh [rNR51], a
.afterDisable
ld a, [wChannelSoundIDs + CHAN5]
cp CRY_SFX_START
jr nc, .maybeCry
jr .skipCry
.maybeCry
ld a, [wChannelSoundIDs + CHAN5]
cp CRY_SFX_END
jr z, .skipCry
jr c, .cry
jr .skipCry
.cry
2014-01-07 03:34:14 +00:00
ld a, c
cp CHAN5
jr z, .skipRewind
call Audio2_GoBackOneCommandIfCry
2014-01-07 03:34:14 +00:00
ret c
.skipRewind
2015-08-09 05:32:44 +00:00
ld a, [wSavedVolume]
ldh [rNR50], a
2014-01-07 03:34:14 +00:00
xor a
2015-08-09 05:32:44 +00:00
ld [wSavedVolume], a
.skipCry
2015-08-09 05:32:44 +00:00
ld hl, wChannelSoundIDs
2014-01-07 03:34:14 +00:00
add hl, bc
ld [hl], b
ret
Audio2_sound_call:
2020-07-16 17:25:02 +00:00
cp sound_call_cmd
jp nz, Audio2_sound_loop
call Audio2_GetNextMusicByte
2014-01-07 03:34:14 +00:00
push af
call Audio2_GetNextMusicByte
2014-01-07 03:34:14 +00:00
ld d, a
pop af
ld e, a
push de ; store pointer
ld d, $0
ld a, c
add a
ld e, a
2015-08-09 05:32:44 +00:00
ld hl, wChannelCommandPointers
2014-01-07 03:34:14 +00:00
add hl, de
push hl
2015-08-09 05:32:44 +00:00
ld hl, wChannelReturnAddresses
2014-01-07 03:34:14 +00:00
add hl, de
ld e, l
ld d, h
pop hl
ld a, [hli]
ld [de], a
inc de
ld a, [hld]
ld [de], a ; copy current channel address
pop de
ld [hl], e
inc hl
ld [hl], d ; overwrite current address with pointer
ld b, $0
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags1
2014-01-07 03:34:14 +00:00
add hl, bc
set BIT_SOUND_CALL, [hl] ; set the call flag
jp Audio2_sound_ret
2014-01-07 03:34:14 +00:00
Audio2_sound_loop:
2020-07-16 17:25:02 +00:00
cp sound_loop_cmd
jp nz, Audio2_note_type
call Audio2_GetNextMusicByte
2014-01-07 03:34:14 +00:00
ld e, a
and a
jr z, .infiniteLoop
ld b, 0
2015-08-09 05:32:44 +00:00
ld hl, wChannelLoopCounters
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, [hl]
cp e
jr nz, .loopAgain
ld a, $1 ; if no more loops to make,
ld [hl], a
call Audio2_GetNextMusicByte ; skip pointer
call Audio2_GetNextMusicByte
jp Audio2_sound_ret
2014-01-07 03:34:14 +00:00
.loopAgain ; inc loop count
inc a
ld [hl], a
; fall through
.infiniteLoop ; overwrite current address with pointer
call Audio2_GetNextMusicByte
2014-01-07 03:34:14 +00:00
push af
call Audio2_GetNextMusicByte
2014-01-07 03:34:14 +00:00
ld b, a
ld d, $0
ld a, c
add a
ld e, a
2015-08-09 05:32:44 +00:00
ld hl, wChannelCommandPointers
2014-01-07 03:34:14 +00:00
add hl, de
pop af
ld [hli], a
ld [hl], b
jp Audio2_sound_ret
2014-01-07 03:34:14 +00:00
Audio2_note_type:
2014-01-07 03:34:14 +00:00
and $f0
2020-07-16 17:25:02 +00:00
cp note_type_cmd
jp nz, Audio2_toggle_perfect_pitch
ld a, d
2014-01-07 03:34:14 +00:00
and $f
ld b, $0
2015-08-09 05:32:44 +00:00
ld hl, wChannelNoteSpeeds
2014-01-07 03:34:14 +00:00
add hl, bc
ld [hl], a ; store low nibble as speed
ld a, c
cp CHAN4
2014-01-07 03:34:14 +00:00
jr z, .noiseChannel ; noise channel has 0 params
call Audio2_GetNextMusicByte
2014-01-07 03:34:14 +00:00
ld d, a
ld a, c
cp CHAN3
2014-01-07 03:34:14 +00:00
jr z, .musicChannel3
cp CHAN7
jr nz, .skipChannel3
2015-08-09 05:32:44 +00:00
ld hl, wSfxWaveInstrument
jr .channel3
2014-01-07 03:34:14 +00:00
.musicChannel3
2015-08-09 05:32:44 +00:00
ld hl, wMusicWaveInstrument
.channel3
2014-01-07 03:34:14 +00:00
ld a, d
and $f
ld [hl], a ; store low nibble of param as wave instrument
2014-01-07 03:34:14 +00:00
ld a, d
and $30
sla a
ld d, a
; fall through
; if channel 3, store high nibble as volume
; else, store volume (high nibble) and fade (low nibble)
.skipChannel3
ld b, 0
2015-08-09 05:32:44 +00:00
ld hl, wChannelVolumes
2014-01-07 03:34:14 +00:00
add hl, bc
ld [hl], d
.noiseChannel
jp Audio2_sound_ret
2014-01-07 03:34:14 +00:00
Audio2_toggle_perfect_pitch:
2014-01-07 03:34:14 +00:00
ld a, d
2020-07-16 17:25:02 +00:00
cp toggle_perfect_pitch_cmd
jr nz, Audio2_vibrato
ld b, 0
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags1
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, [hl]
2024-09-24 03:51:44 +00:00
xor 1 << BIT_PERFECT_PITCH
ld [hl], a
jp Audio2_sound_ret
2014-01-07 03:34:14 +00:00
2016-06-12 00:24:04 +00:00
Audio2_vibrato:
2020-07-16 17:25:02 +00:00
cp vibrato_cmd
jr nz, Audio2_pitch_slide
call Audio2_GetNextMusicByte
ld b, 0
2015-08-09 05:32:44 +00:00
ld hl, wChannelVibratoDelayCounters
2014-01-07 03:34:14 +00:00
add hl, bc
2014-06-09 20:58:02 +00:00
ld [hl], a ; store delay
2015-08-09 05:32:44 +00:00
ld hl, wChannelVibratoDelayCounterReloadValues
2014-01-07 03:34:14 +00:00
add hl, bc
2014-06-09 20:58:02 +00:00
ld [hl], a ; store delay
call Audio2_GetNextMusicByte
2014-01-07 03:34:14 +00:00
ld d, a
; The high nybble of the command byte is the extent of the vibrato.
; Let n be the extent.
; The upper nybble of the channel's byte in the wChannelVibratoExtents
; array will store the extent above the note: (n / 2) + (n % 2).
; The lower nybble will store the extent below the note: (n / 2).
; These two values add to the total extent, n.
2014-01-07 03:34:14 +00:00
and $f0
swap a
ld b, 0
2015-08-09 05:32:44 +00:00
ld hl, wChannelVibratoExtents
2014-01-07 03:34:14 +00:00
add hl, bc
srl a
ld e, a
adc b
swap a
or e
ld [hl], a
; The low nybble of the command byte is the rate of the vibrato.
; The high and low nybbles of the channel's byte in the wChannelVibratoRates
; array are both initialised to this value because the high nybble is the
; counter reload value and the low nybble is the counter itself, which should
; start at its value upon reload.
2014-01-07 03:34:14 +00:00
ld a, d
and $f
ld d, a
2015-08-09 05:32:44 +00:00
ld hl, wChannelVibratoRates
2014-01-07 03:34:14 +00:00
add hl, bc
swap a
or d
ld [hl], a
2014-01-07 03:34:14 +00:00
jp Audio2_sound_ret
Audio2_pitch_slide:
2020-07-16 17:25:02 +00:00
cp pitch_slide_cmd
jr nz, Audio2_duty_cycle
call Audio2_GetNextMusicByte
ld b, 0
ld hl, wChannelPitchSlideLengthModifiers
2014-01-07 03:34:14 +00:00
add hl, bc
ld [hl], a
call Audio2_GetNextMusicByte
2014-01-07 03:34:14 +00:00
ld d, a
and $f0
swap a
ld b, a
ld a, d
and $f
call Audio2_CalculateFrequency
ld b, 0
ld hl, wChannelPitchSlideTargetFrequencyHighBytes
2014-01-07 03:34:14 +00:00
add hl, bc
ld [hl], d
ld hl, wChannelPitchSlideTargetFrequencyLowBytes
2014-01-07 03:34:14 +00:00
add hl, bc
ld [hl], e
ld b, 0
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags1
2014-01-07 03:34:14 +00:00
add hl, bc
set BIT_PITCH_SLIDE_ON, [hl]
call Audio2_GetNextMusicByte
2014-01-07 03:34:14 +00:00
ld d, a
jp Audio2_note_length
2014-01-07 03:34:14 +00:00
Audio2_duty_cycle:
2020-07-16 17:25:02 +00:00
cp duty_cycle_cmd
jr nz, Audio2_tempo
call Audio2_GetNextMusicByte
2014-01-07 03:34:14 +00:00
rrca
rrca
and $c0
ld b, 0
ld hl, wChannelDutyCycles
2014-01-07 03:34:14 +00:00
add hl, bc
ld [hl], a ; store duty cycle
jp Audio2_sound_ret
2014-01-07 03:34:14 +00:00
2016-06-12 00:24:04 +00:00
Audio2_tempo:
2020-07-16 17:25:02 +00:00
cp tempo_cmd
jr nz, Audio2_stereo_panning
ld a, c
cp CHAN5
2014-01-07 03:34:14 +00:00
jr nc, .sfxChannel
call Audio2_GetNextMusicByte
2015-08-09 05:32:44 +00:00
ld [wMusicTempo], a ; store first param
call Audio2_GetNextMusicByte
2015-08-09 05:32:44 +00:00
ld [wMusicTempo + 1], a ; store second param
2014-01-07 03:34:14 +00:00
xor a
2015-08-09 05:32:44 +00:00
ld [wChannelNoteDelayCountersFractionalPart], a ; clear RAM
ld [wChannelNoteDelayCountersFractionalPart + 1], a
ld [wChannelNoteDelayCountersFractionalPart + 2], a
ld [wChannelNoteDelayCountersFractionalPart + 3], a
2014-01-07 03:34:14 +00:00
jr .musicChannelDone
.sfxChannel
call Audio2_GetNextMusicByte
2015-08-09 05:32:44 +00:00
ld [wSfxTempo], a ; store first param
call Audio2_GetNextMusicByte
2015-08-09 05:32:44 +00:00
ld [wSfxTempo + 1], a ; store second param
2014-01-07 03:34:14 +00:00
xor a
2015-08-09 05:32:44 +00:00
ld [wChannelNoteDelayCountersFractionalPart + 4], a ; clear RAM
ld [wChannelNoteDelayCountersFractionalPart + 5], a
ld [wChannelNoteDelayCountersFractionalPart + 6], a
ld [wChannelNoteDelayCountersFractionalPart + 7], a
2014-01-07 03:34:14 +00:00
.musicChannelDone
jp Audio2_sound_ret
2014-01-07 03:34:14 +00:00
Audio2_stereo_panning:
2020-07-16 17:25:02 +00:00
cp stereo_panning_cmd
jr nz, Audio2_unknownmusic0xef
call Audio2_GetNextMusicByte
2015-08-09 05:32:44 +00:00
ld [wStereoPanning], a ; store panning
jp Audio2_sound_ret
2014-01-07 03:34:14 +00:00
; this appears to never be used
2016-06-12 00:24:04 +00:00
Audio2_unknownmusic0xef:
2020-07-16 17:25:02 +00:00
cp unknownmusic0xef_cmd
jr nz, Audio2_duty_cycle_pattern
call Audio2_GetNextMusicByte
2014-01-07 03:34:14 +00:00
push bc
2015-08-09 05:32:44 +00:00
call Audio2_PlaySound
2014-01-07 03:34:14 +00:00
pop bc
2015-08-09 05:32:44 +00:00
ld a, [wDisableChannelOutputWhenSfxEnds]
2014-01-07 03:34:14 +00:00
and a
jr nz, .skip
ld a, [wChannelSoundIDs + CHAN8]
2015-08-09 05:32:44 +00:00
ld [wDisableChannelOutputWhenSfxEnds], a
2014-01-07 03:34:14 +00:00
xor a
ld [wChannelSoundIDs + CHAN8], a
2014-01-07 03:34:14 +00:00
.skip
jp Audio2_sound_ret
2014-01-07 03:34:14 +00:00
Audio2_duty_cycle_pattern:
2020-07-16 17:25:02 +00:00
cp duty_cycle_pattern_cmd
jr nz, Audio2_volume
call Audio2_GetNextMusicByte
ld b, 0
ld hl, wChannelDutyCyclePatterns
2014-01-07 03:34:14 +00:00
add hl, bc
ld [hl], a ; store full pattern
and %11000000
ld hl, wChannelDutyCycles
2014-01-07 03:34:14 +00:00
add hl, bc
ld [hl], a ; store first duty cycle
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags1
2014-01-07 03:34:14 +00:00
add hl, bc
set BIT_ROTATE_DUTY_CYCLE, [hl]
jp Audio2_sound_ret
2014-01-07 03:34:14 +00:00
2016-06-12 00:24:04 +00:00
Audio2_volume:
2020-07-16 17:25:02 +00:00
cp volume_cmd
jr nz, Audio2_execute_music
call Audio2_GetNextMusicByte
ldh [rNR50], a ; store volume
jp Audio2_sound_ret
2014-01-07 03:34:14 +00:00
Audio2_execute_music:
2020-07-16 17:25:02 +00:00
cp execute_music_cmd
jr nz, Audio2_octave
ld b, $0
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags2
2014-01-07 03:34:14 +00:00
add hl, bc
set BIT_EXECUTE_MUSIC, [hl]
jp Audio2_sound_ret
2014-01-07 03:34:14 +00:00
2016-06-12 00:24:04 +00:00
Audio2_octave:
2014-01-07 03:34:14 +00:00
and $f0
2020-07-16 17:25:02 +00:00
cp octave_cmd
jr nz, Audio2_sfx_note
ld hl, wChannelOctaves
ld b, 0
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, d
and $f
ld [hl], a ; store low nibble as octave
jp Audio2_sound_ret
2014-01-07 03:34:14 +00:00
; sfx_note is either square_note or noise_note depending on the channel
Audio2_sfx_note:
2020-07-16 17:25:02 +00:00
cp sfx_note_cmd
jr nz, Audio2_pitch_sweep
2014-01-07 03:34:14 +00:00
ld a, c
cp CHAN4 ; is this a noise or sfx channel?
jr c, Audio2_pitch_sweep ; no
ld b, 0
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags2
2014-01-07 03:34:14 +00:00
add hl, bc
bit BIT_EXECUTE_MUSIC, [hl] ; is execute_music being used?
jr nz, Audio2_pitch_sweep ; yes
call Audio2_note_length
; This code seems to do the same thing as what Audio2_ApplyDutyCycleAndSoundLength
; does below.
2014-01-07 03:34:14 +00:00
ld d, a
ld b, 0
ld hl, wChannelDutyCycles
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, [hl]
or d
ld d, a
ld b, REG_DUTY_SOUND_LEN
call Audio2_GetRegisterPointer
2014-01-07 03:34:14 +00:00
ld [hl], d
call Audio2_GetNextMusicByte
2014-01-07 03:34:14 +00:00
ld d, a
ld b, REG_VOLUME_ENVELOPE
call Audio2_GetRegisterPointer
2014-01-07 03:34:14 +00:00
ld [hl], d
call Audio2_GetNextMusicByte
2014-01-07 03:34:14 +00:00
ld e, a
ld a, c
cp CHAN8
ld a, 0
jr z, .skip
; Channels 1 through 3 have 2 registers that control frequency, but the noise
; channel a single register (the polynomial counter) that controls frequency,
; so this command has one less byte on the noise channel.
2014-01-07 03:34:14 +00:00
push de
call Audio2_GetNextMusicByte
2014-01-07 03:34:14 +00:00
pop de
.skip
2014-01-07 03:34:14 +00:00
ld d, a
push de
call Audio2_ApplyDutyCycleAndSoundLength
call Audio2_EnableChannelOutput
2014-01-07 03:34:14 +00:00
pop de
call Audio2_ApplyWavePatternAndFrequency
2014-01-07 03:34:14 +00:00
ret
Audio2_pitch_sweep:
2014-01-07 03:34:14 +00:00
ld a, c
cp CHAN5
jr c, Audio2_note ; if not a sfx
2014-01-07 03:34:14 +00:00
ld a, d
2020-07-16 17:25:02 +00:00
cp pitch_sweep_cmd
jr nz, Audio2_note
2014-01-07 03:34:14 +00:00
ld b, $0
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags2
2014-01-07 03:34:14 +00:00
add hl, bc
bit BIT_EXECUTE_MUSIC, [hl]
jr nz, Audio2_note ; no
call Audio2_GetNextMusicByte
ldh [rNR10], a
jp Audio2_sound_ret
2014-01-07 03:34:14 +00:00
2016-06-12 00:24:04 +00:00
Audio2_note:
2014-01-07 03:34:14 +00:00
ld a, c
cp CHAN4
jr nz, Audio2_note_length ; if not noise channel
2014-01-07 03:34:14 +00:00
ld a, d
and $f0
2020-07-16 17:25:02 +00:00
cp drum_note_cmd
jr z, .drum_note
2020-07-16 17:25:02 +00:00
jr nc, Audio2_note_length
; this executes when on the noise channel and
2020-07-16 17:25:02 +00:00
; the command id is less than drum_note_cmd ($b0)
; in this case, the upper nybble is used as the noise instrument ($1-$a)
; and the lower nybble is the length minus 1 (0-15)
; however, this doesn't work for instrument #2 because the command id
; is captured by the noise_note command (command id $2x)
; this essentially acts like a drum_note command that is only 1 byte
; instead of 2 and can only be used with instruments 1 and 3 through 10
; this is unused by the game
2014-01-07 03:34:14 +00:00
swap a
ld b, a
ld a, d
and $f
ld d, a
ld a, b
push de
push bc
jr .playDnote
2014-01-07 03:34:14 +00:00
.drum_note
2014-01-07 03:34:14 +00:00
ld a, d
and $f
push af
push bc
call Audio2_GetNextMusicByte ; get drum_note instrument
.playDnote
2014-01-07 03:34:14 +00:00
ld d, a
2015-08-09 05:32:44 +00:00
ld a, [wDisableChannelOutputWhenSfxEnds]
2014-01-07 03:34:14 +00:00
and a
jr nz, .skipDnote
2014-01-07 03:34:14 +00:00
ld a, d
2015-08-09 05:32:44 +00:00
call Audio2_PlaySound
.skipDnote
2014-01-07 03:34:14 +00:00
pop bc
pop de
Audio2_note_length:
2014-01-07 03:34:14 +00:00
ld a, d
push af
and $f
inc a
ld b, 0
ld e, a ; store note length (in 16ths)
2014-01-07 03:34:14 +00:00
ld d, b
2015-08-09 05:32:44 +00:00
ld hl, wChannelNoteSpeeds
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, [hl]
ld l, b
call Audio2_MultiplyAdd
2014-01-07 03:34:14 +00:00
ld a, c
cp CHAN5
2014-01-07 03:34:14 +00:00
jr nc, .sfxChannel
2015-08-09 05:32:44 +00:00
ld a, [wMusicTempo]
2014-01-07 03:34:14 +00:00
ld d, a
2015-08-09 05:32:44 +00:00
ld a, [wMusicTempo + 1]
2014-01-07 03:34:14 +00:00
ld e, a
jr .skip
.sfxChannel
ld d, $1
ld e, $0
cp CHAN8
2014-01-07 03:34:14 +00:00
jr z, .skip ; if noise channel
call Audio2_SetSfxTempo
2015-08-09 05:32:44 +00:00
ld a, [wSfxTempo]
2014-01-07 03:34:14 +00:00
ld d, a
2015-08-09 05:32:44 +00:00
ld a, [wSfxTempo + 1]
2014-01-07 03:34:14 +00:00
ld e, a
.skip
ld a, l ; a = note_length * note_speed
ld b, 0
2015-08-09 05:32:44 +00:00
ld hl, wChannelNoteDelayCountersFractionalPart
2014-01-07 03:34:14 +00:00
add hl, bc
ld l, [hl]
call Audio2_MultiplyAdd
2014-01-07 03:34:14 +00:00
ld e, l
ld d, h ; de = note_delay_frac_part + (note_length * note_speed * tempo)
2015-08-09 05:32:44 +00:00
ld hl, wChannelNoteDelayCountersFractionalPart
2014-01-07 03:34:14 +00:00
add hl, bc
ld [hl], e
ld a, d
2015-08-09 05:32:44 +00:00
ld hl, wChannelNoteDelayCounters
2014-01-07 03:34:14 +00:00
add hl, bc
ld [hl], a
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags2
2014-01-07 03:34:14 +00:00
add hl, bc
bit BIT_EXECUTE_MUSIC, [hl]
jr nz, Audio2_note_pitch
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags1
2014-01-07 03:34:14 +00:00
add hl, bc
bit BIT_NOISE_OR_SFX, [hl]
jr z, Audio2_note_pitch
2014-01-07 03:34:14 +00:00
pop hl
ret
Audio2_note_pitch:
2014-01-07 03:34:14 +00:00
pop af
and $f0
2020-07-16 17:25:02 +00:00
cp rest_cmd
2014-01-07 03:34:14 +00:00
jr nz, .notRest
ld a, c
cp CHAN5
jr nc, .next
; If this isn't an SFX channel, try the corresponding SFX channel.
ld hl, wChannelSoundIDs + CHAN5
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, [hl]
and a
jr nz, .done
; fall through
.next
2014-01-07 03:34:14 +00:00
ld a, c
cp CHAN3
jr z, .channel3
cp CHAN7
jr nz, .notChannel3
.channel3
ld b, 0
ld hl, Audio2_HWChannelDisableMasks
2014-01-07 03:34:14 +00:00
add hl, bc
ldh a, [rNR51]
2014-01-07 03:34:14 +00:00
and [hl]
ldh [rNR51], a ; disable hardware channel 3's output
2014-01-07 03:34:14 +00:00
jr .done
.notChannel3
ld b, REG_VOLUME_ENVELOPE
call Audio2_GetRegisterPointer
ld a, $8 ; fade in sound
2014-01-07 03:34:14 +00:00
ld [hli], a
inc hl
ld a, $80 ; restart sound
2014-01-07 03:34:14 +00:00
ld [hl], a
.done
ret
.notRest
swap a
ld b, 0
2015-08-09 05:32:44 +00:00
ld hl, wChannelOctaves
2014-01-07 03:34:14 +00:00
add hl, bc
ld b, [hl]
call Audio2_CalculateFrequency
ld b, 0
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags1
2014-01-07 03:34:14 +00:00
add hl, bc
bit BIT_PITCH_SLIDE_ON, [hl]
jr z, .skipPitchSlide
call Audio2_InitPitchSlideVars
.skipPitchSlide
2014-01-07 03:34:14 +00:00
push de
ld a, c
cp CHAN5
jr nc, .sfxChannel ; if sfx channel
; If this isn't an SFX channel, try the corresponding SFX channel.
ld hl, wChannelSoundIDs + CHAN5
ld d, 0
2014-01-07 03:34:14 +00:00
ld e, a
add hl, de
ld a, [hl]
and a
jr nz, .noSfx
jr .sfxChannel
.noSfx
2014-01-07 03:34:14 +00:00
pop de
ret
.sfxChannel
ld b, 0
2015-08-09 05:32:44 +00:00
ld hl, wChannelVolumes
2014-01-07 03:34:14 +00:00
add hl, bc
ld d, [hl]
ld b, REG_VOLUME_ENVELOPE
call Audio2_GetRegisterPointer
2014-01-07 03:34:14 +00:00
ld [hl], d
call Audio2_ApplyDutyCycleAndSoundLength
call Audio2_EnableChannelOutput
2014-01-07 03:34:14 +00:00
pop de
ld b, $0
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags1
2014-01-07 03:34:14 +00:00
add hl, bc
bit BIT_PERFECT_PITCH, [hl] ; has toggle_perfect_pitch been used?
jr z, .skipFrequencyInc
inc e ; if yes, increment the frequency by 1
jr nc, .skipFrequencyInc ; Likely a mistake, because `inc` does not set flag C.
; Fortunately this does not seem to affect any notes that actually occur.
2014-01-07 03:34:14 +00:00
inc d
.skipFrequencyInc
2015-08-09 05:32:44 +00:00
ld hl, wChannelFrequencyLowBytes
2014-01-07 03:34:14 +00:00
add hl, bc
ld [hl], e
call Audio2_ApplyWavePatternAndFrequency
2014-01-07 03:34:14 +00:00
ret
Audio2_EnableChannelOutput:
ld b, 0
ld hl, Audio2_HWChannelEnableMasks
2014-01-07 03:34:14 +00:00
add hl, bc
ldh a, [rNR51]
or [hl] ; set this channel's bits
2014-01-07 03:34:14 +00:00
ld d, a
ld a, c
cp CHAN8
jr z, .noiseChannelOrNoSfx
cp CHAN5
2014-01-07 03:34:14 +00:00
jr nc, .skip ; if sfx channel
; If this isn't an SFX channel, try the corresponding SFX channel.
ld hl, wChannelSoundIDs + CHAN5
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, [hl]
and a
jr nz, .skip
.noiseChannelOrNoSfx
; If this is the SFX noise channel or a music channel whose corresponding
; SFX channel is off, apply stereo panning.
2015-08-09 05:32:44 +00:00
ld a, [wStereoPanning]
ld hl, Audio2_HWChannelEnableMasks
2014-01-07 03:34:14 +00:00
add hl, bc
and [hl]
ld d, a
ldh a, [rNR51]
ld hl, Audio2_HWChannelDisableMasks
2014-01-07 03:34:14 +00:00
add hl, bc
and [hl] ; reset this channel's output bits
or d ; set this channel's output bits that enabled in [wStereoPanning]
2014-01-07 03:34:14 +00:00
ld d, a
.skip
ld a, d
ldh [rNR51], a
2014-01-07 03:34:14 +00:00
ret
Audio2_ApplyDutyCycleAndSoundLength:
ld b, 0
ld hl, wChannelNoteDelayCounters ; use the note delay as sound length
2014-01-07 03:34:14 +00:00
add hl, bc
ld d, [hl]
ld a, c
cp CHAN3
jr z, .skipDuty ; if music channel 3
cp CHAN7
jr z, .skipDuty ; if sfx channel 3
; include duty cycle (except on channel 3 which doesn't have it)
2014-01-07 03:34:14 +00:00
ld a, d
and $3f
ld d, a
ld hl, wChannelDutyCycles
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, [hl]
or d
ld d, a
.skipDuty
ld b, REG_DUTY_SOUND_LEN
call Audio2_GetRegisterPointer
2014-01-07 03:34:14 +00:00
ld [hl], d
ret
Audio2_ApplyWavePatternAndFrequency:
2014-01-07 03:34:14 +00:00
ld a, c
cp CHAN3
2014-01-07 03:34:14 +00:00
jr z, .channel3
cp CHAN7
jr nz, .notChannel3
2014-01-07 03:34:14 +00:00
; fall through
.channel3
push de
2015-08-09 05:32:44 +00:00
ld de, wMusicWaveInstrument
cp CHAN3
jr z, .next
2015-08-09 05:32:44 +00:00
ld de, wSfxWaveInstrument
.next
2014-01-07 03:34:14 +00:00
ld a, [de]
add a
ld d, 0
2014-01-07 03:34:14 +00:00
ld e, a
ld hl, Audio2_WavePointers
2014-01-07 03:34:14 +00:00
add hl, de
ld e, [hl]
inc hl
ld d, [hl]
ld hl, rWave_0
2014-01-07 03:34:14 +00:00
ld b, $f
ld a, $0 ; stop hardware channel 3
ldh [rNR30], a
2014-01-07 03:34:14 +00:00
.loop
ld a, [de]
inc de
ld [hli], a
ld a, b
dec b
and a
jr nz, .loop
ld a, $80 ; start hardware channel 3
ldh [rNR30], a
2014-01-07 03:34:14 +00:00
pop de
.notChannel3
2014-01-07 03:34:14 +00:00
ld a, d
or $80 ; use counter mode (i.e. disable output when the counter reaches 0)
and $c7 ; zero the unused bits in the register
2014-01-07 03:34:14 +00:00
ld d, a
ld b, REG_FREQUENCY_LO
call Audio2_GetRegisterPointer
ld [hl], e ; store frequency low byte
2014-01-07 03:34:14 +00:00
inc hl
ld [hl], d ; store frequency high byte
; --- this section is only present in this copy of the sound engine
2014-01-07 03:34:14 +00:00
ld a, c
cp CHAN5
2014-01-07 03:34:14 +00:00
jr c, .musicChannel
call Audio2_ApplyFrequencyModifier
2014-01-07 03:34:14 +00:00
.musicChannel
; ---
2014-01-07 03:34:14 +00:00
ret
; --- this section is only present in this copy of the sound engine
; unused
Audio2_ResetCryModifiers:
2014-01-07 03:34:14 +00:00
ld a, c
cp CHAN5
jr nz, .skip
ld a, [wLowHealthAlarm]
2024-09-24 03:51:44 +00:00
bit BIT_LOW_HEALTH_ALARM, a
jr z, .skip
2014-01-07 03:34:14 +00:00
xor a
2015-08-09 05:32:44 +00:00
ld [wFrequencyModifier], a
2014-01-07 03:34:14 +00:00
ld a, $80
2015-08-09 05:32:44 +00:00
ld [wTempoModifier], a
.skip
2014-01-07 03:34:14 +00:00
ret
; ---
2014-01-07 03:34:14 +00:00
Audio2_SetSfxTempo:
call Audio2_IsCry
jr c, .skipCryCheck
call Audio2_IsBattleSFX
jr nc, .notCry
.skipCryCheck
ld d, 0
2015-08-09 05:32:44 +00:00
ld a, [wTempoModifier]
2014-01-07 03:34:14 +00:00
add $80
jr nc, .next
2014-01-07 03:34:14 +00:00
inc d
.next
2015-08-09 05:32:44 +00:00
ld [wSfxTempo + 1], a
2014-01-07 03:34:14 +00:00
ld a, d
2015-08-09 05:32:44 +00:00
ld [wSfxTempo], a
jr .done
.notCry
2014-01-07 03:34:14 +00:00
xor a
2015-08-09 05:32:44 +00:00
ld [wSfxTempo + 1], a
2014-01-07 03:34:14 +00:00
ld a, $1
2015-08-09 05:32:44 +00:00
ld [wSfxTempo], a
.done
2014-01-07 03:34:14 +00:00
ret
Audio2_ApplyFrequencyModifier:
call Audio2_IsCry
jr c, .skipCryCheck
call Audio2_IsBattleSFX
jr nc, .done
.skipCryCheck
; if playing a cry, add the cry's frequency modifier
2015-08-09 05:32:44 +00:00
ld a, [wFrequencyModifier]
2014-01-07 03:34:14 +00:00
add e
jr nc, .noCarry
2014-01-07 03:34:14 +00:00
inc d
.noCarry
2014-01-07 03:34:14 +00:00
dec hl
ld e, a
ld [hl], e
inc hl
ld [hl], d
.done
2014-01-07 03:34:14 +00:00
ret
Audio2_GoBackOneCommandIfCry:
call Audio2_IsCry
jr nc, .done
2015-08-09 05:32:44 +00:00
ld hl, wChannelCommandPointers
2014-01-07 03:34:14 +00:00
ld e, c
ld d, 0
2014-01-07 03:34:14 +00:00
sla e
rl d
add hl, de
ld a, [hl]
sub 1
2014-01-07 03:34:14 +00:00
ld [hl], a
inc hl
ld a, [hl]
sbc 0
2014-01-07 03:34:14 +00:00
ld [hl], a
scf
ret
.done
2014-01-07 03:34:14 +00:00
scf
ccf
ret
Audio2_IsCry:
; Returns whether the currently playing audio is a cry in carry.
ld a, [wChannelSoundIDs + CHAN5]
cp CRY_SFX_START
jr nc, .next
jr .no
.next
cp CRY_SFX_END
jr z, .no
jr c, .yes
.no
2014-01-07 03:34:14 +00:00
scf
ccf
ret
.yes
2014-01-07 03:34:14 +00:00
scf
ret
; --- this section is only present in this copy of the sound engine
Audio2_IsBattleSFX:
2022-07-15 10:46:22 +00:00
; Returns whether the currently playing audio is a battle sfx in carry.
ld a, [wChannelSoundIDs + CHAN8]
2014-01-07 03:34:14 +00:00
ld b, a
ld a, [wChannelSoundIDs + CHAN5]
2014-01-07 03:34:14 +00:00
or b
cp BATTLE_SFX_START
jr nc, .next
jr .no
.next
cp BATTLE_SFX_END
jr z, .no
jr c, .yes
.no
2014-01-07 03:34:14 +00:00
scf
ccf
ret
.yes
2014-01-07 03:34:14 +00:00
scf
ret
; ---
2014-01-07 03:34:14 +00:00
Audio2_ApplyPitchSlide:
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags1
2014-01-07 03:34:14 +00:00
add hl, bc
bit BIT_PITCH_SLIDE_DECREASING, [hl]
jp nz, .frequencyDecreasing
; frequency increasing
ld hl, wChannelPitchSlideCurrentFrequencyLowBytes
2014-01-07 03:34:14 +00:00
add hl, bc
ld e, [hl]
ld hl, wChannelPitchSlideCurrentFrequencyHighBytes
2014-01-07 03:34:14 +00:00
add hl, bc
ld d, [hl]
ld hl, wChannelPitchSlideFrequencySteps
2014-01-07 03:34:14 +00:00
add hl, bc
ld l, [hl]
ld h, b
add hl, de
ld d, h
ld e, l
ld hl, wChannelPitchSlideCurrentFrequencyFractionalPart
2014-01-07 03:34:14 +00:00
add hl, bc
push hl
ld hl, wChannelPitchSlideFrequencyStepsFractionalPart
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, [hl]
pop hl
add [hl]
ld [hl], a
ld a, 0
2014-01-07 03:34:14 +00:00
adc e
ld e, a
ld a, 0
2014-01-07 03:34:14 +00:00
adc d
ld d, a
ld hl, wChannelPitchSlideTargetFrequencyHighBytes
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, [hl]
cp d
jp c, .reachedTargetFrequency
jr nz, .applyUpdatedFrequency
ld hl, wChannelPitchSlideTargetFrequencyLowBytes
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, [hl]
cp e
jp c, .reachedTargetFrequency
jr .applyUpdatedFrequency
.frequencyDecreasing
ld hl, wChannelPitchSlideCurrentFrequencyLowBytes
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, [hl]
ld hl, wChannelPitchSlideCurrentFrequencyHighBytes
2014-01-07 03:34:14 +00:00
add hl, bc
ld d, [hl]
ld hl, wChannelPitchSlideFrequencySteps
2014-01-07 03:34:14 +00:00
add hl, bc
ld e, [hl]
sub e
ld e, a
ld a, d
sbc b
ld d, a
ld hl, wChannelPitchSlideFrequencyStepsFractionalPart
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, [hl]
add a
ld [hl], a
ld a, e
sbc b
ld e, a
ld a, d
sbc b
ld d, a
ld hl, wChannelPitchSlideTargetFrequencyHighBytes
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, d
cp [hl]
jr c, .reachedTargetFrequency
jr nz, .applyUpdatedFrequency
ld hl, wChannelPitchSlideTargetFrequencyLowBytes
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, e
cp [hl]
jr c, .reachedTargetFrequency
.applyUpdatedFrequency
ld hl, wChannelPitchSlideCurrentFrequencyLowBytes
2014-01-07 03:34:14 +00:00
add hl, bc
ld [hl], e
ld hl, wChannelPitchSlideCurrentFrequencyHighBytes
2014-01-07 03:34:14 +00:00
add hl, bc
ld [hl], d
ld b, REG_FREQUENCY_LO
call Audio2_GetRegisterPointer
2014-01-07 03:34:14 +00:00
ld a, e
ld [hli], a
ld [hl], d
ret
.reachedTargetFrequency
; Turn off pitch slide when the target frequency has been reached.
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags1
2014-01-07 03:34:14 +00:00
add hl, bc
res BIT_PITCH_SLIDE_ON, [hl]
res BIT_PITCH_SLIDE_DECREASING, [hl]
2014-01-07 03:34:14 +00:00
ret
Audio2_InitPitchSlideVars:
ld hl, wChannelPitchSlideCurrentFrequencyHighBytes
2014-01-07 03:34:14 +00:00
add hl, bc
ld [hl], d
ld hl, wChannelPitchSlideCurrentFrequencyLowBytes
2014-01-07 03:34:14 +00:00
add hl, bc
ld [hl], e
2015-08-09 05:32:44 +00:00
ld hl, wChannelNoteDelayCounters
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, [hl]
ld hl, wChannelPitchSlideLengthModifiers
2014-01-07 03:34:14 +00:00
add hl, bc
sub [hl]
jr nc, .next
ld a, 1
.next
2014-01-07 03:34:14 +00:00
ld [hl], a
ld hl, wChannelPitchSlideTargetFrequencyLowBytes
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, e
sub [hl]
ld e, a
ld a, d
sbc b
ld hl, wChannelPitchSlideTargetFrequencyHighBytes
2014-01-07 03:34:14 +00:00
add hl, bc
sub [hl]
jr c, .targetFrequencyGreater
2014-01-07 03:34:14 +00:00
ld d, a
ld b, 0
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags1
2014-01-07 03:34:14 +00:00
add hl, bc
set BIT_PITCH_SLIDE_DECREASING, [hl]
jr .next2
.targetFrequencyGreater
; If the target frequency is greater, subtract the current frequency from
; the target frequency to get the absolute difference.
ld hl, wChannelPitchSlideCurrentFrequencyHighBytes
2014-01-07 03:34:14 +00:00
add hl, bc
ld d, [hl]
ld hl, wChannelPitchSlideCurrentFrequencyLowBytes
2014-01-07 03:34:14 +00:00
add hl, bc
ld e, [hl]
ld hl, wChannelPitchSlideTargetFrequencyLowBytes
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, [hl]
sub e
ld e, a
; Bug. Instead of borrowing from the high byte of the target frequency as it
; should, it borrows from the high byte of the current frequency instead.
; This means that the result will be 0x200 greater than it should be if the
; low byte of the current frequency is greater than the low byte of the
; target frequency.
2014-01-07 03:34:14 +00:00
ld a, d
sbc b
ld d, a
ld hl, wChannelPitchSlideTargetFrequencyHighBytes
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, [hl]
sub d
ld d, a
ld b, 0
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags1
2014-01-07 03:34:14 +00:00
add hl, bc
res BIT_PITCH_SLIDE_DECREASING, [hl]
.next2
ld hl, wChannelPitchSlideLengthModifiers
2014-01-07 03:34:14 +00:00
add hl, bc
.divideLoop
2014-01-07 03:34:14 +00:00
inc b
ld a, e
sub [hl]
ld e, a
jr nc, .divideLoop
2014-01-07 03:34:14 +00:00
ld a, d
and a
jr z, .doneDividing
2014-01-07 03:34:14 +00:00
dec a
ld d, a
jr .divideLoop
.doneDividing
ld a, e ; a = remainder - dividend
2014-01-07 03:34:14 +00:00
add [hl]
ld d, b ; d = quotient + 1
ld b, 0
ld hl, wChannelPitchSlideFrequencySteps
2014-01-07 03:34:14 +00:00
add hl, bc
ld [hl], d ; store quotient + 1
ld hl, wChannelPitchSlideFrequencyStepsFractionalPart
2014-01-07 03:34:14 +00:00
add hl, bc
ld [hl], a ; store remainder - dividend
ld hl, wChannelPitchSlideCurrentFrequencyFractionalPart
2014-01-07 03:34:14 +00:00
add hl, bc
ld [hl], a ; store remainder - dividend
2014-01-07 03:34:14 +00:00
ret
Audio2_ApplyDutyCyclePattern:
ld b, 0
ld hl, wChannelDutyCyclePatterns
2014-01-07 03:34:14 +00:00
add hl, bc
ld a, [hl]
rlca
rlca
ld [hl], a
and $c0
ld d, a
ld b, REG_DUTY_SOUND_LEN
call Audio2_GetRegisterPointer
2014-01-07 03:34:14 +00:00
ld a, [hl]
and $3f
or d
ld [hl], a
ret
2016-06-12 00:24:04 +00:00
Audio2_GetNextMusicByte:
ld d, 0
2014-01-07 03:34:14 +00:00
ld a, c
add a
ld e, a
2015-08-09 05:32:44 +00:00
ld hl, wChannelCommandPointers
2014-01-07 03:34:14 +00:00
add hl, de
ld a, [hli]
ld e, a
ld a, [hld]
ld d, a
ld a, [de] ; get next music command
inc de
ld [hl], e ; store address of next command
inc hl
ld [hl], d
ret
Audio2_GetRegisterPointer:
; hl = address of hardware sound register b for software channel c
2014-01-07 03:34:14 +00:00
ld a, c
ld hl, Audio2_HWChannelBaseAddresses
2014-01-07 03:34:14 +00:00
add l
jr nc, .noCarry
inc h
.noCarry
ld l, a
ld a, [hl]
add b
ld l, a
ld h, $ff
ret
Audio2_MultiplyAdd:
; hl = l + (a * de)
ld h, 0
2014-01-07 03:34:14 +00:00
.loop
srl a
jr nc, .skipAdd
2014-01-07 03:34:14 +00:00
add hl, de
.skipAdd
2014-01-07 03:34:14 +00:00
sla e
rl d
and a
jr z, .done
jr .loop
.done
ret
Audio2_CalculateFrequency:
; return the frequency for note a, octave b in de
ld h, 0
2014-01-07 03:34:14 +00:00
ld l, a
add hl, hl
ld d, h
ld e, l
ld hl, Audio2_Pitches
2014-01-07 03:34:14 +00:00
add hl, de
ld e, [hl]
inc hl
ld d, [hl]
ld a, b
.loop
cp 7
2014-01-07 03:34:14 +00:00
jr z, .done
sra d
rr e
inc a
jr .loop
.done
ld a, 8
2014-01-07 03:34:14 +00:00
add d
ld d, a
ret
2016-06-12 00:24:04 +00:00
Audio2_PlaySound::
2015-08-09 05:32:44 +00:00
ld [wSoundID], a
2020-07-16 17:25:02 +00:00
cp SFX_STOP_ALL_MUSIC
jp z, .stopAllAudio
cp MAX_SFX_ID_2
jp z, .playSfx
jp c, .playSfx
2014-01-07 03:34:14 +00:00
cp $fe
jr z, .playMusic
jp nc, .playSfx
.playMusic
2014-01-07 03:34:14 +00:00
xor a
ld [wUnusedMusicByte], a
2015-08-09 05:32:44 +00:00
ld [wDisableChannelOutputWhenSfxEnds], a
ld [wMusicTempo + 1], a
ld [wMusicWaveInstrument], a
ld [wSfxWaveInstrument], a
ld d, NUM_CHANNELS
2015-08-09 05:32:44 +00:00
ld hl, wChannelReturnAddresses
call .FillMem
2015-08-09 05:32:44 +00:00
ld hl, wChannelCommandPointers
call .FillMem
ld d, NUM_MUSIC_CHANS
2015-08-09 05:32:44 +00:00
ld hl, wChannelSoundIDs
call .FillMem
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags1
call .FillMem
2015-08-09 05:32:44 +00:00
ld hl, wChannelDutyCycles
call .FillMem
ld hl, wChannelDutyCyclePatterns
call .FillMem
2015-08-09 05:32:44 +00:00
ld hl, wChannelVibratoDelayCounters
call .FillMem
2015-08-09 05:32:44 +00:00
ld hl, wChannelVibratoExtents
call .FillMem
2015-08-09 05:32:44 +00:00
ld hl, wChannelVibratoRates
call .FillMem
2015-08-09 05:32:44 +00:00
ld hl, wChannelFrequencyLowBytes
call .FillMem
2015-08-09 05:32:44 +00:00
ld hl, wChannelVibratoDelayCounterReloadValues
call .FillMem
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags2
call .FillMem
ld hl, wChannelPitchSlideLengthModifiers
call .FillMem
ld hl, wChannelPitchSlideFrequencySteps
call .FillMem
ld hl, wChannelPitchSlideFrequencyStepsFractionalPart
call .FillMem
ld hl, wChannelPitchSlideCurrentFrequencyFractionalPart
call .FillMem
ld hl, wChannelPitchSlideCurrentFrequencyHighBytes
call .FillMem
ld hl, wChannelPitchSlideCurrentFrequencyLowBytes
call .FillMem
ld hl, wChannelPitchSlideTargetFrequencyHighBytes
call .FillMem
ld hl, wChannelPitchSlideTargetFrequencyLowBytes
call .FillMem
2014-01-07 03:34:14 +00:00
ld a, $1
2015-08-09 05:32:44 +00:00
ld hl, wChannelLoopCounters
call .FillMem
2015-08-09 05:32:44 +00:00
ld hl, wChannelNoteDelayCounters
call .FillMem
2015-08-09 05:32:44 +00:00
ld hl, wChannelNoteSpeeds
call .FillMem
2015-08-09 05:32:44 +00:00
ld [wMusicTempo], a
2014-01-07 03:34:14 +00:00
ld a, $ff
2015-08-09 05:32:44 +00:00
ld [wStereoPanning], a
2014-01-07 03:34:14 +00:00
xor a
ldh [rNR50], a
2014-01-07 03:34:14 +00:00
ld a, $8
ldh [rNR10], a
ld a, 0
ldh [rNR51], a
2014-01-07 03:34:14 +00:00
xor a
ldh [rNR30], a
2014-01-07 03:34:14 +00:00
ld a, $80
ldh [rNR30], a
2014-01-07 03:34:14 +00:00
ld a, $77
ldh [rNR50], a
jp .playSoundCommon
2014-01-07 03:34:14 +00:00
.playSfx
2014-01-07 03:34:14 +00:00
ld l, a
ld e, a
ld h, 0
2014-01-07 03:34:14 +00:00
ld d, h
add hl, hl
add hl, de
ld de, SFX_Headers_2
2014-01-07 03:34:14 +00:00
add hl, de
ld a, h
2015-08-09 05:32:44 +00:00
ld [wSfxHeaderPointer], a
2014-01-07 03:34:14 +00:00
ld a, l
2015-08-09 05:32:44 +00:00
ld [wSfxHeaderPointer + 1], a
2014-01-07 03:34:14 +00:00
ld a, [hl]
and $c0
rlca
rlca
ld c, a
.sfxChannelLoop
2014-01-07 03:34:14 +00:00
ld d, c
ld a, c
add a
add c
ld c, a
ld b, 0
2015-08-09 05:32:44 +00:00
ld a, [wSfxHeaderPointer]
2014-01-07 03:34:14 +00:00
ld h, a
2015-08-09 05:32:44 +00:00
ld a, [wSfxHeaderPointer + 1]
2014-01-07 03:34:14 +00:00
ld l, a
add hl, bc
ld c, d
ld a, [hl]
and $f
ld e, a ; software channel ID
ld d, 0
2015-08-09 05:32:44 +00:00
ld hl, wChannelSoundIDs
2014-01-07 03:34:14 +00:00
add hl, de
ld a, [hl]
and a
jr z, .playChannel
2014-01-07 03:34:14 +00:00
ld a, e
cp CHAN8
jr nz, .notNoiseChannel
2015-08-09 05:32:44 +00:00
ld a, [wSoundID]
cp NOISE_INSTRUMENTS_END
jr nc, .notNoiseInstrument
2014-01-07 03:34:14 +00:00
ret
.notNoiseInstrument
2014-01-07 03:34:14 +00:00
ld a, [hl]
cp NOISE_INSTRUMENTS_END
jr z, .playChannel
jr c, .playChannel
.notNoiseChannel
2015-08-09 05:32:44 +00:00
ld a, [wSoundID]
2014-01-07 03:34:14 +00:00
cp [hl]
jr z, .playChannel
jr c, .playChannel
2014-01-07 03:34:14 +00:00
ret
.playChannel
2014-01-07 03:34:14 +00:00
xor a
push de
ld h, d
ld l, e
add hl, hl
ld d, h
ld e, l
2015-08-09 05:32:44 +00:00
ld hl, wChannelReturnAddresses
2014-01-07 03:34:14 +00:00
add hl, de
ld [hli], a
ld [hl], a
2015-08-09 05:32:44 +00:00
ld hl, wChannelCommandPointers
2014-01-07 03:34:14 +00:00
add hl, de
ld [hli], a
ld [hl], a
pop de
2015-08-09 05:32:44 +00:00
ld hl, wChannelSoundIDs
2014-01-07 03:34:14 +00:00
add hl, de
ld [hl], a
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags1
2014-01-07 03:34:14 +00:00
add hl, de
ld [hl], a
ld hl, wChannelDutyCycles
2014-01-07 03:34:14 +00:00
add hl, de
ld [hl], a
ld hl, wChannelDutyCyclePatterns
2014-01-07 03:34:14 +00:00
add hl, de
ld [hl], a
2015-08-09 05:32:44 +00:00
ld hl, wChannelVibratoDelayCounters
2014-01-07 03:34:14 +00:00
add hl, de
ld [hl], a
2015-08-09 05:32:44 +00:00
ld hl, wChannelVibratoExtents
2014-01-07 03:34:14 +00:00
add hl, de
ld [hl], a
2015-08-09 05:32:44 +00:00
ld hl, wChannelVibratoRates
2014-01-07 03:34:14 +00:00
add hl, de
ld [hl], a
2015-08-09 05:32:44 +00:00
ld hl, wChannelFrequencyLowBytes
2014-01-07 03:34:14 +00:00
add hl, de
ld [hl], a
2015-08-09 05:32:44 +00:00
ld hl, wChannelVibratoDelayCounterReloadValues
2014-01-07 03:34:14 +00:00
add hl, de
ld [hl], a
ld hl, wChannelPitchSlideLengthModifiers
2014-01-07 03:34:14 +00:00
add hl, de
ld [hl], a
ld hl, wChannelPitchSlideFrequencySteps
2014-01-07 03:34:14 +00:00
add hl, de
ld [hl], a
ld hl, wChannelPitchSlideFrequencyStepsFractionalPart
2014-01-07 03:34:14 +00:00
add hl, de
ld [hl], a
ld hl, wChannelPitchSlideCurrentFrequencyFractionalPart
2014-01-07 03:34:14 +00:00
add hl, de
ld [hl], a
ld hl, wChannelPitchSlideCurrentFrequencyHighBytes
2014-01-07 03:34:14 +00:00
add hl, de
ld [hl], a
ld hl, wChannelPitchSlideCurrentFrequencyLowBytes
2014-01-07 03:34:14 +00:00
add hl, de
ld [hl], a
ld hl, wChannelPitchSlideTargetFrequencyHighBytes
2014-01-07 03:34:14 +00:00
add hl, de
ld [hl], a
ld hl, wChannelPitchSlideTargetFrequencyLowBytes
2014-01-07 03:34:14 +00:00
add hl, de
ld [hl], a
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags2
2014-01-07 03:34:14 +00:00
add hl, de
ld [hl], a
ld a, $1
2015-08-09 05:32:44 +00:00
ld hl, wChannelLoopCounters
2014-01-07 03:34:14 +00:00
add hl, de
ld [hl], a
2015-08-09 05:32:44 +00:00
ld hl, wChannelNoteDelayCounters
2014-01-07 03:34:14 +00:00
add hl, de
ld [hl], a
2015-08-09 05:32:44 +00:00
ld hl, wChannelNoteSpeeds
2014-01-07 03:34:14 +00:00
add hl, de
ld [hl], a
ld a, e
cp CHAN5
jr nz, .skipSweepDisable
2014-01-07 03:34:14 +00:00
ld a, $8
ldh [rNR10], a ; sweep off
.skipSweepDisable
2014-01-07 03:34:14 +00:00
ld a, c
and a
jp z, .playSoundCommon
2014-01-07 03:34:14 +00:00
dec c
jp .sfxChannelLoop
2014-01-07 03:34:14 +00:00
.stopAllAudio
2014-01-07 03:34:14 +00:00
ld a, $80
ldh [rNR52], a ; sound hardware on
ldh [rNR30], a ; wave playback on
2014-01-07 03:34:14 +00:00
xor a
ldh [rNR51], a ; no sound output
ldh [rNR32], a ; mute channel 3 (wave channel)
2014-01-07 03:34:14 +00:00
ld a, $8
ldh [rNR10], a ; sweep off
ldh [rNR12], a ; mute channel 1 (pulse channel 1)
ldh [rNR22], a ; mute channel 2 (pulse channel 2)
ldh [rNR42], a ; mute channel 4 (noise channel)
2014-01-07 03:34:14 +00:00
ld a, $40
ldh [rNR14], a ; counter mode
ldh [rNR24], a
ldh [rNR44], a
2014-01-07 03:34:14 +00:00
ld a, $77
ldh [rNR50], a ; full volume
2014-01-07 03:34:14 +00:00
xor a
ld [wUnusedMusicByte], a
2015-08-09 05:32:44 +00:00
ld [wDisableChannelOutputWhenSfxEnds], a
ld [wMuteAudioAndPauseMusic], a
ld [wMusicTempo + 1], a
ld [wSfxTempo + 1], a
ld [wMusicWaveInstrument], a
ld [wSfxWaveInstrument], a
2014-01-07 03:34:14 +00:00
ld d, $a0
2015-08-09 05:32:44 +00:00
ld hl, wChannelCommandPointers
call .FillMem
2014-01-07 03:34:14 +00:00
ld a, $1
ld d, $18
2015-08-09 05:32:44 +00:00
ld hl, wChannelNoteDelayCounters
call .FillMem
2015-08-09 05:32:44 +00:00
ld [wMusicTempo], a
ld [wSfxTempo], a
2014-01-07 03:34:14 +00:00
ld a, $ff
2015-08-09 05:32:44 +00:00
ld [wStereoPanning], a
2014-01-07 03:34:14 +00:00
ret
; fills d bytes at hl with a
.FillMem
2014-01-07 03:34:14 +00:00
ld b, d
.loop
ld [hli], a
dec b
jr nz, .loop
ret
.playSoundCommon
2015-08-09 05:32:44 +00:00
ld a, [wSoundID]
2014-01-07 03:34:14 +00:00
ld l, a
ld e, a
ld h, 0
2014-01-07 03:34:14 +00:00
ld d, h
add hl, hl
add hl, de
ld de, SFX_Headers_2
2014-01-07 03:34:14 +00:00
add hl, de
ld e, l
ld d, h
2015-08-09 05:32:44 +00:00
ld hl, wChannelCommandPointers
2014-01-07 03:34:14 +00:00
ld a, [de] ; get channel number
ld b, a
rlca
rlca
and $3
ld c, a
ld a, b
and $f
ld b, c
inc b
inc de
ld c, 0
.commandPointerLoop
2014-01-07 03:34:14 +00:00
cp c
jr z, .next
2014-01-07 03:34:14 +00:00
inc c
inc hl
inc hl
jr .commandPointerLoop
.next
2014-01-07 03:34:14 +00:00
push hl
push bc
push af
ld b, 0
2014-01-07 03:34:14 +00:00
ld c, a
2015-08-09 05:32:44 +00:00
ld hl, wChannelSoundIDs
2014-01-07 03:34:14 +00:00
add hl, bc
2015-08-09 05:32:44 +00:00
ld a, [wSoundID]
2014-01-07 03:34:14 +00:00
ld [hl], a
pop af
cp CHAN4
jr c, .skipSettingFlag
2015-08-09 05:32:44 +00:00
ld hl, wChannelFlags1
2014-01-07 03:34:14 +00:00
add hl, bc
set BIT_NOISE_OR_SFX, [hl]
.skipSettingFlag
2014-01-07 03:34:14 +00:00
pop bc
pop hl
ld a, [de] ; get channel pointer
ld [hli], a
inc de
ld a, [de]
ld [hli], a
inc de
inc c
dec b
ld a, b
and a
ld a, [de]
inc de
jr nz, .commandPointerLoop
2015-08-09 05:32:44 +00:00
ld a, [wSoundID]
cp CRY_SFX_START
jr nc, .maybeCry
jr .done
.maybeCry
2015-08-09 05:32:44 +00:00
ld a, [wSoundID]
cp CRY_SFX_END
jr z, .done
jr c, .cry
jr .done
.cry
ld hl, wChannelSoundIDs + CHAN5
2014-01-07 03:34:14 +00:00
ld [hli], a
ld [hli], a
ld [hli], a
ld [hl], a
ld hl, wChannelCommandPointers + CHAN7 * 2 ; sfx wave channel pointer
ld de, Audio2_CryRet
2014-01-07 03:34:14 +00:00
ld [hl], e
inc hl
ld [hl], d ; overwrite pointer to point to sound_ret
2015-08-09 05:32:44 +00:00
ld a, [wSavedVolume]
2014-01-07 03:34:14 +00:00
and a
jr nz, .done
ldh a, [rNR50]
2015-08-09 05:32:44 +00:00
ld [wSavedVolume], a
2014-01-07 03:34:14 +00:00
ld a, $77
ldh [rNR50], a ; full volume
.done
2014-01-07 03:34:14 +00:00
ret
Audio2_CryRet:
sound_ret
2014-01-07 03:34:14 +00:00
Audio2_HWChannelBaseAddresses:
; the low bytes of each HW channel's base address
db HW_CH1_BASE, HW_CH2_BASE, HW_CH3_BASE, HW_CH4_BASE ; channels 0-3
db HW_CH1_BASE, HW_CH2_BASE, HW_CH3_BASE, HW_CH4_BASE ; channels 4-7
2014-01-07 03:34:14 +00:00
Audio2_HWChannelDisableMasks:
db HW_CH1_DISABLE_MASK, HW_CH2_DISABLE_MASK, HW_CH3_DISABLE_MASK, HW_CH4_DISABLE_MASK ; channels 0-3
db HW_CH1_DISABLE_MASK, HW_CH2_DISABLE_MASK, HW_CH3_DISABLE_MASK, HW_CH4_DISABLE_MASK ; channels 4-7
2014-01-07 03:34:14 +00:00
Audio2_HWChannelEnableMasks:
db HW_CH1_ENABLE_MASK, HW_CH2_ENABLE_MASK, HW_CH3_ENABLE_MASK, HW_CH4_ENABLE_MASK ; channels 0-3
db HW_CH1_ENABLE_MASK, HW_CH2_ENABLE_MASK, HW_CH3_ENABLE_MASK, HW_CH4_ENABLE_MASK ; channels 4-7
2014-01-07 03:34:14 +00:00
2016-06-12 00:24:04 +00:00
Audio2_Pitches:
2020-06-28 02:24:13 +00:00
INCLUDE "audio/notes.asm"