diff options
Diffstat (limited to 'audio/engine_3.asm')
-rw-r--r-- | audio/engine_3.asm | 1569 |
1 files changed, 17 insertions, 1552 deletions
diff --git a/audio/engine_3.asm b/audio/engine_3.asm index 57618486..10893868 100644 --- a/audio/engine_3.asm +++ b/audio/engine_3.asm @@ -1,1415 +1,19 @@ ; The third of three duplicated sound engines. -Audio3_UpdateMusic:: - ld c, Ch1 -.loop - ld b, 0 - ld hl, wChannelSoundIDs - add hl, bc - ld a, [hl] - and a - jr z, .nextChannel - ld a, c - cp Ch5 - jr nc, .applyAffects ; if sfx channel - ld a, [wMuteAudioAndPauseMusic] - and a - jr z, .applyAffects - bit 7, a - jr nz, .nextChannel - set 7, a - ld [wMuteAudioAndPauseMusic], a - xor a ; disable all channels' output - ldh [rNR51], a - ldh [rNR30], a - ld a, $80 - ldh [rNR30], a - jr .nextChannel -.applyAffects - call Audio3_ApplyMusicAffects -.nextChannel - ld a, c - inc c ; inc channel number - cp Ch8 - jr nz, .loop - ret - -; this routine checks flags for music effects currently applied -; to the channel and calls certain functions based on flags. -Audio3_ApplyMusicAffects: - ld b, $0 - ld hl, wChannelNoteDelayCounters ; delay until next note - add hl, bc - ld a, [hl] - cp 1 ; if the delay is 1, play next note - jp z, Audio3_PlayNextNote - dec a ; otherwise, decrease the delay timer - ld [hl], a - ld a, c - cp Ch5 - jr nc, .startChecks ; if a sfx channel - ld hl, wChannelSoundIDs + Ch5 - add hl, bc - ld a, [hl] - and a - jr z, .startChecks - ret -.startChecks - ld hl, wChannelFlags1 - add hl, bc - bit BIT_ROTATE_DUTY_CYCLE, [hl] - jr z, .checkForExecuteMusic - call Audio3_ApplyDutyCyclePattern -.checkForExecuteMusic - ld b, 0 - ld hl, wChannelFlags2 - add hl, bc - bit BIT_EXECUTE_MUSIC, [hl] - jr nz, .checkForPitchSlide - ld hl, wChannelFlags1 - add hl, bc - bit BIT_NOISE_OR_SFX, [hl] - jr nz, .skipPitchSlideVibrato -.checkForPitchSlide - ld hl, wChannelFlags1 - add hl, bc - bit BIT_PITCH_SLIDE_ON, [hl] - jr z, .checkVibratoDelay - jp Audio3_ApplyPitchSlide -.checkVibratoDelay - ld hl, wChannelVibratoDelayCounters - add hl, bc - ld a, [hl] - and a ; check if delay is over - jr z, .checkForVibrato - dec [hl] ; otherwise, dec delay -.skipPitchSlideVibrato - ret -.checkForVibrato - ld hl, wChannelVibratoExtents - add hl, bc - ld a, [hl] - and a - jr nz, .vibrato - ret ; no vibrato -.vibrato - ld d, a - ld hl, wChannelVibratoRates - add hl, bc - ld a, [hl] - and $f - and a - jr z, .applyVibrato - dec [hl] ; decrement counter - ret -.applyVibrato - ld a, [hl] - swap [hl] - or [hl] - ld [hl], a ; reload the counter - ld hl, wChannelFrequencyLowBytes - add hl, bc - ld e, [hl] ; get note pitch - ld hl, wChannelFlags1 - 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] - ld a, d - and $f - ld d, a - ld a, e - sub d - jr nc, .noCarry - ld a, 0 -.noCarry - jr .done -.unset - set BIT_VIBRATO_DIRECTION, [hl] - 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 Audio3_GetRegisterPointer - 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 -; until the first note is reached -Audio3_PlayNextNote: -; reload the vibrato delay counter - ld hl, wChannelVibratoDelayCounterReloadValues - add hl, bc - ld a, [hl] - ld hl, wChannelVibratoDelayCounters - add hl, bc - ld [hl], a - - ld hl, wChannelFlags1 - add hl, bc - res BIT_PITCH_SLIDE_ON, [hl] - res BIT_PITCH_SLIDE_DECREASING, [hl] - call Audio3_sound_ret - ret - -Audio3_sound_ret: - call Audio3_GetNextMusicByte - ld d, a - cp sound_ret_cmd - jp nz, Audio3_sound_call - ld b, 0 - ld hl, wChannelFlags1 - add hl, bc - bit BIT_SOUND_CALL, [hl] - jr nz, .returnFromCall - ld a, c - cp Ch4 - jr nc, .noiseOrSfxChannel - jr .disableChannelOutput -.noiseOrSfxChannel - res BIT_NOISE_OR_SFX, [hl] - ld hl, wChannelFlags2 - add hl, bc - res BIT_EXECUTE_MUSIC, [hl] - cp Ch7 - jr nz, .skipSfxChannel3 -; restart hardware channel 3 (wave channel) output - ld a, $0 - ldh [rNR30], a - ld a, $80 - ldh [rNR30], a -.skipSfxChannel3 - jr nz, .dontDisable - ld a, [wDisableChannelOutputWhenSfxEnds] - and a - jr z, .dontDisable - xor a - ld [wDisableChannelOutputWhenSfxEnds], a - jr .disableChannelOutput -.dontDisable - jr .afterDisable -.returnFromCall - res 1, [hl] - ld d, $0 - ld a, c - add a - ld e, a - ld hl, wChannelCommandPointers - add hl, de - push hl ; store current channel address - ld hl, wChannelReturnAddresses - 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 Audio3_sound_ret -.disableChannelOutput - ld hl, Audio3_HWChannelDisableMasks - add hl, bc - ldh a, [rNR51] - and [hl] - ldh [rNR51], a -.afterDisable - ld a, [wChannelSoundIDs + Ch5] - cp CRY_SFX_START - jr nc, .maybeCry - jr .skipCry -.maybeCry - ld a, [wChannelSoundIDs + Ch5] - cp CRY_SFX_END - jr z, .skipCry - jr c, .cry - jr .skipCry -.cry - ld a, c - cp Ch5 - jr z, .skipRewind - call Audio3_GoBackOneCommandIfCry - ret c -.skipRewind - ld a, [wSavedVolume] - ldh [rNR50], a - xor a - ld [wSavedVolume], a -.skipCry - ld hl, wChannelSoundIDs - add hl, bc - ld [hl], b - ret - -Audio3_sound_call: - cp sound_call_cmd - jp nz, Audio3_sound_loop - call Audio3_GetNextMusicByte - push af - call Audio3_GetNextMusicByte - ld d, a - pop af - ld e, a - push de ; store pointer - ld d, $0 - ld a, c - add a - ld e, a - ld hl, wChannelCommandPointers - add hl, de - push hl - ld hl, wChannelReturnAddresses - 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 - ld hl, wChannelFlags1 - add hl, bc - set BIT_SOUND_CALL, [hl] ; set the call flag - jp Audio3_sound_ret - -Audio3_sound_loop: - cp sound_loop_cmd - jp nz, Audio3_note_type - call Audio3_GetNextMusicByte - ld e, a - and a - jr z, .infiniteLoop - ld b, 0 - ld hl, wChannelLoopCounters - add hl, bc - ld a, [hl] - cp e - jr nz, .loopAgain - ld a, $1 ; if no more loops to make, - ld [hl], a - call Audio3_GetNextMusicByte ; skip pointer - call Audio3_GetNextMusicByte - jp Audio3_sound_ret -.loopAgain ; inc loop count - inc a - ld [hl], a - ; fall through -.infiniteLoop ; overwrite current address with pointer - call Audio3_GetNextMusicByte - push af - call Audio3_GetNextMusicByte - ld b, a - ld d, $0 - ld a, c - add a - ld e, a - ld hl, wChannelCommandPointers - add hl, de - pop af - ld [hli], a - ld [hl], b - jp Audio3_sound_ret - -Audio3_note_type: - and $f0 - cp note_type_cmd - jp nz, Audio3_toggle_perfect_pitch - ld a, d - and $f - ld b, $0 - ld hl, wChannelNoteSpeeds - add hl, bc - ld [hl], a ; store low nibble as speed - ld a, c - cp Ch4 - jr z, .noiseChannel ; noise channel has 0 params - call Audio3_GetNextMusicByte - ld d, a - ld a, c - cp Ch3 - jr z, .musicChannel3 - cp Ch7 - jr nz, .skipChannel3 - ld hl, wSfxWaveInstrument - jr .channel3 -.musicChannel3 - ld hl, wMusicWaveInstrument -.channel3 - ld a, d - and $f - ld [hl], a ; store low nibble of param as wave instrument - 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 - ld hl, wChannelVolumes - add hl, bc - ld [hl], d -.noiseChannel - jp Audio3_sound_ret - -Audio3_toggle_perfect_pitch: - ld a, d - cp toggle_perfect_pitch_cmd - jr nz, Audio3_vibrato - ld b, 0 - ld hl, wChannelFlags1 - add hl, bc - ld a, [hl] - xor $1 - ld [hl], a ; flip bit 0 of wChannelFlags1 - jp Audio3_sound_ret - -Audio3_vibrato: - cp vibrato_cmd - jr nz, Audio3_pitch_slide - call Audio3_GetNextMusicByte - ld b, 0 - ld hl, wChannelVibratoDelayCounters - add hl, bc - ld [hl], a ; store delay - ld hl, wChannelVibratoDelayCounterReloadValues - add hl, bc - ld [hl], a ; store delay - call Audio3_GetNextMusicByte - 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. - and $f0 - swap a - ld b, 0 - ld hl, wChannelVibratoExtents - 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. - ld a, d - and $f - ld d, a - ld hl, wChannelVibratoRates - add hl, bc - swap a - or d - ld [hl], a - - jp Audio3_sound_ret - -Audio3_pitch_slide: - cp pitch_slide_cmd - jr nz, Audio3_duty_cycle - call Audio3_GetNextMusicByte - ld b, 0 - ld hl, wChannelPitchSlideLengthModifiers - add hl, bc - ld [hl], a - call Audio3_GetNextMusicByte - ld d, a - and $f0 - swap a - ld b, a - ld a, d - and $f - call Audio3_CalculateFrequency - ld b, 0 - ld hl, wChannelPitchSlideTargetFrequencyHighBytes - add hl, bc - ld [hl], d - ld hl, wChannelPitchSlideTargetFrequencyLowBytes - add hl, bc - ld [hl], e - ld b, 0 - ld hl, wChannelFlags1 - add hl, bc - set BIT_PITCH_SLIDE_ON, [hl] - call Audio3_GetNextMusicByte - ld d, a - jp Audio3_note_length - -Audio3_duty_cycle: - cp duty_cycle_cmd - jr nz, Audio3_tempo - call Audio3_GetNextMusicByte - rrca - rrca - and $c0 - ld b, 0 - ld hl, wChannelDutyCycles - add hl, bc - ld [hl], a ; store duty cycle - jp Audio3_sound_ret - -Audio3_tempo: - cp tempo_cmd - jr nz, Audio3_stereo_panning - ld a, c - cp Ch5 - jr nc, .sfxChannel - call Audio3_GetNextMusicByte - ld [wMusicTempo], a ; store first param - call Audio3_GetNextMusicByte - ld [wMusicTempo + 1], a ; store second param - xor a - ld [wChannelNoteDelayCountersFractionalPart], a ; clear RAM - ld [wChannelNoteDelayCountersFractionalPart + 1], a - ld [wChannelNoteDelayCountersFractionalPart + 2], a - ld [wChannelNoteDelayCountersFractionalPart + 3], a - jr .musicChannelDone -.sfxChannel - call Audio3_GetNextMusicByte - ld [wSfxTempo], a ; store first param - call Audio3_GetNextMusicByte - ld [wSfxTempo + 1], a ; store second param - xor a - ld [wChannelNoteDelayCountersFractionalPart + 4], a ; clear RAM - ld [wChannelNoteDelayCountersFractionalPart + 5], a - ld [wChannelNoteDelayCountersFractionalPart + 6], a - ld [wChannelNoteDelayCountersFractionalPart + 7], a -.musicChannelDone - jp Audio3_sound_ret - -Audio3_stereo_panning: - cp stereo_panning_cmd - jr nz, Audio3_unknownmusic0xef - call Audio3_GetNextMusicByte - ld [wStereoPanning], a ; store panning - jp Audio3_sound_ret - -; this appears to never be used -Audio3_unknownmusic0xef: - cp unknownmusic0xef_cmd - jr nz, Audio3_duty_cycle_pattern - call Audio3_GetNextMusicByte - push bc - call Audio3_PlaySound - pop bc - ld a, [wDisableChannelOutputWhenSfxEnds] - and a - jr nz, .skip - ld a, [wChannelSoundIDs + Ch8] - ld [wDisableChannelOutputWhenSfxEnds], a - xor a - ld [wChannelSoundIDs + Ch8], a -.skip - jp Audio3_sound_ret - -Audio3_duty_cycle_pattern: - cp duty_cycle_pattern_cmd - jr nz, Audio3_volume - call Audio3_GetNextMusicByte - ld b, 0 - ld hl, wChannelDutyCyclePatterns - add hl, bc - ld [hl], a ; store full pattern - and %11000000 - ld hl, wChannelDutyCycles - add hl, bc - ld [hl], a ; store first duty cycle - ld hl, wChannelFlags1 - add hl, bc - set BIT_ROTATE_DUTY_CYCLE, [hl] - jp Audio3_sound_ret - -Audio3_volume: - cp volume_cmd - jr nz, Audio3_execute_music - call Audio3_GetNextMusicByte - ldh [rNR50], a ; store volume - jp Audio3_sound_ret - -Audio3_execute_music: - cp execute_music_cmd - jr nz, Audio3_octave - ld b, $0 - ld hl, wChannelFlags2 - add hl, bc - set BIT_EXECUTE_MUSIC, [hl] - jp Audio3_sound_ret - -Audio3_octave: - and $f0 - cp octave_cmd - jr nz, Audio3_sfx_note - ld hl, wChannelOctaves - ld b, 0 - add hl, bc - ld a, d - and $f - ld [hl], a ; store low nibble as octave - jp Audio3_sound_ret - -; sfx_note is either square_note or noise_note depending on the channel -Audio3_sfx_note: - cp sfx_note_cmd - jr nz, Audio3_pitch_sweep - ld a, c - cp Ch4 ; is this a noise or sfx channel? - jr c, Audio3_pitch_sweep ; no - ld b, 0 - ld hl, wChannelFlags2 - add hl, bc - bit BIT_EXECUTE_MUSIC, [hl] ; is execute_music being used? - jr nz, Audio3_pitch_sweep ; yes - call Audio3_note_length - -; This code seems to do the same thing as what Audio3_ApplyDutyCycleAndSoundLength -; does below. - ld d, a - ld b, 0 - ld hl, wChannelDutyCycles - add hl, bc - ld a, [hl] - or d - ld d, a - ld b, REG_DUTY_SOUND_LEN - call Audio3_GetRegisterPointer - ld [hl], d - - call Audio3_GetNextMusicByte - ld d, a - ld b, REG_VOLUME_ENVELOPE - call Audio3_GetRegisterPointer - ld [hl], d - call Audio3_GetNextMusicByte - ld e, a - ld a, c - cp Ch8 - 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. - push de - call Audio3_GetNextMusicByte - pop de -.skip - ld d, a - push de - call Audio3_ApplyDutyCycleAndSoundLength - call Audio3_EnableChannelOutput - pop de - call Audio3_ApplyWavePatternAndFrequency - ret - -Audio3_pitch_sweep: - ld a, c - cp Ch5 - jr c, Audio3_note ; if not a sfx - ld a, d - cp pitch_sweep_cmd - jr nz, Audio3_note - ld b, $0 - ld hl, wChannelFlags2 - add hl, bc - bit BIT_EXECUTE_MUSIC, [hl] - jr nz, Audio3_note ; no - call Audio3_GetNextMusicByte - ldh [rNR10], a - jp Audio3_sound_ret - -Audio3_note: - ld a, c - cp Ch4 - jr nz, Audio3_note_length ; if not noise channel - ld a, d - and $f0 - cp drum_note_cmd - jr z, .drum_note - jr nc, Audio3_note_length - - ; this executes when on the noise channel and - ; 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 - swap a - ld b, a - ld a, d - and $f - ld d, a - ld a, b - push de - push bc - jr .playDnote - -.drum_note - ld a, d - and $f - push af - push bc - call Audio3_GetNextMusicByte ; get drum_note instrument -.playDnote - ld d, a - ld a, [wDisableChannelOutputWhenSfxEnds] - and a - jr nz, .skipDnote - ld a, d - call Audio3_PlaySound -.skipDnote - pop bc - pop de - -Audio3_note_length: - ld a, d - push af - and $f - inc a - ld b, 0 - ld e, a ; store note length (in 16ths) - ld d, b - ld hl, wChannelNoteSpeeds - add hl, bc - ld a, [hl] - ld l, b - call Audio3_MultiplyAdd - ld a, c - cp Ch5 - jr nc, .sfxChannel - ld a, [wMusicTempo] - ld d, a - ld a, [wMusicTempo + 1] - ld e, a - jr .skip -.sfxChannel - ld d, $1 - ld e, $0 - cp Ch8 - jr z, .skip ; if noise channel - call Audio3_SetSfxTempo - ld a, [wSfxTempo] - ld d, a - ld a, [wSfxTempo + 1] - ld e, a -.skip - ld a, l ; a = note_length * note_speed - ld b, 0 - ld hl, wChannelNoteDelayCountersFractionalPart - add hl, bc - ld l, [hl] - call Audio3_MultiplyAdd - ld e, l - ld d, h ; de = note_delay_frac_part + (note_length * note_speed * tempo) - ld hl, wChannelNoteDelayCountersFractionalPart - add hl, bc - ld [hl], e - ld a, d - ld hl, wChannelNoteDelayCounters - add hl, bc - ld [hl], a - ld hl, wChannelFlags2 - add hl, bc - bit BIT_EXECUTE_MUSIC, [hl] - jr nz, Audio3_note_pitch - ld hl, wChannelFlags1 - add hl, bc - bit BIT_NOISE_OR_SFX, [hl] - jr z, Audio3_note_pitch - pop hl - ret - -Audio3_note_pitch: - pop af - and $f0 - cp rest_cmd - jr nz, .notRest - ld a, c - cp Ch5 - jr nc, .next -; If this isn't an SFX channel, try the corresponding SFX channel. - ld hl, wChannelSoundIDs + Ch5 - add hl, bc - ld a, [hl] - and a - jr nz, .done - ; fall through -.next - ld a, c - cp Ch3 - jr z, .channel3 - cp Ch7 - jr nz, .notChannel3 -.channel3 - ld b, 0 - ld hl, Audio3_HWChannelDisableMasks - add hl, bc - ldh a, [rNR51] - and [hl] - ldh [rNR51], a ; disable hardware channel 3's output - jr .done -.notChannel3 - ld b, REG_VOLUME_ENVELOPE - call Audio3_GetRegisterPointer - ld a, $8 ; fade in sound - ld [hli], a - inc hl - ld a, $80 ; restart sound - ld [hl], a -.done - ret -.notRest - swap a - ld b, 0 - ld hl, wChannelOctaves - add hl, bc - ld b, [hl] - call Audio3_CalculateFrequency - ld b, 0 - ld hl, wChannelFlags1 - add hl, bc - bit BIT_PITCH_SLIDE_ON, [hl] - jr z, .skipPitchSlide - call Audio3_InitPitchSlideVars -.skipPitchSlide - push de - ld a, c - cp Ch5 - jr nc, .sfxChannel ; if sfx channel -; If this isn't an SFX channel, try the corresponding SFX channel. - ld hl, wChannelSoundIDs + Ch5 - ld d, 0 - ld e, a - add hl, de - ld a, [hl] - and a - jr nz, .noSfx - jr .sfxChannel -.noSfx - pop de - ret -.sfxChannel - ld b, 0 - ld hl, wChannelVolumes - add hl, bc - ld d, [hl] - ld b, REG_VOLUME_ENVELOPE - call Audio3_GetRegisterPointer - ld [hl], d - call Audio3_ApplyDutyCycleAndSoundLength - call Audio3_EnableChannelOutput - pop de - ld b, $0 - ld hl, wChannelFlags1 - 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 - inc d -.skipFrequencyInc - ld hl, wChannelFrequencyLowBytes - add hl, bc - ld [hl], e - call Audio3_ApplyWavePatternAndFrequency - ret - -Audio3_EnableChannelOutput: - ld b, 0 - ld hl, Audio3_HWChannelEnableMasks - add hl, bc - ldh a, [rNR51] - or [hl] ; set this channel's bits - ld d, a - ld a, c - cp Ch8 - jr z, .noiseChannelOrNoSfx - cp Ch5 - jr nc, .skip ; if sfx channel -; If this isn't an SFX channel, try the corresponding SFX channel. - ld hl, wChannelSoundIDs + Ch5 - 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. - ld a, [wStereoPanning] - ld hl, Audio3_HWChannelEnableMasks - add hl, bc - and [hl] - ld d, a - ldh a, [rNR51] - ld hl, Audio3_HWChannelDisableMasks - add hl, bc - and [hl] ; reset this channel's output bits - or d ; set this channel's output bits that enabled in [wStereoPanning] - ld d, a -.skip - ld a, d - ldh [rNR51], a - ret - -Audio3_ApplyDutyCycleAndSoundLength: - ld b, 0 - ld hl, wChannelNoteDelayCounters ; use the note delay as sound length - add hl, bc - ld d, [hl] - ld a, c - cp Ch3 - jr z, .skipDuty ; if music channel 3 - cp Ch7 - jr z, .skipDuty ; if sfx channel 3 -; include duty cycle (except on channel 3 which doesn't have it) - ld a, d - and $3f - ld d, a - ld hl, wChannelDutyCycles - add hl, bc - ld a, [hl] - or d - ld d, a -.skipDuty - ld b, REG_DUTY_SOUND_LEN - call Audio3_GetRegisterPointer - ld [hl], d - ret - -Audio3_ApplyWavePatternAndFrequency: - ld a, c - cp Ch3 - jr z, .channel3 - cp Ch7 - jr nz, .notChannel3 - ; fall through -.channel3 - push de - ld de, wMusicWaveInstrument - cp Ch3 - jr z, .next - ld de, wSfxWaveInstrument -.next - ld a, [de] - add a - ld d, 0 - ld e, a - ld hl, Audio3_WavePointers - add hl, de - ld e, [hl] - inc hl - ld d, [hl] - ld hl, rWave_0 - ld b, $f - ld a, $0 ; stop hardware channel 3 - ldh [rNR30], a -.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 - pop de -.notChannel3 - 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 - ld d, a - ld b, REG_FREQUENCY_LO - call Audio3_GetRegisterPointer - ld [hl], e ; store frequency low byte - inc hl - ld [hl], d ; store frequency high byte - call Audio3_ApplyFrequencyModifier - ret - -Audio3_SetSfxTempo: - call Audio3_IsCry - jr nc, .notCry - ld d, 0 - ld a, [wTempoModifier] - add $80 - jr nc, .next - inc d -.next - ld [wSfxTempo + 1], a - ld a, d - ld [wSfxTempo], a - jr .done -.notCry - xor a - ld [wSfxTempo + 1], a - ld a, $1 - ld [wSfxTempo], a -.done - ret - -Audio3_ApplyFrequencyModifier: - call Audio3_IsCry - jr nc, .done -; if playing a cry, add the cry's frequency modifier - ld a, [wFrequencyModifier] - add e - jr nc, .noCarry - inc d -.noCarry - dec hl - ld e, a - ld [hl], e - inc hl - ld [hl], d -.done - ret - -Audio3_GoBackOneCommandIfCry: - call Audio3_IsCry - jr nc, .done - ld hl, wChannelCommandPointers - ld e, c - ld d, 0 - sla e - rl d - add hl, de - ld a, [hl] - sub 1 - ld [hl], a - inc hl - ld a, [hl] - sbc 0 - ld [hl], a - scf - ret -.done - scf - ccf - ret - -Audio3_IsCry: -; Returns whether the currently playing audio is a cry in carry. - ld a, [wChannelSoundIDs + Ch5] - cp CRY_SFX_START - jr nc, .next - jr .no -.next - cp CRY_SFX_END - jr z, .no - jr c, .yes -.no - scf - ccf - ret -.yes - scf - ret - -Audio3_ApplyPitchSlide: - ld hl, wChannelFlags1 - add hl, bc - bit BIT_PITCH_SLIDE_DECREASING, [hl] - jp nz, .frequencyDecreasing -; frequency increasing - ld hl, wChannelPitchSlideCurrentFrequencyLowBytes - add hl, bc - ld e, [hl] - ld hl, wChannelPitchSlideCurrentFrequencyHighBytes - add hl, bc - ld d, [hl] - ld hl, wChannelPitchSlideFrequencySteps - add hl, bc - ld l, [hl] - ld h, b - add hl, de - ld d, h - ld e, l - ld hl, wChannelPitchSlideCurrentFrequencyFractionalPart - add hl, bc - push hl - ld hl, wChannelPitchSlideFrequencyStepsFractionalPart - add hl, bc - ld a, [hl] - pop hl - add [hl] - ld [hl], a - ld a, 0 - adc e - ld e, a - ld a, 0 - adc d - ld d, a - ld hl, wChannelPitchSlideTargetFrequencyHighBytes - add hl, bc - ld a, [hl] - cp d - jp c, .reachedTargetFrequency - jr nz, .applyUpdatedFrequency - ld hl, wChannelPitchSlideTargetFrequencyLowBytes - add hl, bc - ld a, [hl] - cp e - jp c, .reachedTargetFrequency - jr .applyUpdatedFrequency -.frequencyDecreasing - ld hl, wChannelPitchSlideCurrentFrequencyLowBytes - add hl, bc - ld a, [hl] - ld hl, wChannelPitchSlideCurrentFrequencyHighBytes - add hl, bc - ld d, [hl] - ld hl, wChannelPitchSlideFrequencySteps - add hl, bc - ld e, [hl] - sub e - ld e, a - ld a, d - sbc b - ld d, a - ld hl, wChannelPitchSlideFrequencyStepsFractionalPart - 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 - add hl, bc - ld a, d - cp [hl] - jr c, .reachedTargetFrequency - jr nz, .applyUpdatedFrequency - ld hl, wChannelPitchSlideTargetFrequencyLowBytes - add hl, bc - ld a, e - cp [hl] - jr c, .reachedTargetFrequency -.applyUpdatedFrequency - ld hl, wChannelPitchSlideCurrentFrequencyLowBytes - add hl, bc - ld [hl], e - ld hl, wChannelPitchSlideCurrentFrequencyHighBytes - add hl, bc - ld [hl], d - ld b, REG_FREQUENCY_LO - call Audio3_GetRegisterPointer - ld a, e - ld [hli], a - ld [hl], d - ret -.reachedTargetFrequency -; Turn off pitch slide when the target frequency has been reached. - ld hl, wChannelFlags1 - add hl, bc - res BIT_PITCH_SLIDE_ON, [hl] - res BIT_PITCH_SLIDE_DECREASING, [hl] - ret - -Audio3_InitPitchSlideVars: - ld hl, wChannelPitchSlideCurrentFrequencyHighBytes - add hl, bc - ld [hl], d - ld hl, wChannelPitchSlideCurrentFrequencyLowBytes - add hl, bc - ld [hl], e - ld hl, wChannelNoteDelayCounters - add hl, bc - ld a, [hl] - ld hl, wChannelPitchSlideLengthModifiers - add hl, bc - sub [hl] - jr nc, .next - ld a, 1 -.next - ld [hl], a - ld hl, wChannelPitchSlideTargetFrequencyLowBytes - add hl, bc - ld a, e - sub [hl] - ld e, a - ld a, d - sbc b - ld hl, wChannelPitchSlideTargetFrequencyHighBytes - add hl, bc - sub [hl] - jr c, .targetFrequencyGreater - ld d, a - ld b, 0 - ld hl, wChannelFlags1 - 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 - add hl, bc - ld d, [hl] - ld hl, wChannelPitchSlideCurrentFrequencyLowBytes - add hl, bc - ld e, [hl] - ld hl, wChannelPitchSlideTargetFrequencyLowBytes - 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. - ld a, d - sbc b - ld d, a - - ld hl, wChannelPitchSlideTargetFrequencyHighBytes - add hl, bc - ld a, [hl] - sub d - ld d, a - ld b, 0 - ld hl, wChannelFlags1 - add hl, bc - res BIT_PITCH_SLIDE_DECREASING, [hl] - -.next2 - ld hl, wChannelPitchSlideLengthModifiers - add hl, bc -.divideLoop - inc b - ld a, e - sub [hl] - ld e, a - jr nc, .divideLoop - ld a, d - and a - jr z, .doneDividing - dec a - ld d, a - jr .divideLoop -.doneDividing - ld a, e ; a = remainder - dividend - add [hl] - ld d, b ; d = quotient + 1 - ld b, 0 - ld hl, wChannelPitchSlideFrequencySteps - add hl, bc - ld [hl], d ; store quotient + 1 - ld hl, wChannelPitchSlideFrequencyStepsFractionalPart - add hl, bc - ld [hl], a ; store remainder - dividend - ld hl, wChannelPitchSlideCurrentFrequencyFractionalPart - add hl, bc - ld [hl], a ; store remainder - dividend - ret - -Audio3_ApplyDutyCyclePattern: - ld b, 0 - ld hl, wChannelDutyCyclePatterns - add hl, bc - ld a, [hl] - rlca - rlca - ld [hl], a - and $c0 - ld d, a - ld b, REG_DUTY_SOUND_LEN - call Audio3_GetRegisterPointer - ld a, [hl] - and $3f - or d - ld [hl], a - ret - -Audio3_GetNextMusicByte: - ld d, 0 - ld a, c - add a - ld e, a - ld hl, wChannelCommandPointers - 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 - -Audio3_GetRegisterPointer: -; hl = address of hardware sound register b for software channel c - ld a, c - ld hl, Audio3_HWChannelBaseAddresses - add l - jr nc, .noCarry - inc h -.noCarry - ld l, a - ld a, [hl] - add b - ld l, a - ld h, $ff - ret - -Audio3_MultiplyAdd: -; hl = l + (a * de) - ld h, 0 -.loop - srl a - jr nc, .skipAdd - add hl, de -.skipAdd - sla e - rl d - and a - jr z, .done - jr .loop -.done - ret - -Audio3_CalculateFrequency: -; return the frequency for note a, octave b in de - ld h, 0 - ld l, a - add hl, hl - ld d, h - ld e, l - ld hl, Audio3_Pitches - add hl, de - ld e, [hl] - inc hl - ld d, [hl] - ld a, b -.loop - cp 7 - jr z, .done - sra d - rr e - inc a - jr .loop -.done - ld a, 8 - add d - ld d, a - ret - Audio3_PlaySound:: ld [wSoundID], a + ld a, [wSoundID] cp SFX_STOP_ALL_MUSIC jp z, .stopAllAudio cp MAX_SFX_ID_3 jp z, .playSfx jp c, .playSfx - cp $fe + cp $fd jr z, .playMusic jp nc, .playSfx .playMusic - xor a - ld [wUnusedC000], a - ld [wDisableChannelOutputWhenSfxEnds], a - ld [wMusicTempo + 1], a - ld [wMusicWaveInstrument], a - ld [wSfxWaveInstrument], a - ld d, NUM_CHANNELS - ld hl, wChannelReturnAddresses - call .FillMem - ld hl, wChannelCommandPointers - call .FillMem - ld d, NUM_MUSIC_CHANS - ld hl, wChannelSoundIDs - call .FillMem - ld hl, wChannelFlags1 - call .FillMem - ld hl, wChannelDutyCycles - call .FillMem - ld hl, wChannelDutyCyclePatterns - call .FillMem - ld hl, wChannelVibratoDelayCounters - call .FillMem - ld hl, wChannelVibratoExtents - call .FillMem - ld hl, wChannelVibratoRates - call .FillMem - ld hl, wChannelFrequencyLowBytes - call .FillMem - ld hl, wChannelVibratoDelayCounterReloadValues - call .FillMem - 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 - ld a, $1 - ld hl, wChannelLoopCounters - call .FillMem - ld hl, wChannelNoteDelayCounters - call .FillMem - ld hl, wChannelNoteSpeeds - call .FillMem - ld [wMusicTempo], a - ld a, $ff - ld [wStereoPanning], a - xor a - ldh [rNR50], a - ld a, $8 - ldh [rNR10], a - ld a, 0 - ldh [rNR51], a - xor a - ldh [rNR30], a - ld a, $80 - ldh [rNR30], a - ld a, $77 - ldh [rNR50], a + call InitMusicVariables jp .playSoundCommon .playSfx @@ -1471,92 +75,7 @@ Audio3_PlaySound:: jr c, .playChannel ret .playChannel - xor a - push de - ld h, d - ld l, e - add hl, hl - ld d, h - ld e, l - ld hl, wChannelReturnAddresses - add hl, de - ld [hli], a - ld [hl], a - ld hl, wChannelCommandPointers - add hl, de - ld [hli], a - ld [hl], a - pop de - ld hl, wChannelSoundIDs - add hl, de - ld [hl], a - ld hl, wChannelFlags1 - add hl, de - ld [hl], a - ld hl, wChannelDutyCycles - add hl, de - ld [hl], a - ld hl, wChannelDutyCyclePatterns - add hl, de - ld [hl], a - ld hl, wChannelVibratoDelayCounters - add hl, de - ld [hl], a - ld hl, wChannelVibratoExtents - add hl, de - ld [hl], a - ld hl, wChannelVibratoRates - add hl, de - ld [hl], a - ld hl, wChannelFrequencyLowBytes - add hl, de - ld [hl], a - ld hl, wChannelVibratoDelayCounterReloadValues - add hl, de - ld [hl], a - ld hl, wChannelPitchSlideLengthModifiers - add hl, de - ld [hl], a - ld hl, wChannelPitchSlideFrequencySteps - add hl, de - ld [hl], a - ld hl, wChannelPitchSlideFrequencyStepsFractionalPart - add hl, de - ld [hl], a - ld hl, wChannelPitchSlideCurrentFrequencyFractionalPart - add hl, de - ld [hl], a - ld hl, wChannelPitchSlideCurrentFrequencyHighBytes - add hl, de - ld [hl], a - ld hl, wChannelPitchSlideCurrentFrequencyLowBytes - add hl, de - ld [hl], a - ld hl, wChannelPitchSlideTargetFrequencyHighBytes - add hl, de - ld [hl], a - ld hl, wChannelPitchSlideTargetFrequencyLowBytes - add hl, de - ld [hl], a - ld hl, wChannelFlags2 - add hl, de - ld [hl], a - ld a, $1 - ld hl, wChannelLoopCounters - add hl, de - ld [hl], a - ld hl, wChannelNoteDelayCounters - add hl, de - ld [hl], a - ld hl, wChannelNoteSpeeds - add hl, de - ld [hl], a - ld a, e - cp Ch5 - jr nz, .skipSweepDisable - ld a, $8 - ldh [rNR10], a ; sweep off -.skipSweepDisable + call InitSFXVariables ld a, c and a jp z, .playSoundCommon @@ -1564,51 +83,7 @@ Audio3_PlaySound:: jp .sfxChannelLoop .stopAllAudio - ld a, $80 - ldh [rNR52], a ; sound hardware on - ldh [rNR30], a ; wave playback on - xor a - ldh [rNR51], a ; no sound output - ldh [rNR32], a ; mute channel 3 (wave channel) - 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) - ld a, $40 - ldh [rNR14], a ; counter mode - ldh [rNR24], a - ldh [rNR44], a - ld a, $77 - ldh [rNR50], a ; full volume - xor a - ld [wUnusedC000], a - ld [wDisableChannelOutputWhenSfxEnds], a - ld [wMuteAudioAndPauseMusic], a - ld [wMusicTempo + 1], a - ld [wSfxTempo + 1], a - ld [wMusicWaveInstrument], a - ld [wSfxWaveInstrument], a - ld d, $a0 - ld hl, wChannelCommandPointers - call .FillMem - ld a, $1 - ld d, $18 - ld hl, wChannelNoteDelayCounters - call .FillMem - ld [wMusicTempo], a - ld [wSfxTempo], a - ld a, $ff - ld [wStereoPanning], a - ret - -; fills d bytes at hl with a -.FillMem - ld b, d -.loop - ld [hli], a - dec b - jr nz, .loop + call StopAllAudio ret .playSoundCommon @@ -1644,16 +119,11 @@ Audio3_PlaySound:: inc hl jr .commandPointerLoop .next + push af push hl push bc - push af ld b, 0 ld c, a - ld hl, wChannelSoundIDs - add hl, bc - ld a, [wSoundID] - ld [hl], a - pop af cp Ch4 jr c, .skipSettingFlag ld hl, wChannelFlags1 @@ -1668,6 +138,17 @@ Audio3_PlaySound:: ld a, [de] ld [hli], a inc de + pop af + push hl + push bc + ld b, 0 + ld c, a + ld hl, wChannelSoundIDs + add hl, bc + ld a, [wSoundID] + ld [hl], a + pop bc + pop hl inc c dec b ld a, b @@ -1708,19 +189,3 @@ Audio3_PlaySound:: Audio3_CryRet: sound_ret - -Audio3_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 - -Audio3_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 - -Audio3_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 - -Audio3_Pitches: -INCLUDE "audio/notes.asm" |