diff options
author | Juan J. Martinez <jjm@usebox.net> | 2023-11-05 11:22:55 +0000 |
---|---|---|
committer | Juan J. Martinez <jjm@usebox.net> | 2023-11-05 11:31:28 +0000 |
commit | 2fbdf974338bde8576efdae40a819a76b2391033 (patch) | |
tree | 64d41a37470143f142344f9a439d96de3e7918c2 /lib/plw/player/PlayerLightWeight_SoundEffects.asm | |
download | kitsunes-curse-2fbdf974338bde8576efdae40a819a76b2391033.tar.gz kitsunes-curse-2fbdf974338bde8576efdae40a819a76b2391033.zip |
Initial import of the open source release
Diffstat (limited to 'lib/plw/player/PlayerLightWeight_SoundEffects.asm')
-rw-r--r-- | lib/plw/player/PlayerLightWeight_SoundEffects.asm | 458 |
1 files changed, 458 insertions, 0 deletions
diff --git a/lib/plw/player/PlayerLightWeight_SoundEffects.asm b/lib/plw/player/PlayerLightWeight_SoundEffects.asm new file mode 100644 index 0000000..cd15cb8 --- /dev/null +++ b/lib/plw/player/PlayerLightWeight_SoundEffects.asm @@ -0,0 +1,458 @@ +; Player of sound effects, for the Lightweight player. + + ;Is there a loaded Player Configuration source? If no, use a default configuration. + IFNDEF PLY_CFG_SFX_ConfigurationIsPresent + PLY_CFG_UseHardwareSounds = 1 + PLY_CFG_SFX_LoopTo = 1 + PLY_CFG_SFX_NoSoftNoHard = 1 + PLY_CFG_SFX_NoSoftNoHard_Noise = 1 + PLY_CFG_SFX_SoftOnly = 1 + PLY_CFG_SFX_SoftOnly_Noise = 1 + PLY_CFG_SFX_HardOnly = 1 + PLY_CFG_SFX_HardOnly_Noise = 1 + PLY_CFG_SFX_HardOnly_Retrig = 1 + PLY_CFG_SFX_SoftAndHard = 1 + PLY_CFG_SFX_SoftAndHard_Noise = 1 + PLY_CFG_SFX_SoftAndHard_Retrig = 1 + ENDIF + +; Agglomerates some Player Configuration flags. +; -------------------------------------------- +; Mixes the Hardware flags into one. + IFDEF PLY_CFG_SFX_HardOnly + PLY_LW_SE_HardwareSounds = 1 + ENDIF + IFDEF PLY_CFG_SFX_SoftAndHard + PLY_LW_SE_HardwareSounds = 1 + ENDIF +; Mixes the Hardware Noise flags into one. + IFDEF PLY_CFG_SFX_HardOnly_Noise + PLY_LW_SE_HardwareNoise = 1 + ENDIF + IFDEF PLY_CFG_SFX_SoftAndHard_Noise + PLY_LW_SE_HardwareNoise = 1 + ENDIF +; Mixes the Noise flags into one. + IFDEF PLY_LW_SE_HardwareNoise + PLY_LW_SE_Noise = 1 + ENDIF + IFDEF PLY_CFG_SFX_NoSoftNoHard_Noise + PLY_LW_SE_Noise = 1 + ENDIF + IFDEF PLY_CFG_SFX_SoftOnly + PLY_LW_SE_Noise = 1 + ENDIF +; Noise in Sound Effects? Then noise register code must be compiled. + IFDEF PLY_LW_SE_Noise + PLY_LW_USE_NoiseRegister = 1 + ENDIF +; Mixes the Software Volume flags into one. + IFDEF PLY_CFG_SFX_NoSoftNoHard + PLY_LW_SE_VolumeSoft = 1 + PLY_LW_SE_VolumeSoftOrHard = 1 + ENDIF + IFDEF PLY_CFG_SFX_SoftOnly + PLY_LW_SE_VolumeSoft = 1 + PLY_LW_SE_VolumeSoftOrHard = 1 + ENDIF +; Mixes the volume (soft/hard) into one. + IFDEF PLY_CFG_UseHardwareSounds + PLY_LW_SE_VolumeSoftOrHard = 1 + ENDIF +; Mixes the retrig flags into one. + IFDEF PLY_CFG_SFX_HardOnly_Retrig + PLY_LW_SE_Retrig = 1 + ENDIF + IFDEF PLY_CFG_SFX_SoftAndHard_Retrig + PLY_LW_SE_Retrig = 1 + ENDIF + + +;Initializes the sound effects. It MUST be called at any times before a first sound effect is triggered. +;It doesn't matter whether the song is playing or not, or if it has been initialized or not. +;IN: HL = Address to the sound effects data. +PLY_LW_InitSoundEffectsDisarkGenerateExternalLabel: +PLY_LW_InitSoundEffects: + ld (PLY_LW_SE_PtSoundEffectTable + 1),hl + ret + + +;Plays a sound effect. If a previous one was already playing on the same channel, it is replaced. +;This does not actually plays the sound effect, but programs its playing. +;The music player, when called, will call the PLY_LW_PlaySoundEffectsStream method below. +;IN: A = Sound effect number (>0!). +; C = The channel where to play the sound effect (0, 1, 2). +; B = Inverted volume (0 = full volume, 16 = no sound). Hardware sounds are also lowered. +PLY_LW_PlaySoundEffectDisarkGenerateExternalLabel: +PLY_LW_PlaySoundEffect: + ;Gets the address to the sound effect. + dec a ;The 0th is not encoded. +dknr3: +PLY_LW_SE_PtSoundEffectTable: ld hl,0 + ld e,a + ld d,0 + add hl,de + add hl,de + ld e,(hl) + inc hl + ld d,(hl) + ;Reads the header of the sound effect to get the speed. + ld a,(de) + inc de + + push af + ;ex af,af' + + ld a,b + + ;Finds the pointer to the sound effect of the desired channel. + ld hl,PLY_LW_Channel1_SoundEffectData + ld b,0 + sla c + sla c + sla c + add hl,bc + ld (hl),e + inc hl + ld (hl),d + inc hl + + ;Now stores the inverted volume. + ld (hl),a + inc hl + + ;Resets the current speed, stores the instrument speed. + ld (hl),0 + inc hl + + ;ex af,af' + pop af + + ld (hl),a + + ret + +;Stops a sound effect. Nothing happens if there was no sound effect. +;IN: A = The channel where to stop the sound effect (0, 1, 2). +PLY_LW_StopSoundEffectFromChannelDisarkGenerateExternalLabel: +PLY_LW_StopSoundEffectFromChannel: + ;Puts 0 to the pointer of the sound effect. + add a,a + add a,a + add a,a + ld e,a + ld d,0 + ld hl,PLY_LW_Channel1_SoundEffectData + add hl,de + ld (hl),d ;0 means "no sound". + inc hl + ld (hl),d + ret + +;Plays the sound effects, if any has been triggered by the user. +;This does not actually send registers to the PSG, it only overwrite the required values of the registers of the player. +;The sound effects initialization method must have been called before! +;As R7 is required, this must be called after the music has been played, but BEFORE the registers are sent to the PSG. +;IN: A = R7. +PLY_LW_PlaySoundEffectsStream: + ;Shifts the R7 to the left twice, so that bit 2 and 5 only can be set for each track, below. + rla + rla + + ;Plays the sound effects on every track. + ld ix,PLY_LW_Channel1_SoundEffectData + ld iy,PLY_LW_Track1_Registers + ld c,a + call PLY_LW_PSES_Play + ld ix,PLY_LW_Channel2_SoundEffectData + ld iy,PLY_LW_Track2_Registers + srl c ;Not RR, because we have to make sure the b6 is 0, else no more keyboard (on CPC)! + ;Also, on MSX, bit 6 must be 0. + call PLY_LW_PSES_Play + ld ix,PLY_LW_Channel3_SoundEffectData + ld iy,PLY_LW_Track3_Registers + IFDEF PLY_LW_HARDWARE_MSX + scf ;On MSX, bit 7 must be 1. + rr c + ELSE + rr c ;On other platforms, we don't care about b7. + ENDIF + call PLY_LW_PSES_Play + + ld a,c + ld (PLY_LW_MixerRegister),a + ret + + +;Plays the sound stream from the given pointer to the sound effect. If 0, no sound is played. +;The given R7 is given shift twice to the left, so that this code MUST set/reset the bit 2 (sound), and maybe reset bit 5 (noise). +;This code MUST overwrite these bits because sound effects have priority over the music. +;IN: IX = Points on the sound effect pointer. If the sound effect pointer is 0, nothing must be played. +; IY = Points at the beginning of the register structure related to the channel. +; C = R7, shifted twice to the left. +;OUT: The pointed pointer by IX may be modified as the sound advances. +; C = R7, MUST be modified if there is a sound effect. +PLY_LW_PSES_Play: + ;Reads the pointer pointed by IX. + ld l,(ix + 0) + ld h,(ix + 1) + ld a,l + or h + ret z ;No sound to be played? Returns immediately. + + ;Reads the first byte. What type of sound is it? +PLY_LW_PSES_ReadFirstByte: + ld a,(hl) + inc hl + ld b,a + rra + jr c,PLY_LW_PSES_SoftwareOrSoftwareAndHardware + rra + IFDEF PLY_CFG_SFX_HardOnly ;CONFIG SPECIFIC + jr c,PLY_LW_PSES_HardwareOnly + ENDIF ;PLY_CFG_SFX_HardOnly + + ;No software, no hardware, or end/loop. + ;------------------------------------------- + ;End or loop? + rra + IFDEF PLY_CFG_SFX_NoSoftNoHard ;CONFIG SPECIFIC. If not present, the jump is not needed, the method is just below. + jr c,PLY_LW_PSES_S_EndOrLoop + + ;No software, no hardware. + ;------------------------------------------- + ;Gets the volume. + call PLY_LW_PSES_ManageVolumeFromA_Filter4Bits + + ;Noise? + IFDEF PLY_CFG_SFX_NoSoftNoHard_Noise ;CONFIG SPECIFIC + rl b + call c,PLY_LW_PSES_ReadNoiseAndOpenNoiseChannel + ENDIF ;PLY_CFG_SFX_NoSoftNoHard_Noise + + jr PLY_LW_PSES_SavePointerAndExit + ENDIF ;PLY_CFG_SFX_NoSoftNoHard + + ;**Warning!** Do not put any instruction between EndOrLoop and NoSoftNoHard. + +PLY_LW_PSES_S_EndOrLoop: + IFDEF PLY_CFG_SFX_LoopTo ;CONFIG SPECIFIC. If no "loop to", the sounds always end, no need to test. + ;Is it an end? + rra + jr c,PLY_LW_PSES_S_Loop + ENDIF ;PLY_CFG_SFX_LoopTo + ;End of the sound. Marks the sound pointer with 0, meaning "no sound". + xor a + ld (ix + 0),a + ld (ix + 1),a + ret + IFDEF PLY_CFG_SFX_LoopTo ;CONFIG SPECIFIC. +PLY_LW_PSES_S_Loop: + ;Loops. Reads the pointer and directly uses it. + ld a,(hl) + inc hl + ld h,(hl) + ld l,a + jr PLY_LW_PSES_ReadFirstByte + ENDIF ;PLY_CFG_SFX_LoopTo + + +;Saves HL into IX, and exits. This must be called at the end of each Cell. +;If the speed has not been reached, it is not saved. +PLY_LW_PSES_SavePointerAndExit: + ;Speed reached? + ld a,(ix + PLY_LW_SoundEffectData_OffsetCurrentStep) + cp (ix + PLY_LW_SoundEffectData_OffsetSpeed) + jr c,PLY_LW_PSES_NotReached + ;The speed has been reached, so resets it and saves the pointer to the next cell to read. + ld (ix + PLY_LW_SoundEffectData_OffsetCurrentStep),0 + ld (ix + 0),l + ld (ix + 1),h + ret +PLY_LW_PSES_NotReached: + ;Speed not reached. Increases it, that's all. The same cell will be read next time. + inc (ix + PLY_LW_SoundEffectData_OffsetCurrentStep) + ret + + IFDEF PLY_CFG_SFX_HardOnly ;CONFIG SPECIFIC + ;Hardware only. + ;------------------------------------------- +PLY_LW_PSES_HardwareOnly: + ;Calls the shared code that manages everything. + call PLY_LW_PSES_Shared_ReadRetrigHardwareEnvPeriodNoise + ;Cuts the sound. + set 2,c + + jr PLY_LW_PSES_SavePointerAndExit + ENDIF ;PLY_CFG_SFX_HardOnly + + + +PLY_LW_PSES_SoftwareOrSoftwareAndHardware: + ;Software only? + rra + IFDEF PLY_CFG_SFX_SoftAndHard ;CONFIG SPECIFIC + jr c,PLY_LW_PSES_SoftwareAndHardware + ENDIF ;PLY_CFG_SFX_SoftAndHard + + ;Software. + ;------------------------------------------- + IFDEF PLY_CFG_SFX_SoftOnly ;CONFIG SPECIFIC + ;Volume. + call PLY_LW_PSES_ManageVolumeFromA_Filter4Bits + + ;Noise? + rl b + IFDEF PLY_CFG_SFX_SoftOnly_Noise ;CONFIG SPECIFIC + call c,PLY_LW_PSES_ReadNoiseAndOpenNoiseChannel + ENDIF ;PLY_CFG_SFX_SoftOnly_Noise + + ;Opens the "sound" channel. + res 2,c + + ;Reads the software period. + call PLY_LW_PSES_ReadSoftwarePeriod + + jr PLY_LW_PSES_SavePointerAndExit + ENDIF ;PLY_CFG_SFX_SoftOnly + + + ;Software and Hardware. + ;------------------------------------------- + IFDEF PLY_LW_SE_HardwareSounds ;CONFIG SPECIFIC +PLY_LW_PSES_SoftwareAndHardware: + ;Calls the shared code that manages everything. + call PLY_LW_PSES_Shared_ReadRetrigHardwareEnvPeriodNoise + + ;Reads the software period. + call PLY_LW_PSES_ReadSoftwarePeriod + + ;Opens the sound. + res 2,c + + jr PLY_LW_PSES_SavePointerAndExit + ENDIF ;PLY_LW_SE_HardwareSounds + + + IFDEF PLY_CFG_UseHardwareSounds ;CONFIG SPECIFIC + ;Shared code used by the "hardware only" and "software and hardware" part. + ;Reads the Retrig flag, the Hardware Envelope, the possible noise, the hardware period, + ;and sets the volume to 16. The R7 sound channel is NOT modified. +PLY_LW_PSES_Shared_ReadRetrigHardwareEnvPeriodNoise: + ;Retrig? + rra + IFDEF PLY_LW_SE_Retrig ;CONFIG SPECIFIC + jr nc,PLY_LW_PSES_H_AfterRetrig + ld d,a + ld a,255 + ld (PLY_LW_SetReg13Old + 1),a + ld a,d +PLY_LW_PSES_H_AfterRetrig: + ENDIF ;PLY_LW_SE_Retrig + + ;The hardware envelope can be set (8-15). + and %111 + add a,8 + ld (PLY_LW_SetReg13 + 1),a + + ;Noise? + IFDEF PLY_LW_SE_HardwareNoise ;CONFIG SPECIFIC. B not needed after, we can put it in the condition too. + rl b + call c,PLY_LW_PSES_ReadNoiseAndOpenNoiseChannel + ENDIF ;PLY_LW_SE_HardwareNoise + + ;Reads the hardware period. + call PLY_LW_PSES_ReadHardwarePeriod + + ;Sets the volume to "hardware". It still may be decreased. + ld a,16 + jp PLY_LW_PSES_ManageVolumeFromA_Hard + ENDIF ;PLY_CFG_UseHardwareSounds + + + IFDEF PLY_LW_SE_Noise +;Reads the noise pointed by HL, increases HL, and opens the noise channel. +PLY_LW_PSES_ReadNoiseAndOpenNoiseChannel: + ;Reads the noise. + ld a,(hl) + ld (PLY_LW_NoiseRegister),a + inc hl + + ;Opens noise channel. + res 5,c + ret + ENDIF ;PLY_LW_SE_Noise + + IFDEF PLY_CFG_UseHardwareSounds ;CONFIG SPECIFIC +;Reads the hardware period from HL and sets the R11/R12 registers. HL is incremented of 2. +PLY_LW_PSES_ReadHardwarePeriod: + ld a,(hl) + ld (PLY_LW_Reg11),a + inc hl + ld a,(hl) + ld (PLY_LW_Reg12),a + inc hl + ret + ENDIF ;PLY_CFG_UseHardwareSounds + +;Reads the software period from HL and sets the period registers thanks to IY. HL is incremented of 2. +PLY_LW_PSES_ReadSoftwarePeriod: + ld a,(hl) + ld (iy + PLY_LW_Registers_OffsetSoftwarePeriodLSB),a + inc hl + ld a,(hl) + ld (iy + PLY_LW_Registers_OffsetSoftwarePeriodMSB),a + inc hl + ret + + IFDEF PLY_LW_SE_VolumeSoft ;CONFIG SPECIFIC +;Reads the volume in A, decreases it from the inverted volume of the channel, and sets the volume via IY. +;IN: A = volume, from 0 to 15 (no hardware envelope). +PLY_LW_PSES_ManageVolumeFromA_Filter4Bits: + and %1111 + ENDIF ;PLY_LW_SE_VolumeSoft + IFDEF PLY_LW_SE_VolumeSoftOrHard ;CONFIG SPECIFIC +;After the filtering. Useful for hardware sound (volume has been forced to 16). +PLY_LW_PSES_ManageVolumeFromA_Hard: + ;Decreases the volume, checks the limit. + sub (ix + PLY_LW_SoundEffectData_OffsetInvertedVolume) + jr nc,PLY_LW_PSES_MVFA_NoOverflow + xor a +PLY_LW_PSES_MVFA_NoOverflow: + ld (iy + PLY_LW_Registers_OffsetVolume),a + ret + ENDIF ;PLY_LW_SE_VolumeSoftOrHard + + +;The data of the Channels MUST be consecutive. +PLY_LW_Channel1_SoundEffectData: +dkws + dw 0 ;Points to the sound effect for the track 1, or 0 if not playing. +PLY_LW_Channel1_SoundEffectInvertedVolume: +dkwe +dkbs + db 0 ;Inverted volume. +PLY_LW_Channel1_SoundEffectCurrentStep: + db 0 ;Current step (>=0). +PLY_LW_Channel1_SoundEffectSpeed: + db 0 ;Speed (>=0). + ds 3,0 ;Padding. +dkbe +PLY_LW_Channel_SoundEffectDataSize: equ $ - PLY_LW_Channel1_SoundEffectData + +dkbs +PLY_LW_Channel2_SoundEffectData: + ds PLY_LW_Channel_SoundEffectDataSize, 0 +PLY_LW_Channel3_SoundEffectData: + ds PLY_LW_Channel_SoundEffectDataSize, 0 +dkbe + +;Offset from the beginning of the data, to reach the inverted volume. +PLY_LW_SoundEffectData_OffsetInvertedVolume: equ PLY_LW_Channel1_SoundEffectInvertedVolume - PLY_LW_Channel1_SoundEffectData +PLY_LW_SoundEffectData_OffsetCurrentStep: equ PLY_LW_Channel1_SoundEffectCurrentStep - PLY_LW_Channel1_SoundEffectData +PLY_LW_SoundEffectData_OffsetSpeed: equ PLY_LW_Channel1_SoundEffectSpeed - PLY_LW_Channel1_SoundEffectData + + ;Checks that the pointers are consecutive. + assert (PLY_LW_Channel1_SoundEffectData + PLY_LW_Channel_SoundEffectDataSize) == PLY_LW_Channel2_SoundEffectData + assert (PLY_LW_Channel2_SoundEffectData + PLY_LW_Channel_SoundEffectDataSize) == PLY_LW_Channel3_SoundEffectData + |