pokecrystal-board/audio/engine.asm

2995 lines
49 KiB
NASM
Raw Normal View History

; The entire sound engine. Uses section "audio" in WRAM.
; Interfaces are in bank 0.
; Notable functions:
; FadeMusic
2013-10-08 10:05:52 -07:00
; PlayStereoSFX
2015-11-11 20:38:57 -08:00
_MapSetup_Sound_Off:: ; e8000
; restart sound operation
; clear all relevant hardware registers & wram
push hl
push de
push bc
push af
call MusicOff
2013-02-19 23:46:40 -08:00
ld hl, rNR50 ; channel control registers
xor a
2013-02-19 23:46:40 -08:00
ld [hli], a ; rNR50 ; volume/vin
ld [hli], a ; rNR51 ; sfx channels
ld a, $80 ; all channels on
ld [hli], a ; ff26 ; music channels
2013-02-19 23:46:40 -08:00
ld hl, rNR10 ; sound channel registers
2017-12-09 10:28:23 -08:00
ld e, NUM_MUSIC_CHANS
.clearsound
; sound channel 1 2 3 4
xor a
ld [hli], a ; rNR10, rNR20, rNR30, rNR40 ; sweep = 0
2013-02-19 23:46:40 -08:00
ld [hli], a ; rNR11, rNR21, rNR31, rNR41 ; length/wavepattern = 0
2015-12-06 19:36:09 -08:00
ld a, $8
2013-02-19 23:46:40 -08:00
ld [hli], a ; rNR12, rNR22, rNR32, rNR42 ; envelope = 0
xor a
2013-02-19 23:46:40 -08:00
ld [hli], a ; rNR13, rNR23, rNR33, rNR43 ; frequency lo = 0
ld a, $80
2013-02-19 23:46:40 -08:00
ld [hli], a ; rNR14, rNR24, rNR34, rNR44 ; restart sound (freq hi = 0)
dec e
jr nz, .clearsound
2016-03-01 19:31:21 -08:00
ld hl, Channels ; start of channel data
ld de, ChannelsEnd - Channels ; length of area to clear (entire sound wram area)
.clearchannels ; clear Channel1-$c2bf
xor a
ld [hli], a
dec de
ld a, e
or d
jr nz, .clearchannels
2017-12-09 10:28:23 -08:00
ld a, MAX_VOLUME
ld [Volume], a
call MusicOn
pop af
pop bc
pop de
pop hl
ret
2015-12-07 08:28:58 -08:00
; e803d
MusicFadeRestart: ; e803d
; restart but keep the music id to fade in to
ld a, [MusicFadeID + 1]
push af
ld a, [MusicFadeID]
push af
2015-11-11 20:38:57 -08:00
call _MapSetup_Sound_Off
pop af
ld [MusicFadeID], a
pop af
ld [MusicFadeID + 1], a
ret
2015-12-07 08:28:58 -08:00
; e8051
MusicOn: ; e8051
2015-12-06 19:36:09 -08:00
ld a, 1
ld [MusicPlaying], a
ret
2015-12-07 08:28:58 -08:00
; e8057
MusicOff: ; e8057
xor a
ld [MusicPlaying], a
ret
2015-12-07 08:28:58 -08:00
; e805c
_UpdateSound:: ; e805c
; called once per frame
; no use updating audio if it's not playing
ld a, [MusicPlaying]
and a
ret z
; start at ch1
xor a
ld [CurChannel], a ; just
ld [SoundOutput], a ; off
ld bc, Channel1
.loop
; is the channel active?
ld hl, Channel1Flags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
bit SOUND_CHANNEL_ON, [hl]
jp z, .nextchannel
; check time left in the current note
ld hl, Channel1NoteDuration - Channel1
add hl, bc
ld a, [hl]
2015-12-06 19:36:09 -08:00
cp $2 ; 1 or 0?
jr c, .noteover
dec [hl]
2016-05-10 11:33:24 -07:00
jr .continue_sound_update
2015-12-07 15:33:04 -08:00
.noteover
; reset vibrato delay
ld hl, Channel1VibratoDelay - Channel1
add hl, bc
ld a, [hl]
ld hl, Channel1VibratoDelayCount - Channel1
add hl, bc
ld [hl], a
; turn vibrato off for now
ld hl, Channel1Flags2 - Channel1
add hl, bc
2016-05-10 11:33:24 -07:00
res SOUND_PITCH_WHEEL, [hl]
; get next note
call ParseMusic
2016-05-10 11:33:24 -07:00
.continue_sound_update
call ApplyPitchWheel
; duty cycle
ld hl, Channel1DutyCycle - Channel1
add hl, bc
ld a, [hli]
2015-12-07 08:28:58 -08:00
ld [wCurTrackDuty], a
; intensity
ld a, [hli]
2015-12-07 08:28:58 -08:00
ld [wCurTrackIntensity], a
; frequency
ld a, [hli]
2015-12-07 08:28:58 -08:00
ld [wCurTrackFrequency], a
ld a, [hl]
2015-12-07 08:28:58 -08:00
ld [wCurTrackFrequency + 1], a
2016-05-10 13:38:40 -07:00
; vibrato, noise
2016-05-10 11:33:24 -07:00
call HandleTrackVibrato ; handle vibrato and other things
call HandleNoise
; turn off music when playing sfx?
ld a, [SFXPriority]
and a
jr z, .next
; are we in a sfx channel right now?
ld a, [CurChannel]
2017-12-09 10:28:23 -08:00
cp CHAN5
jr nc, .next
; are any sfx channels active?
; if so, mute
ld hl, Channel5Flags
2015-12-07 15:33:04 -08:00
bit SOUND_CHANNEL_ON, [hl]
jr nz, .restnote
ld hl, Channel6Flags
2015-12-07 15:33:04 -08:00
bit SOUND_CHANNEL_ON, [hl]
jr nz, .restnote
ld hl, Channel7Flags
2015-12-07 15:33:04 -08:00
bit SOUND_CHANNEL_ON, [hl]
jr nz, .restnote
ld hl, Channel8Flags
2015-12-07 15:33:04 -08:00
bit SOUND_CHANNEL_ON, [hl]
jr z, .next
.restnote
ld hl, Channel1NoteFlags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
set NOTE_REST, [hl] ; Rest
.next
; are we in a sfx channel right now?
ld a, [CurChannel]
2017-12-09 10:28:23 -08:00
cp CHAN5
2016-05-10 11:33:24 -07:00
jr nc, .sfx_channel
2015-12-06 19:36:09 -08:00
ld hl, Channel5Flags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
bit SOUND_CHANNEL_ON, [hl]
2016-05-10 11:33:24 -07:00
jr nz, .sound_channel_on
.sfx_channel
call UpdateChannels
ld hl, Channel1Tracks - Channel1
add hl, bc
ld a, [SoundOutput]
or [hl]
ld [SoundOutput], a
2016-05-10 11:33:24 -07:00
.sound_channel_on
; clear note flags
ld hl, Channel1NoteFlags - Channel1
add hl, bc
xor a
ld [hl], a
.nextchannel
; next channel
ld hl, Channel2 - Channel1
add hl, bc
ld c, l
ld b, h
ld a, [CurChannel]
inc a
ld [CurChannel], a
2015-12-06 19:36:09 -08:00
cp $8 ; are we done?
jp nz, .loop ; do it all again
2014-04-21 21:02:40 -07:00
call PlayDanger
; fade music in/out
call FadeMusic
; write volume to hardware register
ld a, [Volume]
2013-02-19 23:46:40 -08:00
ld [rNR50], a
; write SO on/off to hardware register
ld a, [SoundOutput]
2013-02-19 23:46:40 -08:00
ld [rNR51], a
ret
2015-12-07 08:28:58 -08:00
; e8125
UpdateChannels: ; e8125
ld hl, .ChannelFnPtrs
ld a, [CurChannel]
2015-12-06 19:36:09 -08:00
and $7
add a
ld e, a
2015-12-06 19:36:09 -08:00
ld d, 0
add hl, de
ld a, [hli]
ld h, [hl]
ld l, a
jp hl
.ChannelFnPtrs:
dw .Channel1
dw .Channel2
dw .Channel3
dw .Channel4
; sfx ch ptrs are identical to music chs
; ..except 5
dw .Channel5
dw .Channel6
dw .Channel7
dw .Channel8
.Channel1:
2014-04-21 21:02:40 -07:00
ld a, [Danger]
bit 7, a
ret nz
.Channel5:
ld hl, Channel1NoteFlags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
bit NOTE_UNKN_3, [hl]
jr z, .asm_e8159
;
ld a, [SoundInput]
2013-02-19 23:46:40 -08:00
ld [rNR10], a
.asm_e8159
2015-12-07 15:33:04 -08:00
bit NOTE_REST, [hl] ; rest
jr nz, .ch1rest
bit NOTE_NOISE_SAMPLING, [hl]
jr nz, .asm_e81a2
bit NOTE_FREQ_OVERRIDE, [hl]
jr nz, .frequency_override
bit NOTE_VIBRATO_OVERRIDE, [hl]
jr nz, .asm_e8184
jr .check_duty_override
2015-12-07 15:33:04 -08:00
.frequency_override
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackFrequency]
2013-02-19 23:46:40 -08:00
ld [rNR13], a
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackFrequency + 1]
2013-02-19 23:46:40 -08:00
ld [rNR14], a
.check_duty_override
bit NOTE_DUTY_OVERRIDE, [hl]
ret z
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackDuty]
ld d, a
2013-02-19 23:46:40 -08:00
ld a, [rNR11]
2015-12-06 19:36:09 -08:00
and $3f ; sound length
or d
2013-02-19 23:46:40 -08:00
ld [rNR11], a
ret
2015-12-07 08:28:58 -08:00
.asm_e8184
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackDuty]
ld d, a
2013-02-19 23:46:40 -08:00
ld a, [rNR11]
2015-12-06 19:36:09 -08:00
and $3f ; sound length
or d
2013-02-19 23:46:40 -08:00
ld [rNR11], a
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackFrequency]
2013-02-19 23:46:40 -08:00
ld [rNR13], a
ret
2015-12-07 08:28:58 -08:00
.ch1rest
2013-02-19 23:46:40 -08:00
ld a, [rNR52]
2015-12-06 19:36:09 -08:00
and %10001110 ; ch1 off
2013-02-19 23:46:40 -08:00
ld [rNR52], a
ld hl, rNR10
call ClearChannel
ret
2015-12-07 08:28:58 -08:00
.asm_e81a2
2015-12-07 08:28:58 -08:00
ld hl, wCurTrackDuty
ld a, $3f ; sound length
or [hl]
2013-02-19 23:46:40 -08:00
ld [rNR11], a
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackIntensity]
2013-02-19 23:46:40 -08:00
ld [rNR12], a
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackFrequency]
2013-02-19 23:46:40 -08:00
ld [rNR13], a
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackFrequency + 1]
2015-12-06 19:36:09 -08:00
or $80
2013-02-19 23:46:40 -08:00
ld [rNR14], a
ret
.Channel2:
.Channel6:
ld hl, Channel1NoteFlags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
bit NOTE_REST, [hl] ; rest
jr nz, .ch2rest
bit NOTE_NOISE_SAMPLING, [hl]
jr nz, .asm_e8204
bit NOTE_VIBRATO_OVERRIDE, [hl]
jr nz, .asm_e81e6
bit NOTE_DUTY_OVERRIDE, [hl]
ret z
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackDuty]
ld d, a
2013-02-19 23:46:40 -08:00
ld a, [rNR21]
2015-12-06 19:36:09 -08:00
and $3f ; sound length
or d
2013-02-19 23:46:40 -08:00
ld [rNR21], a
ret
2015-12-07 08:28:58 -08:00
.asm_e81db ; unused
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackFrequency]
2013-02-19 23:46:40 -08:00
ld [rNR23], a
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackFrequency + 1]
2013-02-19 23:46:40 -08:00
ld [rNR24], a
ret
2015-12-07 08:28:58 -08:00
.asm_e81e6
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackDuty]
ld d, a
2013-02-19 23:46:40 -08:00
ld a, [rNR21]
2015-12-06 19:36:09 -08:00
and $3f ; sound length
or d
2013-02-19 23:46:40 -08:00
ld [rNR21], a
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackFrequency]
2013-02-19 23:46:40 -08:00
ld [rNR23], a
ret
2015-12-07 08:28:58 -08:00
.ch2rest
2013-02-19 23:46:40 -08:00
ld a, [rNR52]
2015-12-06 19:36:09 -08:00
and %10001101 ; ch2 off
2013-02-19 23:46:40 -08:00
ld [rNR52], a
ld hl, rNR20
call ClearChannel
ret
2015-12-07 08:28:58 -08:00
.asm_e8204
2015-12-07 08:28:58 -08:00
ld hl, wCurTrackDuty
ld a, $3f ; sound length
or [hl]
2013-02-19 23:46:40 -08:00
ld [rNR21], a
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackIntensity]
2013-02-19 23:46:40 -08:00
ld [rNR22], a
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackFrequency]
2013-02-19 23:46:40 -08:00
ld [rNR23], a
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackFrequency + 1]
2015-12-06 19:36:09 -08:00
or $80 ; initial (restart)
2013-02-19 23:46:40 -08:00
ld [rNR24], a
ret
.Channel3:
.Channel7:
ld hl, Channel1NoteFlags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
bit NOTE_REST, [hl] ; rest
jr nz, .ch3rest
bit NOTE_NOISE_SAMPLING, [hl]
jr nz, .asm_e824d
bit NOTE_VIBRATO_OVERRIDE, [hl]
jr nz, .asm_e823a
ret
2015-12-07 08:28:58 -08:00
.asm_e822f ; unused
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackFrequency]
2013-02-19 23:46:40 -08:00
ld [rNR33], a
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackFrequency + 1]
2013-02-19 23:46:40 -08:00
ld [rNR34], a
ret
2015-12-07 08:28:58 -08:00
.asm_e823a
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackFrequency]
2013-02-19 23:46:40 -08:00
ld [rNR33], a
ret
2015-12-07 08:28:58 -08:00
.ch3rest
2013-02-19 23:46:40 -08:00
ld a, [rNR52]
2015-12-06 19:36:09 -08:00
and %10001011 ; ch3 off
2013-02-19 23:46:40 -08:00
ld [rNR52], a
ld hl, rNR30
call ClearChannel
ret
2015-12-07 08:28:58 -08:00
.asm_e824d
ld a, $3f
2013-02-19 23:46:40 -08:00
ld [rNR31], a
xor a
2013-02-19 23:46:40 -08:00
ld [rNR30], a
call .asm_e8268
ld a, $80
2013-02-19 23:46:40 -08:00
ld [rNR30], a
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackFrequency]
2013-02-19 23:46:40 -08:00
ld [rNR33], a
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackFrequency + 1]
2015-12-06 19:36:09 -08:00
or $80
2013-02-19 23:46:40 -08:00
ld [rNR34], a
ret
2015-12-07 08:28:58 -08:00
.asm_e8268
push hl
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackIntensity]
2015-12-06 19:36:09 -08:00
and $f ; only 0-9 are valid
ld l, a
2015-12-06 19:36:09 -08:00
ld h, 0
; hl << 4
2015-12-06 19:36:09 -08:00
; each wavepattern is $f bytes long
; so seeking is done in $10s
2015-07-20 19:18:18 -07:00
rept 4
add hl, hl
2015-07-20 19:18:18 -07:00
endr
ld de, WaveSamples
add hl, de
; load wavepattern into rWave_0-rWave_f
ld a, [hli]
ld [rWave_0], a
ld a, [hli]
ld [rWave_1], a
ld a, [hli]
ld [rWave_2], a
ld a, [hli]
ld [rWave_3], a
ld a, [hli]
ld [rWave_4], a
ld a, [hli]
ld [rWave_5], a
ld a, [hli]
ld [rWave_6], a
ld a, [hli]
ld [rWave_7], a
ld a, [hli]
ld [rWave_8], a
ld a, [hli]
ld [rWave_9], a
ld a, [hli]
ld [rWave_a], a
ld a, [hli]
ld [rWave_b], a
ld a, [hli]
ld [rWave_c], a
ld a, [hli]
ld [rWave_d], a
ld a, [hli]
ld [rWave_e], a
ld a, [hli]
ld [rWave_f], a
pop hl
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackIntensity]
2015-12-06 19:36:09 -08:00
and $f0
sla a
2013-02-19 23:46:40 -08:00
ld [rNR32], a
ret
.Channel4:
.Channel8:
ld hl, Channel1NoteFlags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
bit NOTE_REST, [hl] ; rest
jr nz, .ch4rest
bit NOTE_NOISE_SAMPLING, [hl]
jr nz, .asm_e82d4
ret
2015-12-07 08:28:58 -08:00
.asm_e82c1 ; unused
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackFrequency]
2013-02-19 23:46:40 -08:00
ld [rNR43], a
ret
2015-12-07 08:28:58 -08:00
.ch4rest
2013-02-19 23:46:40 -08:00
ld a, [rNR52]
2015-12-06 19:36:09 -08:00
and %10000111 ; ch4 off
2013-02-19 23:46:40 -08:00
ld [rNR52], a
ld hl, rNR40
call ClearChannel
ret
2015-12-07 08:28:58 -08:00
.asm_e82d4
ld a, $3f ; sound length
2013-02-19 23:46:40 -08:00
ld [rNR41], a
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackIntensity]
2013-02-19 23:46:40 -08:00
ld [rNR42], a
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackFrequency]
2013-02-19 23:46:40 -08:00
ld [rNR43], a
ld a, $80
2013-02-19 23:46:40 -08:00
ld [rNR44], a
ret
2015-12-07 08:28:58 -08:00
; e82e7
_CheckSFX: ; e82e7
; return carry if any sfx channels are active
ld hl, Channel5Flags
2015-12-07 15:33:04 -08:00
bit SOUND_CHANNEL_ON, [hl]
jr nz, .sfxon
ld hl, Channel6Flags
2015-12-07 15:33:04 -08:00
bit SOUND_CHANNEL_ON, [hl]
jr nz, .sfxon
ld hl, Channel7Flags
2015-12-07 15:33:04 -08:00
bit SOUND_CHANNEL_ON, [hl]
jr nz, .sfxon
ld hl, Channel8Flags
2015-12-07 15:33:04 -08:00
bit SOUND_CHANNEL_ON, [hl]
jr nz, .sfxon
and a
ret
2015-12-07 08:28:58 -08:00
.sfxon
scf
ret
2015-12-07 08:28:58 -08:00
; e8307
2014-04-21 21:02:40 -07:00
PlayDanger: ; e8307
ld a, [Danger]
bit 7, a
ret z
2015-12-06 19:36:09 -08:00
and $7f
ld d, a
call _CheckSFX
jr c, .asm_e8335
and a
jr z, .asm_e8323
2015-12-06 19:36:09 -08:00
cp 16 ; halfway
jr z, .asm_e831e
jr .asm_e8335
2015-12-07 15:33:04 -08:00
.asm_e831e
ld hl, Tablee8354
jr .updatehw
2015-12-07 15:33:04 -08:00
.asm_e8323
ld hl, Tablee8350
.updatehw
xor a
2013-02-19 23:46:40 -08:00
ld [rNR10], a ; sweep off
ld a, [hli]
2013-02-19 23:46:40 -08:00
ld [rNR11], a ; sound length / duty cycle
ld a, [hli]
2013-02-19 23:46:40 -08:00
ld [rNR12], a ; ch1 volume envelope
ld a, [hli]
2013-02-19 23:46:40 -08:00
ld [rNR13], a ; ch1 frequency lo
ld a, [hli]
2013-02-19 23:46:40 -08:00
ld [rNR14], a ; ch1 frequency hi
.asm_e8335
ld a, d
inc a
2015-12-06 19:36:09 -08:00
cp 30
jr c, .asm_e833c
xor a
.asm_e833c
2015-12-06 19:36:09 -08:00
or $80
2014-04-21 21:02:40 -07:00
ld [Danger], a
; is hw ch1 on?
ld a, [SoundOutput]
2015-12-06 19:36:09 -08:00
and $11
ret nz
; if not, turn it on
ld a, [SoundOutput]
2015-12-06 19:36:09 -08:00
or $11
ld [SoundOutput], a
ret
2015-12-07 08:28:58 -08:00
; e8350
Tablee8350: ; e8350
db $80 ; duty 50%
2015-12-06 19:36:09 -08:00
db $e2 ; volume 14, envelope decrease sweep 2
db $50 ; frequency: $750
db $87 ; restart sound
; e8354
Tablee8354: ; e8354
db $80 ; duty 50%
2015-12-06 19:36:09 -08:00
db $e2 ; volume 14, envelope decrease sweep 2
db $ee ; frequency: $6ee
db $86 ; restart sound
; e8358
FadeMusic: ; e8358
; fade music if applicable
; usage:
; write to MusicFade
; song fades out at the given rate
; load song id in MusicFadeID
; fade new song in
; notes:
; max # frames per volume level is $3f
; fading?
ld a, [MusicFade]
and a
ret z
; has the count ended?
ld a, [MusicFadeCount]
and a
jr z, .update
; count down
dec a
ld [MusicFadeCount], a
ret
2015-12-07 08:28:58 -08:00
.update
ld a, [MusicFade]
ld d, a
; get new count
2015-12-06 19:36:09 -08:00
and $3f
ld [MusicFadeCount], a
; get SO1 volume
ld a, [Volume]
2015-12-06 19:36:09 -08:00
and $7
; which way are we fading?
bit 7, d
jr nz, .fadein
; fading out
and a
jr z, .novolume
dec a
jr .updatevolume
2015-11-05 11:06:03 -08:00
.novolume
; make sure volume is off
xor a
ld [Volume], a
; did we just get on a bike?
ld a, [PlayerState]
2015-12-06 19:36:09 -08:00
cp $1 ; bicycle
jr z, .bicycle
push bc
; restart sound
call MusicFadeRestart
; get new song id
ld a, [MusicFadeID]
and a
jr z, .quit ; this assumes there are fewer than 256 songs!
ld e, a
ld a, [MusicFadeID + 1]
ld d, a
; load new song
2013-10-08 10:26:05 -07:00
call _PlayMusic
.quit
; cleanup
pop bc
; stop fading
xor a
ld [MusicFade], a
ret
2015-12-07 08:28:58 -08:00
.bicycle
push bc
; restart sound
call MusicFadeRestart
; this turns the volume up
; turn it back down
xor a
ld [Volume], a
; get new song id
ld a, [MusicFadeID]
ld e, a
ld a, [MusicFadeID + 1]
ld d, a
; load new song
2013-10-08 10:26:05 -07:00
call _PlayMusic
pop bc
; fade in
ld hl, MusicFade
set 7, [hl]
ret
2015-11-05 11:06:03 -08:00
.fadein
; are we done?
2015-12-06 19:36:09 -08:00
cp $7
jr nc, .maxvolume
; inc volume
inc a
jr .updatevolume
2015-12-07 15:33:04 -08:00
.maxvolume
; we're done
xor a
ld [MusicFade], a
ret
2015-12-07 08:28:58 -08:00
.updatevolume
; hi = lo
ld d, a
swap a
or d
ld [Volume], a
ret
2015-12-07 08:28:58 -08:00
; e83d1
LoadNote: ; e83d1
2016-05-10 11:33:24 -07:00
; wait for pitch wheel to finish
ld hl, Channel1Flags2 - Channel1
add hl, bc
2016-05-10 11:33:24 -07:00
bit SOUND_PITCH_WHEEL, [hl]
ret z
; get note duration
ld hl, Channel1NoteDuration - Channel1
add hl, bc
ld a, [hl]
2016-05-10 11:33:24 -07:00
ld hl, wCurNoteDuration
sub [hl]
jr nc, .ok
2015-12-06 19:36:09 -08:00
ld a, 1
.ok
ld [hl], a
; get frequency
ld hl, Channel1Frequency - Channel1
add hl, bc
ld e, [hl]
inc hl
ld d, [hl]
2016-05-10 11:33:24 -07:00
; get direction of pitch wheel
ld hl, Channel1PitchWheelTarget - Channel1
add hl, bc
ld a, e
sub [hl]
ld e, a
ld a, d
sbc 0
ld d, a
2016-05-10 11:33:24 -07:00
ld hl, Channel1PitchWheelTarget + 1 - Channel1
add hl, bc
sub [hl]
2015-12-08 13:06:13 -08:00
jr nc, .greater_than
ld hl, Channel1Flags3 - Channel1
add hl, bc
2016-05-10 11:33:24 -07:00
set SOUND_PITCH_WHEEL_DIR, [hl]
; get frequency
ld hl, Channel1Frequency - Channel1
add hl, bc
ld e, [hl]
inc hl
ld d, [hl]
; ????
2016-05-10 11:33:24 -07:00
ld hl, Channel1PitchWheelTarget - Channel1
add hl, bc
ld a, [hl]
sub e
ld e, a
ld a, d
sbc 0
ld d, a
; ????
2016-05-10 11:33:24 -07:00
ld hl, Channel1PitchWheelTarget + 1 - Channel1
add hl, bc
ld a, [hl]
sub d
ld d, a
2015-12-08 13:06:13 -08:00
jr .resume
2015-12-07 15:33:04 -08:00
2015-12-08 13:06:13 -08:00
.greater_than
ld hl, Channel1Flags3 - Channel1
add hl, bc
2016-05-10 11:33:24 -07:00
res SOUND_PITCH_WHEEL_DIR, [hl]
; get frequency
ld hl, Channel1Frequency - Channel1
add hl, bc
ld e, [hl]
inc hl
ld d, [hl]
2016-05-10 11:33:24 -07:00
; get distance from pitch wheel target
ld hl, Channel1PitchWheelTarget - Channel1
add hl, bc
ld a, e
sub [hl]
ld e, a
ld a, d
sbc 0
ld d, a
2016-05-10 11:33:24 -07:00
ld hl, Channel1PitchWheelTarget + 1 - Channel1
add hl, bc
sub [hl]
ld d, a
2015-12-08 13:06:13 -08:00
.resume
2016-05-10 11:33:24 -07:00
; de = x * [wCurNoteDuration] + y
; x + 1 -> d
; y -> a
push bc
2016-05-10 11:33:24 -07:00
ld hl, wCurNoteDuration
ld b, 0 ; quotient
.loop
inc b
ld a, e
sub [hl]
ld e, a
jr nc, .loop
ld a, d
and a
jr z, .quit
dec d
jr .loop
2015-12-07 15:33:04 -08:00
.quit
2016-05-10 11:33:24 -07:00
ld a, e ; remainder
add [hl]
2016-05-10 11:33:24 -07:00
ld d, b ; quotient
pop bc
2016-05-10 11:33:24 -07:00
ld hl, Channel1PitchWheelAmount - Channel1
add hl, bc
2016-05-10 11:33:24 -07:00
ld [hl], d ; quotient
ld hl, Channel1PitchWheelAmountFraction - Channel1
add hl, bc
2016-05-10 11:33:24 -07:00
ld [hl], a ; remainder
2015-12-06 19:36:09 -08:00
ld hl, Channel1Field0x25 - Channel1
add hl, bc
xor a
ld [hl], a
ret
2015-12-07 08:28:58 -08:00
; e8466
2016-05-10 11:33:24 -07:00
HandleTrackVibrato: ; e8466
2016-05-10 13:38:40 -07:00
; handle duty, cry pitch, and vibrato
ld hl, Channel1Flags2 - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
bit SOUND_DUTY, [hl] ; duty
jr z, .next
2016-05-10 13:38:40 -07:00
ld hl, Channel1SFXDutyLoop - Channel1
add hl, bc
ld a, [hl]
rlca
rlca
ld [hl], a
2015-12-06 19:36:09 -08:00
and $c0
2015-12-07 08:28:58 -08:00
ld [wCurTrackDuty], a
ld hl, Channel1NoteFlags - Channel1
add hl, bc
set NOTE_DUTY_OVERRIDE, [hl]
.next
ld hl, Channel1Flags2 - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
bit SOUND_CRY_PITCH, [hl]
jr z, .vibrato
ld hl, Channel1CryPitch - Channel1
add hl, bc
ld e, [hl]
inc hl
ld d, [hl]
2015-12-07 08:28:58 -08:00
ld hl, wCurTrackFrequency
ld a, [hli]
ld h, [hl]
ld l, a
add hl, de
ld e, l
ld d, h
2015-12-07 08:28:58 -08:00
ld hl, wCurTrackFrequency
ld [hl], e
inc hl
ld [hl], d
.vibrato
; is vibrato on?
ld hl, Channel1Flags2 - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
bit SOUND_VIBRATO, [hl] ; vibrato
jr z, .quit
; is vibrato active for this note yet?
; is the delay over?
ld hl, Channel1VibratoDelayCount - Channel1
add hl, bc
ld a, [hl]
and a
jr nz, .subexit
; is the extent nonzero?
ld hl, Channel1VibratoExtent - Channel1
add hl, bc
ld a, [hl]
and a
jr z, .quit
; save it for later
ld d, a
; is it time to toggle vibrato up/down?
ld hl, Channel1VibratoRate - Channel1
add hl, bc
ld a, [hl]
2015-12-06 19:36:09 -08:00
and $f ; count
jr z, .toggle
.subexit
dec [hl]
jr .quit
2015-12-07 15:33:04 -08:00
.toggle
; refresh count
ld a, [hl]
swap [hl]
or [hl]
ld [hl], a
; ????
2015-12-07 08:28:58 -08:00
ld a, [wCurTrackFrequency]
ld e, a
; toggle vibrato up/down
ld hl, Channel1Flags3 - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
bit SOUND_VIBRATO_DIR, [hl] ; vibrato up/down
jr z, .down
; up
; vibrato down
2015-12-07 15:33:04 -08:00
res SOUND_VIBRATO_DIR, [hl]
; get the delay
ld a, d
2015-12-06 19:36:09 -08:00
and $f ; lo
;
ld d, a
ld a, e
sub d
jr nc, .no_carry
2015-12-06 19:36:09 -08:00
ld a, 0
jr .no_carry
2015-12-07 15:33:04 -08:00
.down
; vibrato up
2015-12-07 15:33:04 -08:00
set SOUND_VIBRATO_DIR, [hl]
; get the delay
ld a, d
2015-12-06 19:36:09 -08:00
and $f0 ; hi
swap a ; move it to lo
;
add e
jr nc, .no_carry
ld a, $ff
.no_carry
2015-12-07 08:28:58 -08:00
ld [wCurTrackFrequency], a
;
ld hl, Channel1NoteFlags - Channel1
add hl, bc
set NOTE_VIBRATO_OVERRIDE, [hl]
.quit
ret
2015-12-07 08:28:58 -08:00
; e84f9
2016-05-10 11:33:24 -07:00
ApplyPitchWheel: ; e84f9
; quit if pitch wheel inactive
ld hl, Channel1Flags2 - Channel1
add hl, bc
2016-05-10 11:33:24 -07:00
bit SOUND_PITCH_WHEEL, [hl]
ret z
; de = Frequency
ld hl, Channel1Frequency - Channel1
add hl, bc
ld e, [hl]
inc hl
ld d, [hl]
2016-05-10 11:33:24 -07:00
; check whether pitch wheel is going up or down
ld hl, Channel1Flags3 - Channel1
add hl, bc
2016-05-10 11:33:24 -07:00
bit SOUND_PITCH_WHEEL_DIR, [hl]
jr z, .decreasing
; frequency += [Channel*PitchWheelAmount]
ld hl, Channel1PitchWheelAmount - Channel1
add hl, bc
ld l, [hl]
2015-12-06 19:36:09 -08:00
ld h, 0
add hl, de
ld d, h
ld e, l
2016-05-10 11:33:24 -07:00
; [Channel*Field0x25] += [Channel*PitchWheelAmountFraction]
; if rollover: Frequency += 1
ld hl, Channel1PitchWheelAmountFraction - Channel1
add hl, bc
ld a, [hl]
2015-12-06 19:36:09 -08:00
ld hl, Channel1Field0x25 - Channel1
add hl, bc
add [hl]
ld [hl], a
2015-12-06 19:36:09 -08:00
ld a, 0
adc e
ld e, a
2015-12-06 19:36:09 -08:00
ld a, 0
adc d
ld d, a
2016-05-10 11:33:24 -07:00
; Compare the dw at [Channel*PitchWheelTarget] to de.
; If frequency is greater, we're finished.
; Otherwise, load the frequency and set two flags.
ld hl, Channel1PitchWheelTarget + 1 - Channel1
add hl, bc
ld a, [hl]
cp d
2016-05-10 11:33:24 -07:00
jp c, .finished_pitch_wheel
jr nz, .continue_pitch_wheel
ld hl, Channel1PitchWheelTarget - Channel1
add hl, bc
ld a, [hl]
cp e
2016-05-10 11:33:24 -07:00
jp c, .finished_pitch_wheel
jr .continue_pitch_wheel
2015-12-07 15:33:04 -08:00
2016-05-10 11:33:24 -07:00
.decreasing
; frequency -= [Channel*PitchWheelAmount]
ld a, e
2016-05-10 11:33:24 -07:00
ld hl, Channel1PitchWheelAmount - Channel1
add hl, bc
ld e, [hl]
sub e
ld e, a
ld a, d
sbc 0
ld d, a
2016-05-10 11:33:24 -07:00
; [Channel*Field0x25] *= 2
; if rollover: Frequency -= 1
ld hl, Channel1PitchWheelAmountFraction - Channel1
add hl, bc
ld a, [hl]
add a
ld [hl], a
ld a, e
sbc 0
ld e, a
ld a, d
sbc 0
2016-05-10 11:33:24 -07:00
ld d, a
; Compare the dw at [Channel*PitchWheelTarget] to de.
; If frequency is lower, we're finished.
; Otherwise, load the frequency and set two flags.
ld hl, Channel1PitchWheelTarget + 1 - Channel1
add hl, bc
ld a, d
cp [hl]
2016-05-10 11:33:24 -07:00
jr c, .finished_pitch_wheel
jr nz, .continue_pitch_wheel
ld hl, Channel1PitchWheelTarget - Channel1
add hl, bc
ld a, e
cp [hl]
2016-05-10 11:33:24 -07:00
jr nc, .continue_pitch_wheel
.finished_pitch_wheel
ld hl, Channel1Flags2 - Channel1
add hl, bc
2016-05-10 11:33:24 -07:00
res SOUND_PITCH_WHEEL, [hl]
ld hl, Channel1Flags3 - Channel1
add hl, bc
2016-05-10 11:33:24 -07:00
res SOUND_PITCH_WHEEL_DIR, [hl]
ret
2015-12-07 08:28:58 -08:00
2016-05-10 11:33:24 -07:00
.continue_pitch_wheel
ld hl, Channel1Frequency - Channel1
add hl, bc
ld [hl], e
inc hl
ld [hl], d
ld hl, Channel1NoteFlags - Channel1
add hl, bc
set NOTE_FREQ_OVERRIDE, [hl]
set NOTE_DUTY_OVERRIDE, [hl]
ret
2015-12-07 08:28:58 -08:00
; e858c
HandleNoise: ; e858c
; is noise sampling on?
ld hl, Channel1Flags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
bit SOUND_NOISE, [hl] ; noise sampling
ret z
; are we in a sfx channel?
ld a, [CurChannel]
bit 2, a ; sfx
jr nz, .next
; is ch8 on? (noise)
ld hl, Channel8Flags
2015-12-07 15:33:04 -08:00
bit SOUND_CHANNEL_ON, [hl] ; on?
jr z, .next
; is ch8 playing noise?
2015-12-07 15:33:04 -08:00
bit SOUND_NOISE, [hl]
ret nz ; quit if so
;
.next
2015-12-07 08:28:58 -08:00
ld a, [wNoiseSampleDelay]
and a
jr z, ReadNoiseSample
dec a
2015-12-07 08:28:58 -08:00
ld [wNoiseSampleDelay], a
ret
2015-12-07 08:28:58 -08:00
; e85af
ReadNoiseSample: ; e85af
; sample struct:
; [wx] [yy] [zz]
; w: ? either 2 or 3
2013-11-05 12:04:26 -08:00
; x: duration
; zz: intensity
; yy: frequency
2013-11-05 12:04:26 -08:00
; de = [NoiseSampleAddress]
ld hl, NoiseSampleAddress
ld e, [hl]
inc hl
ld d, [hl]
2013-11-05 12:04:26 -08:00
; is it empty?
ld a, e
or d
jr z, .quit
2013-11-05 12:04:26 -08:00
ld a, [de]
inc de
2013-11-05 12:04:26 -08:00
cp $ff
jr z, .quit
2013-11-05 12:04:26 -08:00
and $f
inc a
2015-12-07 08:28:58 -08:00
ld [wNoiseSampleDelay], a
ld a, [de]
inc de
2015-12-07 08:28:58 -08:00
ld [wCurTrackIntensity], a
ld a, [de]
inc de
2015-12-07 08:28:58 -08:00
ld [wCurTrackFrequency], a
xor a
2015-12-07 08:28:58 -08:00
ld [wCurTrackFrequency + 1], a
2013-11-05 12:04:26 -08:00
ld hl, NoiseSampleAddress
ld [hl], e
inc hl
ld [hl], d
2013-11-05 12:04:26 -08:00
ld hl, Channel1NoteFlags - Channel1
add hl, bc
set NOTE_NOISE_SAMPLING, [hl]
ret
2015-12-07 08:28:58 -08:00
.quit
ret
2015-12-07 08:28:58 -08:00
; e85e1
ParseMusic: ; e85e1
; parses until a note is read or the song is ended
call GetMusicByte ; store next byte in a
2015-12-06 19:36:09 -08:00
cp $ff ; is the song over?
2015-12-07 15:33:04 -08:00
jr z, .endchannel
2015-12-06 19:36:09 -08:00
cp $d0 ; is it a note?
jr c, .readnote
; then it's a command
.readcommand
call ParseMusicCommand
jr ParseMusic ; start over
.readnote
; CurMusicByte contains current note
; special notes
ld hl, Channel1Flags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
bit SOUND_SFX, [hl]
2016-05-10 11:33:24 -07:00
jp nz, ParseSFXOrRest
2015-12-07 15:33:04 -08:00
bit SOUND_REST, [hl] ; rest
2016-05-10 11:33:24 -07:00
jp nz, ParseSFXOrRest
2015-12-07 15:33:04 -08:00
bit SOUND_NOISE, [hl] ; noise sample
jp nz, GetNoiseSample
; normal note
; set note duration (bottom nybble)
ld a, [CurMusicByte]
2015-12-06 19:36:09 -08:00
and $f
call SetNoteDuration
; get note pitch (top nybble)
ld a, [CurMusicByte]
swap a
2015-12-06 19:36:09 -08:00
and $f
jr z, .rest ; pitch 0-> rest
; update pitch
ld hl, Channel1Pitch - Channel1
add hl, bc
ld [hl], a
; store pitch in e
ld e, a
; store octave in d
ld hl, Channel1Octave - Channel1
add hl, bc
ld d, [hl]
; update frequency
call GetFrequency
ld hl, Channel1Frequency - Channel1
add hl, bc
ld [hl], e
inc hl
ld [hl], d
; ????
ld hl, Channel1NoteFlags - Channel1
add hl, bc
set NOTE_NOISE_SAMPLING, [hl]
jp LoadNote
2015-12-06 19:36:09 -08:00
.rest
; note = rest
ld hl, Channel1NoteFlags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
set NOTE_REST, [hl] ; Rest
ret
2015-12-07 08:28:58 -08:00
2015-12-07 15:33:04 -08:00
.endchannel
; $ff is reached in music data
ld hl, Channel1Flags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
bit SOUND_SUBROUTINE, [hl] ; in a subroutine?
jr nz, .readcommand ; execute
ld a, [CurChannel]
2017-12-09 10:28:23 -08:00
cp CHAN5
2015-12-06 19:36:09 -08:00
jr nc, .chan_5to8
; ????
2015-12-06 19:36:09 -08:00
ld hl, Channel5Flags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
bit SOUND_CHANNEL_ON, [hl]
jr nz, .ok
2015-12-06 19:36:09 -08:00
.chan_5to8
ld hl, Channel1Flags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
bit SOUND_REST, [hl]
call nz, RestoreVolume
; end music
ld a, [CurChannel]
2017-12-09 10:28:23 -08:00
cp CHAN5
jr nz, .ok
; ????
xor a
2013-02-19 23:46:40 -08:00
ld [rNR10], a ; sweep = 0
.ok
; stop playing
; turn channel off
ld hl, Channel1Flags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
res SOUND_CHANNEL_ON, [hl]
; note = rest
ld hl, Channel1NoteFlags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
set NOTE_REST, [hl]
; clear music id & bank
ld hl, Channel1MusicID - Channel1
add hl, bc
xor a
ld [hli], a ; id hi
ld [hli], a ; id lo
ld [hli], a ; bank
ret
2015-12-07 08:28:58 -08:00
; e8679
RestoreVolume: ; e8679
; ch5 only
ld a, [CurChannel]
2017-12-09 10:28:23 -08:00
cp CHAN5
ret nz
xor a
ld hl, Channel6CryPitch
ld [hli], a
ld [hl], a
ld hl, Channel8CryPitch
ld [hli], a
ld [hl], a
ld a, [LastVolume]
ld [Volume], a
xor a
ld [LastVolume], a
ld [SFXPriority], a
ret
2015-12-07 08:28:58 -08:00
; e8698
2016-05-10 11:33:24 -07:00
ParseSFXOrRest: ; e8698
; turn noise sampling on
ld hl, Channel1NoteFlags - Channel1
add hl, bc
set NOTE_NOISE_SAMPLING, [hl] ; noise sample
; update note duration
ld a, [CurMusicByte]
call SetNoteDuration ; top nybble doesnt matter?
; update intensity from next param
call GetMusicByte
ld hl, Channel1Intensity - Channel1
add hl, bc
ld [hl], a
; update lo frequency from next param
call GetMusicByte
ld hl, Channel1FrequencyLo - Channel1
add hl, bc
ld [hl], a
; are we on the last channel? (noise sampling)
ld a, [CurChannel]
2015-12-06 19:36:09 -08:00
and $3
cp $3
ret z
; update hi frequency from next param
call GetMusicByte
ld hl, Channel1FrequencyHi - Channel1
add hl, bc
ld [hl], a
ret
2015-12-07 08:28:58 -08:00
; e86c5
GetNoiseSample: ; e86c5
; load ptr to sample header in NoiseSampleAddress
; are we on the last channel?
ld a, [CurChannel]
2015-12-06 19:36:09 -08:00
and $3
cp $3
; ret if not
ret nz
; update note duration
ld a, [CurMusicByte]
2015-12-06 19:36:09 -08:00
and $f
call SetNoteDuration
; check current channel
ld a, [CurChannel]
bit 2, a ; are we in a sfx channel?
jr nz, .sfx
ld hl, Channel8Flags
2015-12-07 15:33:04 -08:00
bit SOUND_CHANNEL_ON, [hl] ; is ch8 on? (noise)
ret nz
ld a, [MusicNoiseSampleSet]
jr .next
2015-12-07 15:33:04 -08:00
.sfx
ld a, [SFXNoiseSampleSet]
.next
; load noise sample set id into de
ld e, a
2015-12-06 19:36:09 -08:00
ld d, 0
; load ptr to noise sample set in hl
ld hl, Drumkits
add hl, de
add hl, de
ld a, [hli]
ld h, [hl]
ld l, a
; get pitch
ld a, [CurMusicByte]
swap a
; non-rest note?
2015-12-06 19:36:09 -08:00
and $f
ret z
; use 'pitch' to seek noise sample set
ld e, a
2015-12-06 19:36:09 -08:00
ld d, 0
add hl, de
add hl, de
; load sample pointer into NoiseSampleAddress
ld a, [hli]
ld [NoiseSampleAddress], a
ld a, [hl]
ld [NoiseSampleAddress + 1], a
; clear ????
xor a
2015-12-07 08:28:58 -08:00
ld [wNoiseSampleDelay], a
ret
2015-12-07 08:28:58 -08:00
; e870f
ParseMusicCommand: ; e870f
; reload command
ld a, [CurMusicByte]
; get command #
sub $d0 ; first command
ld e, a
2015-12-06 19:36:09 -08:00
ld d, 0
; seek command pointer
ld hl, MusicCommands
add hl, de
add hl, de
; jump to the new pointer
ld a, [hli]
ld h, [hl]
ld l, a
jp hl
2015-12-07 15:33:04 -08:00
; e8720
MusicCommands: ; e8720
; pointer to each command in order
; octaves
2015-12-06 19:36:09 -08:00
dw Music_Octave8 ; octave 8
dw Music_Octave7 ; octave 7
dw Music_Octave6 ; octave 6
dw Music_Octave5 ; octave 5
dw Music_Octave4 ; octave 4
dw Music_Octave3 ; octave 3
dw Music_Octave2 ; octave 2
dw Music_Octave1 ; octave 1
dw Music_NoteType ; note length + intensity
dw Music_ForceOctave ; set starting octave
dw Music_Tempo ; tempo
dw Music_DutyCycle ; duty cycle
dw Music_Intensity ; intensity
dw Music_SoundStatus ; update sound status
2016-05-10 13:38:40 -07:00
dw Music_SoundDuty ; sfx duty
dw Music_ToggleSFX ; sound on/off
dw Music_SlidePitchTo ; pitch wheel
2015-12-06 19:36:09 -08:00
dw Music_Vibrato ; vibrato
2015-12-08 13:06:13 -08:00
dw MusicE2 ; unused
2015-12-06 19:36:09 -08:00
dw Music_ToggleNoise ; music noise sampling
dw Music_Panning ; force panning
dw Music_Volume ; volume
dw Music_Tone ; tone
2015-12-08 13:06:13 -08:00
dw MusicE7 ; unused
dw MusicE8 ; unused
dw Music_TempoRelative ; global tempo
2015-12-06 19:36:09 -08:00
dw Music_RestartChannel ; restart current channel from header
dw Music_NewSong ; new song
dw Music_SFXPriorityOn ; sfx priority on
dw Music_SFXPriorityOff ; sfx priority off
2015-12-08 13:06:13 -08:00
dw MusicEE ; unused
2015-12-06 19:36:09 -08:00
dw Music_StereoPanning ; stereo panning
dw Music_SFXToggleNoise ; sfx noise sampling
dw MusicF1 ; nothing
2013-11-05 12:17:24 -08:00
dw MusicF2 ; nothing
dw MusicF3 ; nothing
dw MusicF4 ; nothing
dw MusicF5 ; nothing
dw MusicF6 ; nothing
dw MusicF7 ; nothing
dw MusicF8 ; nothing
2015-12-08 13:06:13 -08:00
dw MusicF9 ; unused
2016-05-10 13:38:40 -07:00
dw Music_SetCondition ; setcondition
dw Music_JumpIf ; jumpif
2015-12-06 19:36:09 -08:00
dw Music_JumpChannel ; jump
dw Music_LoopChannel ; loop
dw Music_CallChannel ; call
dw Music_EndChannel ; return
; e8780
MusicF1: ; e8780
2013-11-05 12:17:24 -08:00
MusicF2: ; e8780
MusicF3: ; e8780
MusicF4: ; e8780
MusicF5: ; e8780
MusicF6: ; e8780
MusicF7: ; e8780
MusicF8: ; e8780
ret
2015-12-07 08:28:58 -08:00
; e8781
2015-12-06 19:36:09 -08:00
Music_EndChannel: ; e8781
; called when $ff is encountered w/ subroutine flag set
; end music stream
; return to caller of the subroutine
; reset subroutine flag
ld hl, Channel1Flags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
res SOUND_SUBROUTINE, [hl]
; copy LastMusicAddress to MusicAddress
ld hl, Channel1LastMusicAddress - Channel1
add hl, bc
ld e, [hl]
inc hl
ld d, [hl]
ld hl, Channel1MusicAddress - Channel1
add hl, bc
ld [hl], e
inc hl
ld [hl], d
ret
2015-12-07 08:28:58 -08:00
; e8796
2015-12-06 19:36:09 -08:00
Music_CallChannel: ; e8796
; call music stream (subroutine)
; parameters: ll hh ; pointer to subroutine
; get pointer from next 2 bytes
call GetMusicByte
ld e, a
call GetMusicByte
ld d, a
push de
; copy MusicAddress to LastMusicAddress
ld hl, Channel1MusicAddress - Channel1
add hl, bc
ld e, [hl]
inc hl
ld d, [hl]
ld hl, Channel1LastMusicAddress - Channel1
add hl, bc
ld [hl], e
inc hl
ld [hl], d
; load pointer into MusicAddress
pop de
ld hl, Channel1MusicAddress - Channel1
add hl, bc
ld [hl], e
inc hl
ld [hl], d
; set subroutine flag
ld hl, Channel1Flags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
set SOUND_SUBROUTINE, [hl]
ret
2015-12-07 08:28:58 -08:00
; e87bc
2015-12-06 19:36:09 -08:00
Music_JumpChannel: ; e87bc
; jump
; parameters: ll hh ; pointer
; get pointer from next 2 bytes
call GetMusicByte
ld e, a
call GetMusicByte
ld d, a
ld hl, Channel1MusicAddress - Channel1
add hl, bc
ld [hl], e
inc hl
ld [hl], d
ret
2015-12-07 08:28:58 -08:00
; e87cc
2015-12-06 19:36:09 -08:00
Music_LoopChannel: ; e87cc
; loops xx - 1 times
; 00: infinite
; params: 3
; xx ll hh
; xx : loop count
; ll hh : pointer
; get loop count
call GetMusicByte
ld hl, Channel1Flags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
bit SOUND_LOOPING, [hl] ; has the loop been initiated?
jr nz, .checkloop
and a ; loop counter 0 = infinite
jr z, .loop
; initiate loop
dec a
2015-12-07 15:33:04 -08:00
set SOUND_LOOPING, [hl] ; set loop flag
ld hl, Channel1LoopCount - Channel1
add hl, bc
ld [hl], a ; store loop counter
.checkloop
ld hl, Channel1LoopCount - Channel1
add hl, bc
ld a, [hl]
and a ; are we done?
jr z, .endloop
dec [hl]
.loop
; get pointer
call GetMusicByte
ld e, a
call GetMusicByte
ld d, a
; load new pointer into MusicAddress
ld hl, Channel1MusicAddress - Channel1
add hl, bc
ld [hl], e
inc hl
ld [hl], d
ret
.endloop
; reset loop flag
ld hl, Channel1Flags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
res SOUND_LOOPING, [hl]
; skip to next command
ld hl, Channel1MusicAddress - Channel1
add hl, bc
ld e, [hl]
inc hl
ld d, [hl]
inc de ; skip
inc de ; pointer
ld [hl], d
dec hl
ld [hl], e
ret
2015-12-07 08:28:58 -08:00
; e880e
2015-12-06 19:36:09 -08:00
Music_SetCondition: ; e880e
; set condition for a jump
; used with FB
; params: 1
; xx ; condition
; set condition
call GetMusicByte
ld hl, Channel1Condition - Channel1
add hl, bc
ld [hl], a
ret
2015-12-07 08:28:58 -08:00
; e8817
2015-12-06 19:36:09 -08:00
Music_JumpIf: ; e8817
; conditional jump
; used with FA
; params: 3
; xx: condition
; ll hh: pointer
; check condition
; a = condition
call GetMusicByte
; if existing condition matches, jump to new address
ld hl, Channel1Condition - Channel1
add hl, bc
cp [hl]
jr z, .jump
; skip to next command
; get address
ld hl, Channel1MusicAddress - Channel1
add hl, bc
ld e, [hl]
inc hl
ld d, [hl]
; skip pointer
inc de
inc de
; update address
ld [hl], d
dec hl
ld [hl], e
ret
2015-12-07 08:28:58 -08:00
.jump
; jump to the new address
; get pointer
call GetMusicByte
ld e, a
call GetMusicByte
ld d, a
; update pointer in MusicAddress
ld hl, Channel1MusicAddress - Channel1
add hl, bc
ld [hl], e
inc hl
ld [hl], d
ret
2015-12-07 08:28:58 -08:00
; e883e
MusicEE; e883e
; conditional jump
; checks a byte in ram corresponding to the current channel
; doesn't seem to be set by any commands
; params: 2
; ll hh ; pointer
; if ????, jump
; get channel
ld a, [CurChannel]
2015-12-06 19:36:09 -08:00
and $3 ; ch0-3
ld e, a
2015-12-06 19:36:09 -08:00
ld d, 0
2015-12-07 15:33:04 -08:00
; hl = Channel1JumpCondition + channel id
ld hl, Channel1JumpCondition
add hl, de
; if set, jump
ld a, [hl]
and a
jr nz, .jump
; skip to next command
; get address
ld hl, Channel1MusicAddress - Channel1
add hl, bc
ld e, [hl]
inc hl
ld d, [hl]
; skip pointer
inc de
inc de
; update address
ld [hl], d
dec hl
ld [hl], e
ret
2015-12-07 08:28:58 -08:00
.jump
; reset jump flag
2015-12-06 19:36:09 -08:00
ld [hl], 0
; de = pointer
call GetMusicByte
ld e, a
call GetMusicByte
ld d, a
; update address
ld hl, Channel1MusicAddress - Channel1
add hl, bc
ld [hl], e
inc hl
ld [hl], d
ret
2015-12-07 08:28:58 -08:00
; e886d
MusicF9: ; e886d
; sets some flag
; seems to be unused
; params: 0
2015-12-06 19:36:09 -08:00
ld a, 1
ld [wc2b5], a
ret
2015-12-07 08:28:58 -08:00
; e8873
MusicE2: ; e8873
; seems to have been dummied out
; params: 1
call GetMusicByte
2015-12-06 19:36:09 -08:00
ld hl, Channel1Field0x2c - Channel1
add hl, bc
ld [hl], a
ld hl, Channel1Flags2 - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
set SOUND_UNKN_0B, [hl]
ret
2015-12-07 08:28:58 -08:00
; e8882
2015-12-06 19:36:09 -08:00
Music_Vibrato: ; e8882
; vibrato
; params: 2
; 1: [xx]
; delay in frames
; 2: [yz]
; y: extent
; z: rate (# frames per cycle)
; set vibrato flag?
ld hl, Channel1Flags2 - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
set SOUND_VIBRATO, [hl]
; start at lower frequency (extent is positive)
ld hl, Channel1Flags3 - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
res SOUND_VIBRATO_DIR, [hl]
; get delay
call GetMusicByte
; update delay
ld hl, Channel1VibratoDelay - Channel1
add hl, bc
ld [hl], a
; update delay count
ld hl, Channel1VibratoDelayCount - Channel1
add hl, bc
ld [hl], a
; update extent
; this is split into halves only to get added back together at the last second
; get extent/rate
call GetMusicByte
ld hl, Channel1VibratoExtent - Channel1
add hl, bc
ld d, a
; get top nybble
2015-12-06 19:36:09 -08:00
and $f0
swap a
srl a ; halve
ld e, a
2015-12-06 19:36:09 -08:00
adc a, 0; round up
swap a
or e
ld [hl], a
; update rate
ld hl, Channel1VibratoRate - Channel1
add hl, bc
; get bottom nybble
ld a, d
2015-12-06 19:36:09 -08:00
and $f
ld d, a
swap a
or d
ld [hl], a
ret
2015-12-07 08:28:58 -08:00
; e88bd
2016-05-10 11:33:24 -07:00
Music_SlidePitchTo: ; e88bd
; set the target for pitch wheel
; params: 2
; note duration
; target note
call GetMusicByte
2016-05-10 11:33:24 -07:00
ld [wCurNoteDuration], a
2015-12-06 19:36:09 -08:00
call GetMusicByte
; pitch in e
ld d, a
2015-12-06 19:36:09 -08:00
and $f
ld e, a
2015-12-06 19:36:09 -08:00
; octave in d
ld a, d
swap a
2015-12-06 19:36:09 -08:00
and $f
ld d, a
call GetFrequency
2016-05-10 11:33:24 -07:00
ld hl, Channel1PitchWheelTarget - Channel1
add hl, bc
ld [hl], e
2016-05-10 11:33:24 -07:00
ld hl, Channel1PitchWheelTarget + 1 - Channel1
add hl, bc
ld [hl], d
ld hl, Channel1Flags2 - Channel1
add hl, bc
2016-05-10 11:33:24 -07:00
set SOUND_PITCH_WHEEL, [hl]
ret
2015-12-07 08:28:58 -08:00
; e88e4
2015-12-06 19:36:09 -08:00
Music_Tone: ; e88e4
; tone
; params: 1 (dw)
ld hl, Channel1Flags2 - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
set SOUND_CRY_PITCH, [hl]
ld hl, Channel1CryPitch + 1 - Channel1
add hl, bc
call GetMusicByte
ld [hld], a
call GetMusicByte
ld [hl], a
ret
2015-12-07 08:28:58 -08:00
; e88f7
MusicE7: ; e88f7
2015-12-08 13:06:13 -08:00
; unused
; params: 1
ld hl, Channel1Flags2 - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
set SOUND_UNKN_0E, [hl]
call GetMusicByte
2015-12-06 19:36:09 -08:00
ld hl, Channel1Field0x29 - Channel1
add hl, bc
ld [hl], a
ret
2015-12-07 08:28:58 -08:00
; e8906
2016-05-10 13:38:40 -07:00
Music_SoundDuty: ; e8906
; sequence of 4 duty cycles to be looped
; params: 1 (4 2-bit duty cycle arguments)
ld hl, Channel1Flags2 - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
set SOUND_DUTY, [hl] ; duty cycle
2016-05-10 13:38:40 -07:00
; sound duty sequence
call GetMusicByte
rrca
rrca
2016-05-10 13:38:40 -07:00
ld hl, Channel1SFXDutyLoop - Channel1
add hl, bc
ld [hl], a
; update duty cycle
2015-12-06 19:36:09 -08:00
and $c0 ; only uses top 2 bits
ld hl, Channel1DutyCycle - Channel1
add hl, bc
ld [hl], a
ret
2015-12-07 08:28:58 -08:00
; e891e
MusicE8: ; e891e
2015-12-08 13:06:13 -08:00
; unused
; params: 1
ld hl, Channel1Flags2 - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
set SOUND_UNKN_0D, [hl]
call GetMusicByte
2015-12-06 19:36:09 -08:00
ld hl, Channel1Field0x2a - Channel1
add hl, bc
ld [hl], a
ret
2015-12-07 08:28:58 -08:00
; e892d
2015-12-06 19:36:09 -08:00
Music_ToggleSFX: ; e892d
; toggle something
; params: none
ld hl, Channel1Flags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
bit SOUND_SFX, [hl]
jr z, .on
2015-12-07 15:33:04 -08:00
res SOUND_SFX, [hl]
ret
2015-12-07 08:28:58 -08:00
.on
2015-12-07 15:33:04 -08:00
set SOUND_SFX, [hl]
ret
2015-12-07 08:28:58 -08:00
; e893b
2015-12-06 19:36:09 -08:00
Music_ToggleNoise: ; e893b
; toggle music noise sampling
; can't be used as a straight toggle since the param is not read from on->off
; params:
; noise on: 1
; noise off: 0
; check if noise sampling is on
ld hl, Channel1Flags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
bit SOUND_NOISE, [hl]
jr z, .on
; turn noise sampling off
2015-12-07 15:33:04 -08:00
res SOUND_NOISE, [hl]
ret
2015-12-07 08:28:58 -08:00
.on
; turn noise sampling on
2015-12-07 15:33:04 -08:00
set SOUND_NOISE, [hl]
call GetMusicByte
ld [MusicNoiseSampleSet], a
ret
2015-12-07 08:28:58 -08:00
; e894f
2015-12-06 19:36:09 -08:00
Music_SFXToggleNoise: ; e894f
; toggle sfx noise sampling
; params:
; on: 1
; off: 0
; check if noise sampling is on
ld hl, Channel1Flags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
bit SOUND_NOISE, [hl]
jr z, .on
; turn noise sampling off
2015-12-07 15:33:04 -08:00
res SOUND_NOISE, [hl]
ret
2015-12-07 08:28:58 -08:00
.on
; turn noise sampling on
2015-12-07 15:33:04 -08:00
set SOUND_NOISE, [hl]
call GetMusicByte
ld [SFXNoiseSampleSet], a
ret
2015-12-07 08:28:58 -08:00
; e8963
2015-12-06 19:36:09 -08:00
Music_NoteType: ; e8963
; note length
; # frames per 16th note
2015-12-06 19:36:09 -08:00
; intensity: see Music_Intensity
; params: 2
; note length
call GetMusicByte
2015-12-06 19:36:09 -08:00
ld hl, Channel1NoteLength - Channel1
add hl, bc
ld [hl], a
ld a, [CurChannel]
2015-12-06 19:36:09 -08:00
and $3
2017-12-09 10:28:23 -08:00
cp CHAN8 & $3
ret z
; intensity
2015-12-06 19:36:09 -08:00
call Music_Intensity
ret
2015-12-07 08:28:58 -08:00
; e8977
2015-12-06 19:36:09 -08:00
Music_SoundStatus: ; e8977
; update sound status
; params: 1
call GetMusicByte
ld [SoundInput], a
ld hl, Channel1NoteFlags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
set NOTE_UNKN_3, [hl]
ret
2015-12-07 08:28:58 -08:00
; e8984
2015-12-06 19:36:09 -08:00
Music_DutyCycle: ; e8984
; duty cycle
; params: 1
call GetMusicByte
rrca
rrca
2015-12-06 19:36:09 -08:00
and $c0
ld hl, Channel1DutyCycle - Channel1
add hl, bc
ld [hl], a
ret
2015-12-07 08:28:58 -08:00
; e8991
2015-12-06 19:36:09 -08:00
Music_Intensity: ; e8991
; intensity
; params: 1
; hi: pressure
; lo: velocity
call GetMusicByte
ld hl, Channel1Intensity - Channel1
add hl, bc
ld [hl], a
ret
2015-12-07 08:28:58 -08:00
; e899a
2015-12-06 19:36:09 -08:00
Music_Tempo: ; e899a
; global tempo
; params: 2
; de: tempo
call GetMusicByte
ld d, a
call GetMusicByte
ld e, a
call SetGlobalTempo
ret
2015-12-07 08:28:58 -08:00
; e89a6
2015-12-06 19:36:09 -08:00
Music_Octave8: ; e89a6
Music_Octave7: ; e89a6
Music_Octave6: ; e89a6
Music_Octave5: ; e89a6
Music_Octave4: ; e89a6
Music_Octave3: ; e89a6
Music_Octave2: ; e89a6
Music_Octave1: ; e89a6
; set octave based on lo nybble of the command
ld hl, Channel1Octave - Channel1
add hl, bc
2013-11-05 12:17:24 -08:00
ld a, [CurMusicByte]
and 7
ld [hl], a
ret
2015-12-07 08:28:58 -08:00
; e89b1
2015-12-06 19:36:09 -08:00
Music_ForceOctave: ; e89b1
; set starting octave
; this forces all notes up by the starting octave
; params: 1
call GetMusicByte
ld hl, Channel1PitchOffset - Channel1
add hl, bc
ld [hl], a
ret
2015-12-07 08:28:58 -08:00
; e89ba
2015-12-06 19:36:09 -08:00
Music_StereoPanning: ; e89ba
; stereo panning
; params: 1
; stereo on?
ld a, [Options]
2017-12-09 10:28:23 -08:00
bit STEREO, a
2015-12-06 19:36:09 -08:00
jr nz, Music_Panning
; skip param
call GetMusicByte
ret
2015-12-07 08:28:58 -08:00
; e89c5
2015-12-06 19:36:09 -08:00
Music_Panning: ; e89c5
; force panning
; params: 1
call SetLRTracks
call GetMusicByte
ld hl, Channel1Tracks - Channel1
add hl, bc
and [hl]
ld [hl], a
ret
2015-12-07 08:28:58 -08:00
; e89d2
2015-12-06 19:36:09 -08:00
Music_Volume: ; e89d2
; set volume
; params: 1
; see Volume
; read param even if it's not used
call GetMusicByte
; is the song fading?
ld a, [MusicFade]
and a
ret nz
; reload param
ld a, [CurMusicByte]
; set volume
ld [Volume], a
ret
2015-12-07 08:28:58 -08:00
; e89e1
2015-12-08 13:06:13 -08:00
Music_TempoRelative: ; e89e1
; set global tempo to current channel tempo +- param
; params: 1 signed
call GetMusicByte
ld e, a
; check sign
2015-12-06 19:36:09 -08:00
cp $80
jr nc, .negative
;positive
2015-12-06 19:36:09 -08:00
ld d, 0
jr .ok
2015-12-07 15:33:04 -08:00
.negative
2015-12-06 19:36:09 -08:00
ld d, -1
.ok
ld hl, Channel1Tempo - Channel1
add hl, bc
ld a, [hli]
ld h, [hl]
ld l, a
add hl, de
ld e, l
ld d, h
call SetGlobalTempo
ret
2015-12-07 08:28:58 -08:00
; e89fd
2015-12-06 19:36:09 -08:00
Music_SFXPriorityOn: ; e89fd
; turn sfx priority on
; params: none
2015-12-06 19:36:09 -08:00
ld a, 1
ld [SFXPriority], a
ret
2015-12-07 08:28:58 -08:00
; e8a03
2015-12-06 19:36:09 -08:00
Music_SFXPriorityOff: ; e8a03
; turn sfx priority off
; params: none
xor a
ld [SFXPriority], a
ret
2015-12-07 08:28:58 -08:00
; e8a08
2015-12-06 19:36:09 -08:00
Music_RestartChannel: ; e8a08
; restart current channel from channel header (same bank)
; params: 2 (5)
; ll hh: pointer to new channel header
; header format: 0x yy zz
; x: channel # (0-3)
; zzyy: pointer to new music data
; update music id
ld hl, Channel1MusicID - Channel1
add hl, bc
ld a, [hli]
ld [MusicID], a
ld a, [hl]
ld [MusicID + 1], a
; update music bank
ld hl, Channel1MusicBank - Channel1
add hl, bc
ld a, [hl]
ld [MusicBank], a
; get pointer to new channel header
call GetMusicByte
ld l, a
call GetMusicByte
ld h, a
ld e, [hl]
inc hl
ld d, [hl]
push bc ; save current channel
call LoadChannel
call StartChannel
pop bc ; restore current channel
ret
2015-12-07 08:28:58 -08:00
; e8a30
2015-12-06 19:36:09 -08:00
Music_NewSong: ; e8a30
; new song
; params: 2
; de: song id
call GetMusicByte
ld e, a
call GetMusicByte
ld d, a
push bc
2013-10-08 10:26:05 -07:00
call _PlayMusic
pop bc
ret
2015-12-07 08:28:58 -08:00
; e8a3e
GetMusicByte: ; e8a3e
; returns byte from current address in a
; advances to next byte in music data
; input: bc = start of current channel
push hl
push de
; load address into de
ld hl, Channel1MusicAddress - Channel1
add hl, bc
ld a, [hli]
ld e, a
ld d, [hl]
; load bank into a
ld hl, Channel1MusicBank - Channel1
add hl, bc
ld a, [hl]
; get byte
2013-10-08 10:34:32 -07:00
call _LoadMusicByte ; load data into CurMusicByte
inc de ; advance to next byte for next time this is called
; update channeldata address
ld hl, Channel1MusicAddress - Channel1
add hl, bc
ld a, e
ld [hli], a
ld [hl], d
; cleanup
pop de
pop hl
; store channeldata in a
ld a, [CurMusicByte]
ret
2015-12-07 08:28:58 -08:00
; e8a5d
GetFrequency: ; e8a5d
; generate frequency
; input:
; d: octave
; e: pitch
; output:
; de: frequency
; get octave
; get starting octave
ld hl, Channel1PitchOffset - Channel1
add hl, bc
ld a, [hl]
swap a ; hi nybble
2015-12-06 19:36:09 -08:00
and $f
; add current octave
add d
push af ; we'll use this later
; get starting octave
ld hl, Channel1PitchOffset - Channel1
add hl, bc
ld a, [hl]
2015-12-06 19:36:09 -08:00
and $f ; lo nybble
ld l, a ; ok
2015-12-06 19:36:09 -08:00
ld d, 0
ld h, d
add hl, de ; add current pitch
add hl, hl ; skip 2 bytes for each
ld de, FrequencyTable
add hl, de
ld e, [hl]
inc hl
ld d, [hl]
; get our octave
pop af
2015-12-06 19:36:09 -08:00
; shift right by [7 - octave] bits
.loop
; [7 - octave] loops
2015-12-06 19:36:09 -08:00
cp $7
jr nc, .ok
; sra de
sra d
rr e
inc a
jr .loop
2015-12-07 15:33:04 -08:00
.ok
ld a, d
2015-12-06 19:36:09 -08:00
and $7 ; top 3 bits for frequency (11 total)
ld d, a
ret
2015-12-07 08:28:58 -08:00
; e8a8d
SetNoteDuration: ; e8a8d
; input: a = note duration in 16ths
; store delay units in de
inc a
ld e, a
2015-12-06 19:36:09 -08:00
ld d, 0
; store NoteLength in a
ld hl, Channel1NoteLength - Channel1
add hl, bc
ld a, [hl]
; multiply NoteLength by delay units
2015-12-06 19:36:09 -08:00
ld l, 0; just multiply
2015-12-08 13:06:13 -08:00
call .Multiply
ld a, l ; % $100
; store Tempo in de
ld hl, Channel1Tempo - Channel1
add hl, bc
ld e, [hl]
inc hl
ld d, [hl]
; add ???? to the next result
2015-12-06 19:36:09 -08:00
ld hl, Channel1Field0x16 - Channel1
add hl, bc
ld l, [hl]
; multiply Tempo by last result (NoteLength * delay % $100)
2015-12-08 13:06:13 -08:00
call .Multiply
; copy result to de
ld e, l
ld d, h
; store result in ????
2015-12-06 19:36:09 -08:00
ld hl, Channel1Field0x16 - Channel1
add hl, bc
ld [hl], e
; store result in NoteDuration
ld hl, Channel1NoteDuration - Channel1
add hl, bc
ld [hl], d
ret
2015-12-07 08:28:58 -08:00
; e8ab8
2015-12-08 13:06:13 -08:00
.Multiply: ; e8ab8
; multiplies a and de
; adds the result to l
; stores the result in hl
2015-12-06 19:36:09 -08:00
ld h, 0
.loop
; halve a
srl a
; is there a remainder?
jr nc, .skip
; add it to the result
add hl, de
.skip
; add de, de
sla e
rl d
; are we done?
and a
jr nz, .loop
ret
2015-12-07 08:28:58 -08:00
; e8ac7
SetGlobalTempo: ; e8ac7
push bc ; save current channel
; are we dealing with music or sfx?
ld a, [CurChannel]
2015-12-07 08:28:58 -08:00
cp CHAN5
jr nc, .sfxchannels
ld bc, Channel1
2015-12-08 13:06:13 -08:00
call Tempo
ld bc, Channel2
2015-12-08 13:06:13 -08:00
call Tempo
ld bc, Channel3
2015-12-08 13:06:13 -08:00
call Tempo
ld bc, Channel4
2015-12-08 13:06:13 -08:00
call Tempo
jr .end
2015-12-07 15:33:04 -08:00
.sfxchannels
ld bc, Channel5
2015-12-08 13:06:13 -08:00
call Tempo
ld bc, Channel6
2015-12-08 13:06:13 -08:00
call Tempo
ld bc, Channel7
2015-12-08 13:06:13 -08:00
call Tempo
ld bc, Channel8
2015-12-08 13:06:13 -08:00
call Tempo
.end
pop bc ; restore current channel
ret
2015-12-07 08:28:58 -08:00
; e8b03
2015-12-08 13:06:13 -08:00
Tempo: ; e8b03
; input:
; de: note length
; update Tempo
ld hl, Channel1Tempo - Channel1
add hl, bc
ld [hl], e
inc hl
ld [hl], d
; clear ????
xor a
2015-12-06 19:36:09 -08:00
ld hl, Channel1Field0x16 - Channel1
add hl, bc
ld [hl], a
ret
2015-12-07 08:28:58 -08:00
; e8b11
StartChannel: ; e8b11
call SetLRTracks
ld hl, Channel1Flags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
set SOUND_CHANNEL_ON, [hl] ; turn channel on
ret
2015-12-07 08:28:58 -08:00
; e8b1b
SetLRTracks: ; e8b1b
; set tracks for a the current channel to default
; seems to be redundant since this is overwritten by stereo data later
push de
; store current channel in de
ld a, [CurChannel]
2015-12-06 19:36:09 -08:00
and $3
ld e, a
2015-12-06 19:36:09 -08:00
ld d, 0
; get this channel's lr tracks
call GetLRTracks
add hl, de ; de = channel 0-3
ld a, [hl]
; load lr tracks into Tracks
ld hl, Channel1Tracks - Channel1
add hl, bc
ld [hl], a
pop de
ret
2015-12-07 08:28:58 -08:00
; e8b30
_PlayMusic:: ; e8b30
; load music
call MusicOff
ld hl, MusicID
ld [hl], e ; song number
inc hl
ld [hl], d ; (always 0)
ld hl, Music
add hl, de ; three
add hl, de ; byte
add hl, de ; pointer
ld a, [hli]
ld [MusicBank], a
ld e, [hl]
inc hl
ld d, [hl] ; music header address
2013-10-08 10:34:32 -07:00
call LoadMusicByte ; store first byte of music header in a
rlca
rlca
2015-12-06 19:36:09 -08:00
and $3 ; get number of channels
inc a
.loop
; start playing channels
push af
call LoadChannel
call StartChannel
pop af
dec a
jr nz, .loop
xor a
ld [wc2b5], a
2015-12-07 15:33:04 -08:00
ld [Channel1JumpCondition], a
ld [Channel2JumpCondition], a
ld [Channel3JumpCondition], a
ld [Channel4JumpCondition], a
ld [NoiseSampleAddress], a
ld [NoiseSampleAddress + 1], a
2015-12-07 08:28:58 -08:00
ld [wNoiseSampleDelay], a
ld [MusicNoiseSampleSet], a
call MusicOn
ret
2015-12-07 08:28:58 -08:00
; e8b79
_PlayCryHeader:: ; e8b79
2013-02-23 13:47:39 -08:00
; Play cry de using parameters:
; CryPitch
; CryLength
call MusicOff
2013-02-23 13:47:39 -08:00
; Overload the music id with the cry id
ld hl, MusicID
ld [hl], e
inc hl
ld [hl], d
2013-02-23 13:47:39 -08:00
; 3-byte pointers (bank, address)
ld hl, Cries
add hl, de
add hl, de
add hl, de
ld a, [hli]
ld [MusicBank], a
ld e, [hl]
inc hl
ld d, [hl]
2013-02-23 13:47:39 -08:00
; Read the cry's sound header
2013-10-08 10:34:32 -07:00
call LoadMusicByte
2013-02-23 13:47:39 -08:00
; Top 2 bits contain the number of channels
rlca
rlca
2015-12-06 19:36:09 -08:00
and 3
2013-02-23 13:47:39 -08:00
; For each channel:
inc a
.loop
push af
call LoadChannel
ld hl, Channel1Flags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
set SOUND_REST, [hl]
ld hl, Channel1Flags2 - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
set SOUND_CRY_PITCH, [hl]
2013-02-23 13:47:39 -08:00
ld hl, Channel1CryPitch - Channel1
add hl, bc
2013-02-23 13:47:39 -08:00
ld a, [CryPitch]
ld [hli], a
ld a, [CryPitch + 1]
ld [hl], a
2013-02-23 13:47:39 -08:00
; No tempo for channel 4
ld a, [CurChannel]
2015-12-06 19:36:09 -08:00
and 3
2013-02-23 13:47:39 -08:00
cp 3
jr nc, .start
2013-02-23 13:47:39 -08:00
; Tempo is effectively length
ld hl, Channel1Tempo - Channel1
add hl, bc
2013-02-23 13:47:39 -08:00
ld a, [CryLength]
ld [hli], a
2013-02-23 13:47:39 -08:00
ld a, [CryLength+1]
ld [hl], a
.start
call StartChannel
2015-12-23 14:10:50 -08:00
ld a, [wStereoPanningMask]
and a
jr z, .next
2013-02-23 13:47:39 -08:00
; Stereo only: Play cry from the monster's side.
; This only applies in-battle.
ld a, [Options]
2017-12-09 10:28:23 -08:00
bit STEREO, a
jr z, .next
2013-02-23 13:47:39 -08:00
; [Tracks] &= [CryTracks]
ld hl, Channel1Tracks - Channel1
add hl, bc
ld a, [hl]
ld hl, CryTracks
2015-12-06 19:36:09 -08:00
and [hl]
ld hl, Channel1Tracks - Channel1
add hl, bc
ld [hl], a
.next
pop af
dec a
jr nz, .loop
2013-02-23 13:47:39 -08:00
; Cries play at max volume, so we save the current volume for later.
ld a, [LastVolume]
and a
jr nz, .end
ld a, [Volume]
ld [LastVolume], a
2017-12-09 10:28:23 -08:00
ld a, MAX_VOLUME
ld [Volume], a
.end
2013-02-23 13:47:39 -08:00
ld a, 1 ; stop playing music
ld [SFXPriority], a
call MusicOn
ret
2015-12-07 08:28:58 -08:00
; e8c04
_PlaySFX:: ; e8c04
; clear channels if they aren't already
call MusicOff
ld hl, Channel5Flags
2015-12-07 15:33:04 -08:00
bit SOUND_CHANNEL_ON, [hl] ; ch5 on?
jr z, .ch6
2015-12-07 15:33:04 -08:00
res SOUND_CHANNEL_ON, [hl] ; turn it off
xor a
2013-02-19 23:46:40 -08:00
ld [rNR11], a ; length/wavepattern = 0
2015-12-06 19:36:09 -08:00
ld a, $8
2013-02-19 23:46:40 -08:00
ld [rNR12], a ; envelope = 0
xor a
2013-02-19 23:46:40 -08:00
ld [rNR13], a ; frequency lo = 0
ld a, $80
2013-02-19 23:46:40 -08:00
ld [rNR14], a ; restart sound (freq hi = 0)
xor a
ld [SoundInput], a ; global sound off
2013-02-19 23:46:40 -08:00
ld [rNR10], a ; sweep = 0
.ch6
ld hl, Channel6Flags
2015-12-07 15:33:04 -08:00
bit SOUND_CHANNEL_ON, [hl]
jr z, .ch7
2015-12-07 15:33:04 -08:00
res SOUND_CHANNEL_ON, [hl] ; turn it off
xor a
2013-02-19 23:46:40 -08:00
ld [rNR21], a ; length/wavepattern = 0
2015-12-06 19:36:09 -08:00
ld a, $8
2013-02-19 23:46:40 -08:00
ld [rNR22], a ; envelope = 0
xor a
2013-02-19 23:46:40 -08:00
ld [rNR23], a ; frequency lo = 0
ld a, $80
2013-02-19 23:46:40 -08:00
ld [rNR24], a ; restart sound (freq hi = 0)
.ch7
ld hl, Channel7Flags
2015-12-07 15:33:04 -08:00
bit SOUND_CHANNEL_ON, [hl]
jr z, .ch8
2015-12-07 15:33:04 -08:00
res SOUND_CHANNEL_ON, [hl] ; turn it off
xor a
2013-02-19 23:46:40 -08:00
ld [rNR30], a ; sound mode #3 off
ld [rNR31], a ; length/wavepattern = 0
2015-12-06 19:36:09 -08:00
ld a, $8
2013-02-19 23:46:40 -08:00
ld [rNR32], a ; envelope = 0
xor a
2013-02-19 23:46:40 -08:00
ld [rNR33], a ; frequency lo = 0
ld a, $80
2013-02-19 23:46:40 -08:00
ld [rNR34], a ; restart sound (freq hi = 0)
.ch8
ld hl, Channel8Flags
2015-12-07 15:33:04 -08:00
bit SOUND_CHANNEL_ON, [hl]
jr z, .chscleared
2015-12-07 15:33:04 -08:00
res SOUND_CHANNEL_ON, [hl] ; turn it off
xor a
2013-02-19 23:46:40 -08:00
ld [rNR41], a ; length/wavepattern = 0
2015-12-06 19:36:09 -08:00
ld a, $8
2013-02-19 23:46:40 -08:00
ld [rNR42], a ; envelope = 0
xor a
2013-02-19 23:46:40 -08:00
ld [rNR43], a ; frequency lo = 0
ld a, $80
2013-02-19 23:46:40 -08:00
ld [rNR44], a ; restart sound (freq hi = 0)
xor a
ld [NoiseSampleAddress], a
ld [NoiseSampleAddress + 1], a
.chscleared
; start reading sfx header for # chs
ld hl, MusicID
ld [hl], e
inc hl
ld [hl], d
ld hl, SFX
add hl, de ; three
add hl, de ; byte
add hl, de ; pointers
; get bank
ld a, [hli]
ld [MusicBank], a
; get address
ld e, [hl]
inc hl
ld d, [hl]
; get # channels
2013-10-08 10:34:32 -07:00
call LoadMusicByte
rlca ; top 2
rlca ; bits
2015-12-06 19:36:09 -08:00
and $3
inc a ; # channels -> # loops
.startchannels
push af
call LoadChannel ; bc = current channel
ld hl, Channel1Flags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
set SOUND_SFX, [hl]
call StartChannel
pop af
dec a
jr nz, .startchannels
call MusicOn
xor a
ld [SFXPriority], a
ret
2015-12-07 08:28:58 -08:00
; e8ca6
PlayStereoSFX:: ; e8ca6
; play sfx de
call MusicOff
; standard procedure if stereo's off
ld a, [Options]
2017-12-09 10:28:23 -08:00
bit STEREO, a
2013-10-08 10:13:35 -07:00
jp z, _PlaySFX
; else, let's go ahead with this
ld hl, MusicID
ld [hl], e
inc hl
ld [hl], d
; get sfx ptr
ld hl, SFX
add hl, de
add hl, de
add hl, de
; bank
ld a, [hli]
ld [MusicBank], a
; address
ld e, [hl]
inc hl
ld d, [hl]
; bit 2-3
2013-10-08 10:34:32 -07:00
call LoadMusicByte
rlca
rlca
and 3 ; ch1-4
inc a
.loop
push af
call LoadChannel
ld hl, Channel1Flags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
set SOUND_SFX, [hl]
push de
; get tracks for this channel
ld a, [CurChannel]
and 3 ; ch1-4
ld e, a
2015-12-06 19:36:09 -08:00
ld d, 0
call GetLRTracks
add hl, de
ld a, [hl]
2015-12-23 14:10:50 -08:00
ld hl, wStereoPanningMask
and [hl]
ld hl, Channel1Tracks - Channel1
add hl, bc
ld [hl], a
2015-12-06 19:36:09 -08:00
ld hl, Channel1Field0x30 - Channel1 ; $c131 - Channel1
add hl, bc
ld [hl], a
ld a, [CryTracks]
cp 2 ; ch 1-2
2015-12-06 19:36:09 -08:00
jr c, .skip
; ch3-4
2015-12-23 14:10:50 -08:00
ld a, [wSFXDuration]
2015-12-06 19:36:09 -08:00
ld hl, Channel1Field0x2e - Channel1 ; $c12f - Channel1
add hl, bc
ld [hl], a
2015-12-06 19:36:09 -08:00
ld hl, Channel1Field0x2f - Channel1 ; $c130 - Channel1
add hl, bc
ld [hl], a
ld hl, Channel1Flags2 - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
set SOUND_UNKN_0F, [hl]
2015-12-06 19:36:09 -08:00
.skip
pop de
; turn channel on
ld hl, Channel1Flags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
set SOUND_CHANNEL_ON, [hl] ; on
; done?
pop af
dec a
jr nz, .loop
; we're done
call MusicOn
ret
2015-12-07 08:28:58 -08:00
; e8d1b
LoadChannel: ; e8d1b
; prep channel for use
; input:
; de:
; get pointer to current channel
2013-10-08 10:34:32 -07:00
call LoadMusicByte
inc de
2015-12-06 19:36:09 -08:00
and $7 ; bit 0-2 (current channel)
ld [CurChannel], a
ld c, a
2015-12-06 19:36:09 -08:00
ld b, 0
ld hl, ChannelPointers
add hl, bc
add hl, bc
ld c, [hl]
inc hl
ld b, [hl] ; bc = channel pointer
ld hl, Channel1Flags - Channel1
add hl, bc
2015-12-07 15:33:04 -08:00
res SOUND_CHANNEL_ON, [hl] ; channel off
call ChannelInit
; load music pointer
ld hl, Channel1MusicAddress - Channel1
add hl, bc
2013-10-08 10:34:32 -07:00
call LoadMusicByte
ld [hli], a
inc de
2013-10-08 10:34:32 -07:00
call LoadMusicByte
ld [hl], a
inc de
; load music id
ld hl, Channel1MusicID - Channel1
add hl, bc
ld a, [MusicID]
ld [hli], a
ld a, [MusicID + 1]
ld [hl], a
; load music bank
ld hl, Channel1MusicBank - Channel1
add hl, bc
ld a, [MusicBank]
ld [hl], a
ret
2015-12-07 08:28:58 -08:00
; e8d5b
ChannelInit: ; e8d5b
; make sure channel is cleared
; set default tempo and note length in case nothing is loaded
; input:
; bc = channel struct pointer
push de
xor a
; get channel struct location and length
ld hl, Channel1MusicID - Channel1 ; start
add hl, bc
ld e, Channel2 - Channel1 ; channel struct length
; clear channel
.loop
ld [hli], a
dec e
jr nz, .loop
; set tempo to default ($100)
ld hl, Channel1Tempo - Channel1
add hl, bc
xor a
ld [hli], a
inc a
ld [hl], a
2015-12-06 19:36:09 -08:00
; set note length to default ($1) (fast)
ld hl, Channel1NoteLength - Channel1
add hl, bc
ld [hl], a
pop de
ret
2015-12-07 08:28:58 -08:00
; e8d76
LoadMusicByte:: ; e8d76
; input:
; de = current music address
; output:
; a = CurMusicByte
ld a, [MusicBank]
2013-10-08 10:34:32 -07:00
call _LoadMusicByte
ld a, [CurMusicByte]
ret
2015-12-07 08:28:58 -08:00
; e8d80
FrequencyTable: ; e8d80
INCLUDE "data/audio/notes.asm"
; e8db2
WaveSamples: ; e8db2
INCLUDE "data/audio/wave_samples.asm"
; e8e52
INCLUDE "audio/drumkits.asm"
GetLRTracks: ; e8fc2
; gets the default sound l/r channels
; stores mono/stereo table in hl
ld a, [Options]
2017-12-09 10:28:23 -08:00
bit STEREO, a
; made redundant, could have had a purpose in gold
jr nz, .stereo
ld hl, MonoTracks
ret
2015-12-07 08:28:58 -08:00
.stereo
ld hl, StereoTracks
ret
2015-12-07 08:28:58 -08:00
; e8fd1
MonoTracks: ; e8fd1
; bit corresponds to track #
; hi: left channel
; lo: right channel
db $11, $22, $44, $88
; e8fd5
StereoTracks: ; e8fd5
; made redundant
; seems to be modified on a per-song basis
db $11, $22, $44, $88
; e8fd9
ChannelPointers: ; e8fd9
; music channels
dw Channel1
dw Channel2
dw Channel3
dw Channel4
; sfx channels
dw Channel5
dw Channel6
dw Channel7
dw Channel8
; e8fe9
ClearChannels:: ; e8fe9
; runs ClearChannel for all 4 channels
2015-11-11 20:38:57 -08:00
; doesn't seem to be used, but functionally identical to MapSetup_Sound_Off
2013-02-19 23:46:40 -08:00
ld hl, rNR50
xor a
ld [hli], a
ld [hli], a
ld a, $80
ld [hli], a
2013-02-19 23:46:40 -08:00
ld hl, rNR10
2017-12-09 10:28:23 -08:00
ld e, NUM_MUSIC_CHANS
.loop
call ClearChannel
dec e
jr nz, .loop
ret
2015-12-07 08:28:58 -08:00
; e8ffe
ClearChannel: ; e8ffe
; input: hl = beginning hw sound register (rNR10, rNR20, rNR30, rNR40)
; output: 00 00 80 00 80
; sound channel 1 2 3 4
xor a
ld [hli], a ; rNR10, rNR20, rNR30, rNR40 ; sweep = 0
2013-02-19 23:46:40 -08:00
ld [hli], a ; rNR11, rNR21, rNR31, rNR41 ; length/wavepattern = 0
2015-12-06 19:36:09 -08:00
ld a, $8
2013-02-19 23:46:40 -08:00
ld [hli], a ; rNR12, rNR22, rNR32, rNR42 ; envelope = 0
xor a
2013-02-19 23:46:40 -08:00
ld [hli], a ; rNR13, rNR23, rNR33, rNR43 ; frequency lo = 0
ld a, $80
2013-02-19 23:46:40 -08:00
ld [hli], a ; rNR14, rNR24, rNR34, rNR44 ; restart sound (freq hi = 0)
ret
2015-12-07 08:28:58 -08:00
; e900a
PlayTrainerEncounterMusic:: ; e900a
; input: e = trainer type
; turn fade off
xor a
ld [MusicFade], a
; play nothing for one frame
push de
ld de, 0 ; id: Music_Nothing
call PlayMusic
call DelayFrame
; play new song
call MaxVolume
pop de
ld d, $00
ld hl, TrainerEncounterMusic
add hl, de
ld e, [hl]
call PlayMusic
ret
; e9027