aboutsummaryrefslogtreecommitdiff
path: root/src/mplayer/akm/PlayerAkm_SoundEffects.asm
diff options
context:
space:
mode:
authorJuan J. Martinez <jjm@usebox.net>2020-12-30 19:07:31 +0000
committerJuan J. Martinez <jjm@usebox.net>2020-12-30 19:23:41 +0000
commit2682bc5d1d864341aaeb42a449db73c3ecd16d70 (patch)
tree9116764364b4ee0ce7f6037305077807b57776de /src/mplayer/akm/PlayerAkm_SoundEffects.asm
downloadubox-msx-lib-2682bc5d1d864341aaeb42a449db73c3ecd16d70.tar.gz
ubox-msx-lib-2682bc5d1d864341aaeb42a449db73c3ecd16d70.zip
Initial import1.0
Diffstat (limited to 'src/mplayer/akm/PlayerAkm_SoundEffects.asm')
-rw-r--r--src/mplayer/akm/PlayerAkm_SoundEffects.asm477
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