
;Procedure playing synchronized distortion C sounds.
;The synchronization of timers with poly4 counter takes place on demand (syncWithPoly4Flag must be set to !=0).
;This is the implementation of synchronization method which uses (writes to) STIMER register.
;It is fast and simple method of synchronization. The drawback is an audible click on all the channels because of reloading timers.
;
;Author: Pawel Rosowski (pavros)
;Date: 2018.04.09

playAndSync
	lda vAudCtl
	sta audctl

	ldx #3
plySnd1
	ldy voiceControlX,X
	lda voiceControlToAudC,Y
	sta vAudCx,X
	lda vAudFx,X
	sta vSAudFx,X
	dex
	bpl plySnd1

	lda syncWithPoly4Flag
	and syncWithPoly4MasterFlag
	bne plySnd2
	jmp plySnd4
plySnd2
	clc ; clear carry bit; it will be used to indicate whether any channel plays distortion C and needs to be synchronized with poly4 counter
	
	lda vAudCtl ; 0 = normal base clock (div28/64kHz), 1 = low base clock (div114/15kHz)
	and #$01
	bne plySndSynL1

; set synchronization point selectors (initial AUDFx values) based on selected Ex elements of poly4 sequence for normal base clock (div28/64kHz)
plySndSynN1
	lda voiceControlX + 0
	bne plySndSynN2 ; branch if voiceControlX != VoiceWaveC = 0
	ldx poly4SyncPointX + 0
	lda spToAudFCh1N,X
	sta vSAudF1
	sec
plySndSynN2
	lda voiceControlX + 1
	bne plySndSynN3
	ldx poly4SyncPointX + 1
	lda spToAudFCh2N,X
	sta vSAudF2
	sec
plySndSynN3
	lda voiceControlX + 2
	bne plySndSynN4
	ldx poly4SyncPointX + 2
	lda spToAudFCh3N,X
	sta vSAudF3
	sec
plySndSynN4
	lda voiceControlX + 3
	bne plySndSynN5
	ldx poly4SyncPointX + 3
	lda spToAudFCh4N,X
	sta vSAudF4
	sec
plySndSynN5
	bcs plySnd3 ; some voice requires sync
	jmp plySnd4 ; no voice requires sync

; set synchronization point selectors (initial AUDFx values) based on selected Ex elements of poly4 sequence for low base clock (div114/15kHz)
plySndSynL1
	lda voiceControlX + 0
	bne plySndSynL2 ; branch if voiceControlX != VoiceWaveC = 0
	ldx poly4SyncPointX + 0
	ldy sp15To5,X
	lda spToAudFCh1L,Y
	sta vSAudF1
	sec
plySndSynL2
	lda voiceControlX + 1
	bne plySndSynL3
	ldx poly4SyncPointX + 1
	ldy sp15To5,X
	lda spToAudFCh2L,Y
	sta vSAudF2
	sec
plySndSynL3
	lda voiceControlX + 2
	bne plySndSynL4
	ldx poly4SyncPointX + 2
	ldy sp15To5,X
	lda spToAudFCh3L,Y
	sta vSAudF3
	sec
plySndSynL4
	lda voiceControlX + 3
	bne plySndSynL5
	ldx poly4SyncPointX + 3
	ldy sp15To5,X
	lda spToAudFCh4L,Y
	sta vSAudF4
	sec
plySndSynL5
	bcc plySnd4 ; no voice requires sync

;synchronize channels with poly4 counter
plySnd3
	lda #0
	sta skctl
	; the period of resetting POKEY (SKCTL = 0) should last for at least 17 cycles to clear the longest 17-bit polycounter;

	; set AUDFx registers with synchronization point selectors
	lda vSAudF1
	sta audF1
	lda vSAudF2
	sta audF2
	lda vSAudF3
	sta audF3
	lda vSAudF4
	sta audF4

	sta stimer

plySnd4
	; set AUDFx registers with desired frequency divisors
	lda vAudF1
	sta audF1
	lda vAudF2
	sta audF2
	lda vAudF3
	sta audF3
	lda vAudF4
	sta audF4

	lda #3
	sta skctl ; put POKEY back to normal work/finish resetting

	lda vAudC1
	sta audC1
	lda vAudC2
	sta audC2
	lda vAudC3
	sta audC3
	lda vAudC4
	sta audC4

	lda syncWithPoly4Flag
	beq plySnd5
	lda #0
	sta syncWithPoly4Flag
	lda syncWithPoly4MasterFlag
	beq plySnd5
	;activate key debuncing after POKEY reset
	jsr activateKeyDebouncing

plySnd5
	lda continuousPhaseMod
	beq plySnd6
	jsr delayAccuratePhase
plySnd6
	rts


syncWithPoly4Flag
	.db 1
syncWithPoly4MasterFlag
	.db 1
poly4SyncPointX
	:4 .db 1 ; Default is E1 which belongs to ST1 sampling track

vSAudFx
vSAudF1
	.db 0
vSAudF2
	.db 0
vSAudF3
	.db 0
vSAudF4
	.db 0

vAudFx
vAudF1
	.db $3E ;$F5 ;$1F ;$BF
vAudF2
	.db $3E
vAudF3
	.db $3E
vAudF4
	.db $3E

vAudCx
vAudC1
	.db 0
vAudC2
	.db 0
vAudC3
	.db 0
vAudC4
	.db 0

vAudCtl
	.db 0 ; 0 = normal base clock (div28/64kHz), 1 = low base clock (div114/15kHz)

voiceControlToAudC
	.db $C8, $A8, $A0

voiceControlX
	.db VoiceOff
	.db VoiceOff
	.db VoiceWaveC ; initially audible
	.db VoiceOff

scale
	.db 0 ; 0 - diatonic (8 steps), 1 - chromatic (13 steps)
octave
	.db 2
continuousPhaseMod
	.db 0

;mapping: synchronization point number from range 0-14 (normal base clock) -> range 0-5 (low base clock); GUI handles 15 sync points but we need only 5 for low base clock
sp15To5
	.db 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2, 3, 4
