diff options
Diffstat (limited to 'audio/engine_2.asm')
-rw-r--r-- | audio/engine_2.asm | 1741 |
1 files changed, 179 insertions, 1562 deletions
diff --git a/audio/engine_2.asm b/audio/engine_2.asm index 51a5d7c4..65c25c20 100644 --- a/audio/engine_2.asm +++ b/audio/engine_2.asm @@ -2,1407 +2,201 @@ ; This copy has a few differences relating to battle sound effects ; and the low health alarm that plays in battle -Audio2_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 Audio2_ApplyMusicAffects -.nextChannel - ld a, c - inc c ; inc channel number - cp Ch8 - jr nz, .loop - ret +Audio2_PlaySound:: + ld [wSoundID], a + ld a, [wSoundID] + cp SFX_STOP_ALL_MUSIC + jp z, .stopAllAudio + cp MAX_SFX_ID_2 + jp z, .playSfx + jp c, .playSfx + cp $fe + jr z, .playMusic + jp nc, .playSfx -; this routine checks flags for music effects currently applied -; to the channel and calls certain functions based on flags. -Audio2_ApplyMusicAffects: - ld b, $0 - ld hl, wChannelNoteDelayCounters ; delay until next note - add hl, bc +.playMusic + call InitMusicVariables + jp .playSoundCommon + +.playSfx + ld l, a + ld e, a + ld h, 0 + ld d, h + add hl, hl + add hl, de + ld de, SFX_Headers_2 + add hl, de + ld a, h + ld [wSfxHeaderPointer], a + ld a, l + ld [wSfxHeaderPointer + 1], a ld a, [hl] - cp 1 ; if the delay is 1, play next note - jp z, Audio2_PlayNextNote - dec a ; otherwise, decrease the delay timer - ld [hl], a + and $c0 + rlca + rlca + ld c, a +.sfxChannelLoop + ld d, c 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 Audio2_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 Audio2_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 a + add c + ld c, a + ld b, $0 + ld a, [wSfxHeaderPointer] + ld h, a + ld a, [wSfxHeaderPointer + 1] + ld l, a add hl, bc + ld c, d ld a, [hl] and $f - and a - jr z, .applyVibrato - dec [hl] ; decrement counter - ret -.applyVibrato + ld e, a ; software channel ID + ld d, 0 + ld hl, wChannelSoundIDs + add hl, de 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 + and a + jr z, .playChannel 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 Audio2_GetRegisterPointer - ld [hl], d + cp Ch8 + jr nz, .notNoiseChannel + ld a, [wSoundID] + cp NOISE_INSTRUMENTS_END + jr nc, .notNoiseInstrument 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 -Audio2_PlayNextNote: -; reload the vibrato delay counter - ld hl, wChannelVibratoDelayCounterReloadValues - add hl, bc +.notNoiseInstrument 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] - ; --- this section is only present in this copy of the sound engine - ld a, c - cp Ch5 - jr nz, .beginChecks - ld a, [wLowHealthAlarm] ; low health alarm enabled? - bit 7, a - ret nz -.beginChecks - ; --- - call Audio2_sound_ret + cp NOISE_INSTRUMENTS_END + jr z, .playChannel + jr c, .playChannel +.notNoiseChannel + ld a, [wSoundID] + cp [hl] + jr z, .playChannel + jr c, .playChannel ret - -Audio2_sound_ret: - call Audio2_GetNextMusicByte - ld d, a - cp sound_ret_cmd - jp nz, Audio2_sound_call - ld b, 0 - ld hl, wChannelFlags1 - add hl, bc - bit BIT_SOUND_CALL, [hl] - jr nz, .returnFromCall +.playChannel + call InitSFXVariables 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 Audio2_sound_ret -.disableChannelOutput - ld hl, Audio2_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 Audio2_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 + jp z, .playSoundCommon + dec c + jp .sfxChannelLoop + +.stopAllAudio + call StopAllAudio ret -Audio2_sound_call: - cp sound_call_cmd - jp nz, Audio2_sound_loop - call Audio2_GetNextMusicByte - push af - call Audio2_GetNextMusicByte - ld d, a - pop af - ld e, a - push de ; store pointer - ld d, $0 - ld a, c - add a +.playSoundCommon + ld a, [wSoundID] + ld l, a ld e, a - ld hl, wChannelCommandPointers + ld h, 0 + ld d, h + add hl, hl add hl, de - push hl - ld hl, wChannelReturnAddresses + ld de, SFX_Headers_2 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 Audio2_sound_ret - -Audio2_sound_loop: - cp sound_loop_cmd - jp nz, Audio2_note_type - call Audio2_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 Audio2_GetNextMusicByte ; skip pointer - call Audio2_GetNextMusicByte - jp Audio2_sound_ret -.loopAgain ; inc loop count - inc a - ld [hl], a - ; fall through -.infiniteLoop ; overwrite current address with pointer - call Audio2_GetNextMusicByte - push af - call Audio2_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 Audio2_sound_ret - -Audio2_note_type: - and $f0 - cp note_type_cmd - jp nz, Audio2_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 Audio2_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 Audio2_sound_ret - -Audio2_toggle_perfect_pitch: - ld a, d - cp toggle_perfect_pitch_cmd - jr nz, Audio2_vibrato - ld b, 0 - ld hl, wChannelFlags1 - add hl, bc - ld a, [hl] - xor $1 - ld [hl], a ; flip bit 0 of wChannelFlags1 - jp Audio2_sound_ret - -Audio2_vibrato: - cp vibrato_cmd - jr nz, Audio2_pitch_slide - call Audio2_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 Audio2_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 Audio2_sound_ret - -Audio2_pitch_slide: - cp pitch_slide_cmd - jr nz, Audio2_duty_cycle - call Audio2_GetNextMusicByte - ld b, 0 - ld hl, wChannelPitchSlideLengthModifiers - add hl, bc - ld [hl], a - call Audio2_GetNextMusicByte - ld d, a - and $f0 - swap a - ld b, a - ld a, d - and $f - call Audio2_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 Audio2_GetNextMusicByte - ld d, a - jp Audio2_note_length - -Audio2_duty_cycle: - cp duty_cycle_cmd - jr nz, Audio2_tempo - call Audio2_GetNextMusicByte - rrca - rrca - and $c0 - ld b, 0 - ld hl, wChannelDutyCycles - add hl, bc - ld [hl], a ; store duty cycle - jp Audio2_sound_ret - -Audio2_tempo: - cp tempo_cmd - jr nz, Audio2_stereo_panning - ld a, c - cp Ch5 - jr nc, .sfxChannel - call Audio2_GetNextMusicByte - ld [wMusicTempo], a ; store first param - call Audio2_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 Audio2_GetNextMusicByte - ld [wSfxTempo], a ; store first param - call Audio2_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 Audio2_sound_ret - -Audio2_stereo_panning: - cp stereo_panning_cmd - jr nz, Audio2_unknownmusic0xef - call Audio2_GetNextMusicByte - ld [wStereoPanning], a ; store panning - jp Audio2_sound_ret - -; this appears to never be used -Audio2_unknownmusic0xef: - cp unknownmusic0xef_cmd - jr nz, Audio2_duty_cycle_pattern - call Audio2_GetNextMusicByte - push bc - call Audio2_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 Audio2_sound_ret - -Audio2_duty_cycle_pattern: - cp duty_cycle_pattern_cmd - jr nz, Audio2_volume - call Audio2_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 Audio2_sound_ret - -Audio2_volume: - cp volume_cmd - jr nz, Audio2_execute_music - call Audio2_GetNextMusicByte - ldh [rNR50], a ; store volume - jp Audio2_sound_ret - -Audio2_execute_music: - cp execute_music_cmd - jr nz, Audio2_octave - ld b, $0 - ld hl, wChannelFlags2 - add hl, bc - set BIT_EXECUTE_MUSIC, [hl] - jp Audio2_sound_ret - -Audio2_octave: - and $f0 - cp octave_cmd - jr nz, Audio2_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 Audio2_sound_ret - -; sfx_note is either square_note or noise_note depending on the channel -Audio2_sfx_note: - cp sfx_note_cmd - jr nz, Audio2_pitch_sweep - ld a, c - cp Ch4 ; is this a noise or sfx channel? - jr c, Audio2_pitch_sweep ; no - ld b, 0 - ld hl, wChannelFlags2 - add hl, bc - bit BIT_EXECUTE_MUSIC, [hl] ; is execute_music being used? - jr nz, Audio2_pitch_sweep ; yes - call Audio2_note_length - -; This code seems to do the same thing as what Audio2_ApplyDutyCycleAndSoundLength -; does below. - 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 Audio2_GetRegisterPointer - ld [hl], d - - call Audio2_GetNextMusicByte - ld d, a - ld b, REG_VOLUME_ENVELOPE - call Audio2_GetRegisterPointer - ld [hl], d - call Audio2_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 Audio2_GetNextMusicByte - pop de -.skip - ld d, a - push de - call Audio2_ApplyDutyCycleAndSoundLength - call Audio2_EnableChannelOutput - pop de - call Audio2_ApplyWavePatternAndFrequency - ret - -Audio2_pitch_sweep: - ld a, c - cp Ch5 - jr c, Audio2_note ; if not a sfx - ld a, d - cp pitch_sweep_cmd - jr nz, Audio2_note - ld b, $0 - ld hl, wChannelFlags2 - add hl, bc - bit BIT_EXECUTE_MUSIC, [hl] - jr nz, Audio2_note ; no - call Audio2_GetNextMusicByte - ldh [rNR10], a - jp Audio2_sound_ret - -Audio2_note: - ld a, c - cp Ch4 - jr nz, Audio2_note_length ; if not noise channel - ld a, d - and $f0 - cp drum_note_cmd - jr z, .drum_note - jr nc, Audio2_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 a, [de] ; get channel number ld b, a - ld a, d - and $f - ld d, a + rlca + rlca + and $3 + ld c, a ld a, b - push de - push bc - jr .playDnote - -.drum_note - ld a, d and $f + ld b, c + inc b + inc de + ld c, 0 +.commandPointerLoop + cp c + jr z, .next + inc c + inc hl + inc hl + jr .commandPointerLoop +.next push af + push hl push bc - call Audio2_GetNextMusicByte ; get drum_note instrument -.playDnote - ld d, a - ld a, [wDisableChannelOutputWhenSfxEnds] - and a - jr nz, .skipDnote - ld a, d - call Audio2_PlaySound -.skipDnote - pop bc - pop de - -Audio2_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 Audio2_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 Audio2_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 Audio2_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, Audio2_note_pitch + ld c, a + cp Ch4 + jr c, .skipSettingFlag ld hl, wChannelFlags1 add hl, bc - bit BIT_NOISE_OR_SFX, [hl] - jr z, Audio2_note_pitch + set BIT_NOISE_OR_SFX, [hl] +.skipSettingFlag + pop bc pop hl - ret - -Audio2_note_pitch: + ld a, [de] ; get channel pointer + ld [hli], a + inc de + ld a, [de] + ld [hli], a + inc de 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 + push hl + push bc ld b, 0 - ld hl, Audio2_HWChannelDisableMasks + ld c, a + ld hl, wChannelSoundIDs 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 Audio2_GetRegisterPointer - ld a, $8 ; fade in sound - ld [hli], a - inc hl - ld a, $80 ; restart sound + ld a, [wSoundID] ld [hl], a -.done - ret -.notRest - swap a - ld b, 0 - ld hl, wChannelOctaves - add hl, bc - ld b, [hl] - call Audio2_CalculateFrequency - ld b, 0 - ld hl, wChannelFlags1 - add hl, bc - bit BIT_PITCH_SLIDE_ON, [hl] - jr z, .skipPitchSlide - call Audio2_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 Audio2_GetRegisterPointer - ld [hl], d - call Audio2_ApplyDutyCycleAndSoundLength - call Audio2_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 Audio2_ApplyWavePatternAndFrequency - ret - -Audio2_EnableChannelOutput: - ld b, 0 - ld hl, Audio2_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] + pop bc + pop hl + inc c + dec b + ld a, b 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, Audio2_HWChannelEnableMasks - add hl, bc - and [hl] - ld d, a - ldh a, [rNR51] - ld hl, Audio2_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 - -Audio2_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 Audio2_GetRegisterPointer - ld [hl], d - ret - -Audio2_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, Audio2_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 Audio2_GetRegisterPointer - ld [hl], e ; store frequency low byte - inc hl - ld [hl], d ; store frequency high byte - ; --- this section is only present in this copy of the sound engine - ld a, c - cp Ch5 - jr c, .musicChannel - call Audio2_ApplyFrequencyModifier -.musicChannel - ; --- - ret - -; --- this section is only present in this copy of the sound engine -; unused -Audio2_ResetCryModifiers: - ld a, c - cp Ch5 - jr nz, .skip - ld a, [wLowHealthAlarm] - bit 7, a - jr z, .skip - xor a - ld [wFrequencyModifier], a - ld a, $80 - ld [wTempoModifier], a -.skip - ret -; --- - -Audio2_SetSfxTempo: - call Audio2_IsCry - jr c, .skipCryCheck - call Audio2_IsBattleSFX - jr nc, .notCry -.skipCryCheck - 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 - -Audio2_ApplyFrequencyModifier: - call Audio2_IsCry - jr c, .skipCryCheck - call Audio2_IsBattleSFX - jr nc, .done -.skipCryCheck -; if playing a cry, add the cry's frequency modifier - 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 - -Audio2_GoBackOneCommandIfCry: - call Audio2_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 - -Audio2_IsCry: -; Returns whether the currently playing audio is a cry in carry. - ld a, [wChannelSoundIDs + Ch5] + jr nz, .commandPointerLoop + ld a, [wSoundID] cp CRY_SFX_START - jr nc, .next - jr .no -.next + jr nc, .maybeCry + jr .done +.maybeCry + ld a, [wSoundID] cp CRY_SFX_END - jr z, .no - jr c, .yes -.no - scf - ccf - ret -.yes - scf - ret - -; --- this section is only present in this copy of the sound engine -Audio2_IsBattleSFX: -; Returns whether the currently playing audio is a cry in carry. - ld a, [wChannelSoundIDs + Ch8] - ld b, a - ld a, [wChannelSoundIDs + Ch5] - or b - cp BATTLE_SFX_START - jr nc, .next - jr .no -.next - cp BATTLE_SFX_END - jr z, .no - jr c, .yes -.no - scf - ccf - ret -.yes - scf - ret -; --- - -Audio2_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 Audio2_GetRegisterPointer - ld a, e + jr z, .done + jr c, .cry + jr .done +.cry + ld hl, wChannelSoundIDs + Ch5 + ld [hli], a + ld [hli], a 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 - -Audio2_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 - -Audio2_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 Audio2_GetRegisterPointer - ld a, [hl] - and $3f - or d ld [hl], a - ret - -Audio2_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 + ld hl, wChannelCommandPointers + Ch7 * 2 ; sfx wave channel pointer + ld de, Audio2_CryRet + ld [hl], e inc hl - ld [hl], d - ret - -Audio2_GetRegisterPointer: -; hl = address of hardware sound register b for software channel c - ld a, c - ld hl, Audio2_HWChannelBaseAddresses - add l - jr nc, .noCarry - inc h -.noCarry - ld l, a - ld a, [hl] - add b - ld l, a - ld h, $ff - ret - -Audio2_MultiplyAdd: -; hl = l + (a * de) - ld h, 0 -.loop - srl a - jr nc, .skipAdd - add hl, de -.skipAdd - sla e - rl d + ld [hl], d ; overwrite pointer to point to sound_ret + ld a, [wSavedVolume] and a - jr z, .done - jr .loop + jr nz, .done + ldh a, [rNR50] + ld [wSavedVolume], a + ld a, $77 + ldh [rNR50], a .done ret -Audio2_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, Audio2_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 +Audio2_CryRet: + sound_ret -Audio2_PlaySound:: - ld [wSoundID], a - cp SFX_STOP_ALL_MUSIC - jp z, .stopAllAudio - cp MAX_SFX_ID_2 - jp z, .playSfx - jp c, .playSfx - cp $fe - jr z, .playMusic - jp nc, .playSfx +INCLUDE "audio/poke_flute.asm" -.playMusic +INCLUDE "audio/sfx/pokeflute_ch5_ch6.asm" + +Audio2_InitMusicVariables:: xor a ld [wUnusedC000], a ld [wDisableChannelOutputWhenSfxEnds], a @@ -1411,53 +205,53 @@ Audio2_PlaySound:: ld [wSfxWaveInstrument], a ld d, NUM_CHANNELS ld hl, wChannelReturnAddresses - call .FillMem + call Audio2_FillMem ld hl, wChannelCommandPointers - call .FillMem + call Audio2_FillMem ld d, NUM_MUSIC_CHANS ld hl, wChannelSoundIDs - call .FillMem + call Audio2_FillMem ld hl, wChannelFlags1 - call .FillMem + call Audio2_FillMem ld hl, wChannelDutyCycles - call .FillMem + call Audio2_FillMem ld hl, wChannelDutyCyclePatterns - call .FillMem + call Audio2_FillMem ld hl, wChannelVibratoDelayCounters - call .FillMem + call Audio2_FillMem ld hl, wChannelVibratoExtents - call .FillMem + call Audio2_FillMem ld hl, wChannelVibratoRates - call .FillMem + call Audio2_FillMem ld hl, wChannelFrequencyLowBytes - call .FillMem + call Audio2_FillMem ld hl, wChannelVibratoDelayCounterReloadValues - call .FillMem + call Audio2_FillMem ld hl, wChannelFlags2 - call .FillMem + call Audio2_FillMem ld hl, wChannelPitchSlideLengthModifiers - call .FillMem + call Audio2_FillMem ld hl, wChannelPitchSlideFrequencySteps - call .FillMem + call Audio2_FillMem ld hl, wChannelPitchSlideFrequencyStepsFractionalPart - call .FillMem + call Audio2_FillMem ld hl, wChannelPitchSlideCurrentFrequencyFractionalPart - call .FillMem + call Audio2_FillMem ld hl, wChannelPitchSlideCurrentFrequencyHighBytes - call .FillMem + call Audio2_FillMem ld hl, wChannelPitchSlideCurrentFrequencyLowBytes - call .FillMem + call Audio2_FillMem ld hl, wChannelPitchSlideTargetFrequencyHighBytes - call .FillMem + call Audio2_FillMem ld hl, wChannelPitchSlideTargetFrequencyLowBytes - call .FillMem + call Audio2_FillMem ld a, $1 ld hl, wChannelLoopCounters - call .FillMem + call Audio2_FillMem ld hl, wChannelNoteDelayCounters - call .FillMem + call Audio2_FillMem ld hl, wChannelNoteSpeeds - call .FillMem + call Audio2_FillMem ld [wMusicTempo], a ld a, $ff ld [wStereoPanning], a @@ -1473,67 +267,9 @@ Audio2_PlaySound:: ldh [rNR30], a ld a, $77 ldh [rNR50], a - jp .playSoundCommon - -.playSfx - ld l, a - ld e, a - ld h, 0 - ld d, h - add hl, hl - add hl, de - ld de, SFX_Headers_2 - add hl, de - ld a, h - ld [wSfxHeaderPointer], a - ld a, l - ld [wSfxHeaderPointer + 1], a - ld a, [hl] - and $c0 - rlca - rlca - ld c, a -.sfxChannelLoop - ld d, c - ld a, c - add a - add c - ld c, a - ld b, 0 - ld a, [wSfxHeaderPointer] - ld h, a - ld a, [wSfxHeaderPointer + 1] - ld l, a - add hl, bc - ld c, d - ld a, [hl] - and $f - ld e, a ; software channel ID - ld d, 0 - ld hl, wChannelSoundIDs - add hl, de - ld a, [hl] - and a - jr z, .playChannel - ld a, e - cp Ch8 - jr nz, .notNoiseChannel - ld a, [wSoundID] - cp NOISE_INSTRUMENTS_END - jr nc, .notNoiseInstrument - ret -.notNoiseInstrument - ld a, [hl] - cp NOISE_INSTRUMENTS_END - jr z, .playChannel - jr c, .playChannel -.notNoiseChannel - ld a, [wSoundID] - cp [hl] - jr z, .playChannel - jr c, .playChannel ret -.playChannel + +Audio2_InitSFXVariables:: xor a push de ld h, d @@ -1616,17 +352,12 @@ Audio2_PlaySound:: ld [hl], a ld a, e cp Ch5 - jr nz, .skipSweepDisable + ret nz ld a, $8 ldh [rNR10], a ; sweep off -.skipSweepDisable - ld a, c - and a - jp z, .playSoundCommon - dec c - jp .sfxChannelLoop + ret -.stopAllAudio +Audio2_StopAllAudio:: ld a, $80 ldh [rNR52], a ; sound hardware on ldh [rNR30], a ; wave playback on @@ -1652,13 +383,13 @@ Audio2_PlaySound:: ld [wSfxTempo + 1], a ld [wMusicWaveInstrument], a ld [wSfxWaveInstrument], a - ld d, $a0 + ld d, $b0 ld hl, wChannelCommandPointers - call .FillMem + call Audio2_FillMem ld a, $1 ld d, $18 ld hl, wChannelNoteDelayCounters - call .FillMem + call Audio2_FillMem ld [wMusicTempo], a ld [wSfxTempo], a ld a, $ff @@ -1666,124 +397,10 @@ Audio2_PlaySound:: ret ; fills d bytes at hl with a -.FillMem +Audio2_FillMem: ld b, d .loop ld [hli], a dec b jr nz, .loop ret - -.playSoundCommon - ld a, [wSoundID] - ld l, a - ld e, a - ld h, 0 - ld d, h - add hl, hl - add hl, de - ld de, SFX_Headers_2 - add hl, de - ld e, l - ld d, h - ld hl, wChannelCommandPointers - ld a, [de] ; get channel number - ld b, a - rlca - rlca - and $3 - ld c, a - ld a, b - and $f - ld b, c - inc b - inc de - ld c, 0 -.commandPointerLoop - cp c - jr z, .next - inc c - inc hl - inc hl - jr .commandPointerLoop -.next - 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 - add hl, bc - set BIT_NOISE_OR_SFX, [hl] -.skipSettingFlag - pop bc - pop hl - ld a, [de] ; get channel pointer - ld [hli], a - inc de - ld a, [de] - ld [hli], a - inc de - inc c - dec b - ld a, b - and a - ld a, [de] - inc de - jr nz, .commandPointerLoop - ld a, [wSoundID] - cp CRY_SFX_START - jr nc, .maybeCry - jr .done -.maybeCry - ld a, [wSoundID] - cp CRY_SFX_END - jr z, .done - jr c, .cry - jr .done -.cry - ld hl, wChannelSoundIDs + Ch5 - ld [hli], a - ld [hli], a - ld [hli], a - ld [hl], a - ld hl, wChannelCommandPointers + Ch7 * 2 ; sfx wave channel pointer - ld de, Audio2_CryRet - ld [hl], e - inc hl - ld [hl], d ; overwrite pointer to point to sound_ret - ld a, [wSavedVolume] - and a - jr nz, .done - ldh a, [rNR50] - ld [wSavedVolume], a - ld a, $77 - ldh [rNR50], a ; full volume -.done - ret - -Audio2_CryRet: - sound_ret - -Audio2_HWChannelBaseAddresses: -; the low bytes of each HW channel's base address - db HW_CH1_BASE, HW_CH2_BASE, HW_CH3_BASE, HW_CH4_BASE ; channels 0-3 - db HW_CH1_BASE, HW_CH2_BASE, HW_CH3_BASE, HW_CH4_BASE ; channels 4-7 - -Audio2_HWChannelDisableMasks: - db HW_CH1_DISABLE_MASK, HW_CH2_DISABLE_MASK, HW_CH3_DISABLE_MASK, HW_CH4_DISABLE_MASK ; channels 0-3 - db HW_CH1_DISABLE_MASK, HW_CH2_DISABLE_MASK, HW_CH3_DISABLE_MASK, HW_CH4_DISABLE_MASK ; channels 4-7 - -Audio2_HWChannelEnableMasks: - db HW_CH1_ENABLE_MASK, HW_CH2_ENABLE_MASK, HW_CH3_ENABLE_MASK, HW_CH4_ENABLE_MASK ; channels 0-3 - db HW_CH1_ENABLE_MASK, HW_CH2_ENABLE_MASK, HW_CH3_ENABLE_MASK, HW_CH4_ENABLE_MASK ; channels 4-7 - -Audio2_Pitches: -INCLUDE "audio/notes.asm" |