I could be wrong, but investigating on the use of ayFX I think I have found a bug.
The ayFX player released here
http://z80st-software.blogspot.com/ has a problem in the mixer:
here we have:
@@SETMASKS: ; --- Set mixer masks ---
ld a,c ; a:=Control byte
and $90 ; Only bits 7 and 4 (noise and tone mask for psg reg 7)
cp $90 ; If no noise and no tone...
ret z ; ...return (don't copy ayFX values in to AYREGS)
; --- Copy ayFX values in to ARYREGS ---
rrc a ; Rotate a to the right (1 TIME)
rrc a ; Rotate a to the right (2 TIMES) (OR mask)
ld d,$DB ; d:=Mask for psg mixer (AND mask)
; --- Calculate next ayFX channel ---
ld hl,ayFX_CHANNEL ; Old ayFX playing channel
dec [hl] ; New ayFX playing channel
jp nz,@@SETCHAN ; If not zero jump to @@SETCHAN
ld [hl],3 ; If zero -> set channel 3
@@SETCHAN: ld b,[hl] ; Channel counter
@@CHK1: ; --- Check if playing channel was 1 ---
djnz @@CHK2 ; Decrement and jump if channel was not 1
@@PLAY_C: ; --- Play ayFX stream on channel C ---
call @@SETMIXER ; Set PSG mixer value (a:=ayFX volume)
....
Cntering in this segment, C is the current control byte of the sfx.
The segment analyzes bits 7 and 4 of C
When we call SETMIXER, A is a mask derived from C, where only bits 5 and 2 have meaning.
In SETMIXER we have this:
@@SETMIXER: ; --- Set PSG mixer value ---
ld c,a ; c:=OR mask
ld a,[AYREGS+7] ; a:=PSG mixer value
and d ; AND mask
or c ; OR mask
ld [AYREGS+7],a ; PSG mixer value updated
ld a,[ayFX_VOLUME] ; a:=ayFX volume value
ret ; Return
ayFX_END: ; --- End of an ayFX stream ---
xor a ; a:=0
ld [ayFX_PLAYING],a ; There's no ayFX stream to be played!
dec a ; a:=255
ld [ayFX_CURRENT],a ; Lower ayFX stream
ret ; Return
Thus, on exit, C has only bit 5 and 2 that can have meaning.
The problem is now, as the following code pretend to read c as it were register 7 of the AY8910.
The code in fact, tests for bit 2, 1 or 0 in branches for channels C,B and A
....
ld [AYREGS+10],a ; Volume copied in to AYREGS (channel C volume)
bit 2,c ; If tone is off...
ret nz ; ...return
ld hl,[ayFX_TONE] ; ayFX tone value
ld [AYREGS+4],hl ; copied in to AYREGS (channel C tone)
ret ; Return
@@CHK2: ; --- Check if playing channel was 2 ---
rrc d ; Rotate right AND mask
rrc a ; Rotate right OR mask
djnz @@CHK3 ; Decrement and jump if channel was not 2
@@PLAY_B: ; --- Play ayFX stream on channel B ---
call @@SETMIXER ; Set PSG mixer value (a:=ayFX volume)
ld [AYREGS+9],a ; Volume copied in to AYREGS (channel B volume)
bit 1,c ; If tone is off...
ret nz ; ...return
ld hl,[ayFX_TONE] ; ayFX tone value
ld [AYREGS+2],hl ; copied in to AYREGS (channel B tone)
ret ; Return
@@CHK3: ; --- Check if playing channel was 3 ---
rrc d ; Rotate right AND mask
rrc a ; Rotate right OR mask
@@PLAY_A: ; --- Play ayFX stream on channel A ---
call @@SETMIXER ; Set PSG mixer value (a:=ayFX volume)
ld [AYREGS+8],a ; Volume copied in to AYREGS (channel A volume)
bit 0,c ; If tone is off...
ret nz ; ...return
ld hl,[ayFX_TONE] ; ayFX tone value
ld [AYREGS+0],hl ; copied in to AYREGS (channel A tone)
ret
I think that in SETMIXER there is a missing bit that loads in C the value that the rest of the code tests.
Shappire do you agree?
IMHO a patch could be to add a ld c,a here
@@SETMIXER: ; --- Set PSG mixer value ---
ld c,a ; c:=OR mask
ld a,[AYREGS+7] ; a:=PSG mixer value
and d ; AND mask
or c ; OR mask
ld [AYREGS+7],a ; PSG mixer value updated
[b] LD C,A[/b]
ld a,[ayFX_VOLUME] ; a:=ayFX volume value
ret ; Return
ayFX_END: ; --- End of an ayFX stream ---
xor a ; a:=0
ld [ayFX_PLAYING],a ; There's no ayFX stream to be played!
dec a ; a:=255
ld [ayFX_CURRENT],a ; Lower ayFX stream
ret ; Return