diff options
author | Juan J. Martinez <jjm@usebox.net> | 2020-12-30 19:07:31 +0000 |
---|---|---|
committer | Juan J. Martinez <jjm@usebox.net> | 2020-12-30 19:23:41 +0000 |
commit | 2682bc5d1d864341aaeb42a449db73c3ecd16d70 (patch) | |
tree | 9116764364b4ee0ce7f6037305077807b57776de /src/mplayer/akm/PlayerAkm_SoundEffects.asm | |
download | ubox-msx-lib-1.0.tar.gz ubox-msx-lib-1.0.zip |
Initial import1.0
Diffstat (limited to 'src/mplayer/akm/PlayerAkm_SoundEffects.asm')
-rw-r--r-- | src/mplayer/akm/PlayerAkm_SoundEffects.asm | 477 |
1 files changed, 477 insertions, 0 deletions
diff --git a/src/mplayer/akm/PlayerAkm_SoundEffects.asm b/src/mplayer/akm/PlayerAkm_SoundEffects.asm new file mode 100644 index 0000000..1e4c3b8 --- /dev/null +++ b/src/mplayer/akm/PlayerAkm_SoundEffects.asm @@ -0,0 +1,477 @@ +; Player of sound effects, for the AKM player. +; Note that this is the exact same code as for the Lightweight player, as the way to output to the PSG is the same. + + ;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_AKM_SE_HardwareSounds = 1 + ENDIF + IFDEF PLY_CFG_SFX_SoftAndHard + PLY_AKM_SE_HardwareSounds = 1 + ENDIF +; Mixes the Hardware Noise flags into one. + IFDEF PLY_CFG_SFX_HardOnly_Noise + PLY_AKM_SE_HardwareNoise = 1 + ENDIF + IFDEF PLY_CFG_SFX_SoftAndHard_Noise + PLY_AKM_SE_HardwareNoise = 1 + ENDIF +; Mixes the Noise flags into one. + IFDEF PLY_AKM_SE_HardwareNoise + PLY_AKM_SE_Noise = 1 + ENDIF + IFDEF PLY_CFG_SFX_NoSoftNoHard_Noise + PLY_AKM_SE_Noise = 1 + ENDIF + IFDEF PLY_CFG_SFX_SoftOnly + PLY_AKM_SE_Noise = 1 + ENDIF +; Noise in Sound Effects? Then noise register code must be compiled. + IFDEF PLY_AKM_SE_Noise + PLY_AKM_USE_NoiseRegister = 1 + ENDIF +; Mixes the Software Volume flags into one. + IFDEF PLY_CFG_SFX_NoSoftNoHard + PLY_AKM_SE_VolumeSoft = 1 + PLY_AKM_SE_VolumeSoftOrHard = 1 + ENDIF + IFDEF PLY_CFG_SFX_SoftOnly + PLY_AKM_SE_VolumeSoft = 1 + PLY_AKM_SE_VolumeSoftOrHard = 1 + ENDIF +; Mixes the volume (soft/hard) into one. + IFDEF PLY_CFG_UseHardwareSounds + PLY_AKM_SE_VolumeSoftOrHard = 1 + ENDIF +; Mixes the retrig flags into one. + IFDEF PLY_CFG_SFX_HardOnly_Retrig + PLY_AKM_SE_Retrig = 1 + ENDIF + IFDEF PLY_CFG_SFX_SoftAndHard_Retrig + PLY_AKM_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_AKM_InitSoundEffectsDisarkGenerateExternalLabel: +PLY_AKM_InitSoundEffects: + ld (PLY_AKM_PtSoundEffectTable + PLY_AKM_Offset1b),hl + ret + + +;Pl²ys 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_AKM_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_AKM_PlaySoundEffectDisarkGenerateExternalLabel: +PLY_AKM_PlaySoundEffect: + ;Gets the address to the sound effect. + dec a ;The 0th is not encoded. + IFNDEF PLY_AKM_Rom +dknr3 (void): +PLY_AKM_PtSoundEffectTable: ld hl,0 + ELSE + ld hl,(PLY_AKM_PtSoundEffectTable) + ENDIF + 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 + ex af,af' + + ld a,b + + ;Finds the pointer to the sound effect of the desired channel. + ld hl,PLY_AKM_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' + 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_AKM_StopSoundEffectFromChannelDisarkGenerateExternalLabel: +PLY_AKM_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_AKM_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_AKM_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_AKM_Channel1_SoundEffectData + ld iy,PLY_AKM_Track1_Registers + ld c,a + call PLY_AKM_PSES_Play + ld ix,PLY_AKM_Channel2_SoundEffectData + ld iy,PLY_AKM_Track2_Registers + srl c ;Not RR, to make sure bit 6 is 0 (else, no more keyboard on CPC!). + ;Also, on MSX, bit 6 must be 0. + call PLY_AKM_PSES_Play + ld ix,PLY_AKM_Channel3_SoundEffectData + ld iy,PLY_AKM_Track3_Registers + IFDEF PLY_AKM_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_AKM_PSES_Play + + ld a,c + ld (PLY_AKM_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 set/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_AKM_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_AKM_PSES_ReadFirstByte: + ld a,(hl) + inc hl + ld b,a + rra + jr c,PLY_AKM_PSES_SoftwareOrSoftwareAndHardware + rra + IFDEF PLY_CFG_SFX_HardOnly ;CONFIG SPECIFIC + jr c,PLY_AKM_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_AKM_PSES_S_EndOrLoop + + ;No software, no hardware. + ;------------------------------------------- + ;Gets the volume. + call PLY_AKM_PSES_ManageVolumeFromA_Filter4Bits + + ;Noise? + IFDEF PLY_CFG_SFX_NoSoftNoHard_Noise ;CONFIG SPECIFIC + rl b + call PLY_AKM_PSES_ReadNoiseIfNeededAndOpenOrCloseNoiseChannel + ELSE + set 5,c ;No noise in compilation, so stops the noise. + ENDIF ;PLY_CFG_SFX_NoSoftNoHard_Noise + + ;Cuts the sound. + set 2,c + + jr PLY_AKM_PSES_SavePointerAndExit + ENDIF ;PLY_CFG_SFX_NoSoftNoHard + + ;**Warning!** Do not put any instruction between EndOrLoop and NoSoftNoHard. + +PLY_AKM_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_AKM_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_AKM_PSES_S_Loop: + ;Loops. Reads the pointer and directly uses it. + ld a,(hl) + inc hl + ld h,(hl) + ld l,a + jr PLY_AKM_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_AKM_PSES_SavePointerAndExit: + ;Speed reached? + ld a,(ix + PLY_AKM_SoundEffectData_OffsetCurrentStep) + cp (ix + PLY_AKM_SoundEffectData_OffsetSpeed) + jr c,PLY_AKM_PSES_NotReached + ;The speed has been reached, so resets it and saves the pointer to the next cell to read. + ld (ix + PLY_AKM_SoundEffectData_OffsetCurrentStep),0 + ld (ix + 0),l + ld (ix + 1),h + ret +PLY_AKM_PSES_NotReached: + ;Speed not reached. Increases it, that's all. The same cell will be read next time. + inc (ix + PLY_AKM_SoundEffectData_OffsetCurrentStep) + ret + + IFDEF PLY_CFG_SFX_HardOnly ;CONFIG SPECIFIC + ;Hardware only. + ;------------------------------------------- +PLY_AKM_PSES_HardwareOnly: + ;Calls the shared code that manages everything. + call PLY_AKM_PSES_Shared_ReadRetrigHardwareEnvPeriodNoise + ;Cuts the sound. + set 2,c + + jr PLY_AKM_PSES_SavePointerAndExit + ENDIF ;PLY_CFG_SFX_HardOnly + + + +PLY_AKM_PSES_SoftwareOrSoftwareAndHardware: + ;Software only? + rra + IFDEF PLY_CFG_SFX_SoftAndHard ;CONFIG SPECIFIC + jr c,PLY_AKM_PSES_SoftwareAndHardware + ENDIF ;PLY_CFG_SFX_SoftAndHard + + ;Software. + ;------------------------------------------- + IFDEF PLY_CFG_SFX_SoftOnly ;CONFIG SPECIFIC + ;Volume. + call PLY_AKM_PSES_ManageVolumeFromA_Filter4Bits + + ;Noise? + IFDEF PLY_CFG_SFX_SoftOnly_Noise ;CONFIG SPECIFIC + rl b + call PLY_AKM_PSES_ReadNoiseIfNeededAndOpenOrCloseNoiseChannel + ELSE + set 5,c ;No noise in compilation, so stops the noise. + ENDIF ;PLY_CFG_SFX_SoftOnly_Noise + + ;Opens the "sound" channel. + res 2,c + + ;Reads the software period. + call PLY_AKM_PSES_ReadSoftwarePeriod + + jr PLY_AKM_PSES_SavePointerAndExit + ENDIF ;PLY_CFG_SFX_SoftOnly + + + ;Software and Hardware. + ;------------------------------------------- + IFDEF PLY_AKM_SE_HardwareSounds ;CONFIG SPECIFIC +PLY_AKM_PSES_SoftwareAndHardware: + ;Calls the shared code that manages everything. + call PLY_AKM_PSES_Shared_ReadRetrigHardwareEnvPeriodNoise + + ;Reads the software period. + call PLY_AKM_PSES_ReadSoftwarePeriod + + ;Opens the sound. + res 2,c + + jr PLY_AKM_PSES_SavePointerAndExit + ENDIF ;PLY_AKM_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_AKM_PSES_Shared_ReadRetrigHardwareEnvPeriodNoise: + ;Retrig? + rra + IFDEF PLY_AKM_SE_Retrig ;CONFIG SPECIFIC + jr nc,PLY_AKM_PSES_H_AfterRetrig + ld d,a + ld a,255 + ld (PLY_AKM_SetReg13Old + PLY_AKM_Offset1b),a + ld a,d +PLY_AKM_PSES_H_AfterRetrig: + ENDIF ;PLY_AKM_SE_Retrig + + ;The hardware envelope can be set (8-15). + and %111 + add a,8 + ld (PLY_AKM_SetReg13 + PLY_AKM_Offset1b),a + + ;Noise? + IFDEF PLY_AKM_SE_HardwareNoise ;CONFIG SPECIFIC. B not needed after, we can put it in the condition too. + rl b + call PLY_AKM_PSES_ReadNoiseIfNeededAndOpenOrCloseNoiseChannel + ELSE + set 5,c ;No noise in compilation, so stops the noise. + ENDIF ;PLY_AKM_SE_HardwareNoise + + ;Reads the hardware period. + call PLY_AKM_PSES_ReadHardwarePeriod + + ;Sets the volume to "hardware". It still may be decreased. + ld a,16 + jp PLY_AKM_PSES_ManageVolumeFromA_Hard + ENDIF ;PLY_CFG_UseHardwareSounds + + + IFDEF PLY_AKM_SE_Noise +;If asked to, reads the noise pointed by HL, increases HL, and opens the noise channel. If no noise, closes the noise channel. +;IN: Carry = true if noise to read. False if no noise, so the noise channel must be closed. +; HL = the data. +PLY_AKM_PSES_ReadNoiseIfNeededAndOpenOrCloseNoiseChannel: + jr c,PLY_AKM_PSES_ReadNoiseAndOpenNoiseChannel_OpenNoise + ;No noise, so closes the noise channel. + set 5,c + ret +PLY_AKM_PSES_ReadNoiseAndOpenNoiseChannel_OpenNoise: + ;Reads the noise. + ld a,(hl) + ld (PLY_AKM_NoiseRegister),a + inc hl + + ;Opens noise channel. + res 5,c + ret + ENDIF ;PLY_AKM_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_AKM_PSES_ReadHardwarePeriod: + ld a,(hl) + ld (PLY_AKM_Reg11),a + inc hl + ld a,(hl) + ld (PLY_AKM_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_AKM_PSES_ReadSoftwarePeriod: + ld a,(hl) + ld (iy + PLY_AKM_Registers_OffsetSoftwarePeriodLSB),a + inc hl + ld a,(hl) + ld (iy + PLY_AKM_Registers_OffsetSoftwarePeriodMSB),a + inc hl + ret + + IFDEF PLY_AKM_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_AKM_PSES_ManageVolumeFromA_Filter4Bits: + and %1111 + ENDIF ;PLY_AKM_SE_VolumeSoft + IFDEF PLY_AKM_SE_VolumeSoftOrHard ;CONFIG SPECIFIC +;After the filtering. Useful for hardware sound (volume has been forced to 16). +PLY_AKM_PSES_ManageVolumeFromA_Hard: + ;Decreases the volume, checks the limit. + sub (ix + PLY_AKM_SoundEffectData_OffsetInvertedVolume) + jr nc,PLY_AKM_PSES_MVFA_NoOverflow + xor a +PLY_AKM_PSES_MVFA_NoOverflow: + ld (iy + PLY_AKM_Registers_OffsetVolume),a + ret + ENDIF ;PLY_AKM_SE_VolumeSoftOrHard + + + ;The data for RAM player. For ROM player, it is declared in the main player. + IFNDEF PLY_AKM_Rom +;The data of the Channels MUST be consecutive. +PLY_AKM_Channel1_SoundEffectData: +dkws (void): + dw 0 ;Points to the sound effect for the track 1, or 0 if not playing. +PLY_AKM_Channel1_SoundEffectInvertedVolume: +dkwe (void): +dkbs (void): + db 0 ;Inverted volume. +PLY_AKM_Channel1_SoundEffectCurrentStep: + db 0 ;Current step (>=0). +PLY_AKM_Channel1_SoundEffectSpeed: + db 0 ;Speed (>=0). + ds 3,0 ;Padding. +dkbe (void): +PLY_AKM_Channel_SoundEffectDataSize: equ $ - PLY_AKM_Channel1_SoundEffectData + +dkbs (void): +PLY_AKM_Channel2_SoundEffectData: + ds PLY_AKM_Channel_SoundEffectDataSize, 0 +PLY_AKM_Channel3_SoundEffectData: + ds PLY_AKM_Channel_SoundEffectDataSize, 0 +dkbe (void): + + ;Checks that the pointers are consecutive. + assert (PLY_AKM_Channel1_SoundEffectData + PLY_AKM_Channel_SoundEffectDataSize) == PLY_AKM_Channel2_SoundEffectData + assert (PLY_AKM_Channel2_SoundEffectData + PLY_AKM_Channel_SoundEffectDataSize) == PLY_AKM_Channel3_SoundEffectData + + ENDIF ;PLY_AKM_Rom + +;Offset from the beginning of the data, to reach the inverted volume. +PLY_AKM_SoundEffectData_OffsetInvertedVolume: equ PLY_AKM_Channel1_SoundEffectInvertedVolume - PLY_AKM_Channel1_SoundEffectData +PLY_AKM_SoundEffectData_OffsetCurrentStep: equ PLY_AKM_Channel1_SoundEffectCurrentStep - PLY_AKM_Channel1_SoundEffectData +PLY_AKM_SoundEffectData_OffsetSpeed: equ PLY_AKM_Channel1_SoundEffectSpeed - PLY_AKM_Channel1_SoundEffectData
\ No newline at end of file |