Topic: 6502 Conversion of Squeeker Plus Engine
I’ve been working on converting the Z80 Squeeker Plus engine by utz to the 6502. A work in progress but getting reasonable results so far.
Drums are very off compared to the Z80, and the pitch still needs some work.
You can see the current progress here:
https://m.youtube.com/watch?v=W1Br7rr8cps
If you’re interested in the code (and can help eliminating bugs / inconsistencies / misinterpretations) this is what I have so far (BeebAsm format for the BBC Micro):
VIA_DDRA = $FE43
VIA_DDRB = $FE42
VIA_ORA = $FE41
VIA_ORB = $FE40
SN_LOUD = $90
SN_MUTE = $9F
SAMPLES_PER_FRAME = 260
SAMPLES_LO = SAMPLES_PER_FRAME AND 255
SAMPLES_HI = SAMPLES_PER_FRAME DIV 256
ORG 0
.seq_ptr SKIP 2
.row_timer SKIP 1
.sample_count SKIP 2
.tmp_mix SKIP 1
.ctrl_a SKIP 1
.ctrl_b SKIP 1
.pat_ptr SKIP 2
.drum_flag SKIP 1
.drum_index SKIP 1
.drum_delay SKIP 1
.drum_state SKIP 1
.ch1_f SKIP 2
.ch1_a SKIP 2
.ch1_e SKIP 2
.ch1_d SKIP 1
.ch1_n SKIP 1
.ch2_f SKIP 2
.ch2_a SKIP 2
.ch2_e SKIP 2
.ch2_d SKIP 1
.ch2_n SKIP 1
.ch3_f SKIP 2
.ch3_a SKIP 2
.ch3_e SKIP 2
.ch3_d SKIP 1
.ch4_f SKIP 2
.ch4_a SKIP 2
.ch4_e SKIP 2
.ch4_d SKIP 1
.ch4_s SKIP 1
ORG $1100
.start
SEI
JSR init_hw
LDA #LO(music_data+2)
STA seq_ptr
LDA #HI(music_data+2)
STA seq_ptr+1
JSR fetch_new_pattern
JMP check_row
.pattern_end
LDA seq_ptr
CLC
ADC #2
STA seq_ptr
BCC p_next
INC seq_ptr+1
.p_next
LDY #0
LDA (seq_ptr),Y
STA pat_ptr
INY
LDA (seq_ptr),Y
STA pat_ptr+1
LDA pat_ptr
ORA pat_ptr+1
BNE check_row
LDA music_data
STA seq_ptr
LDA music_data+1
STA seq_ptr+1
JMP pattern_end
.check_row
LDY #0
LDA (pat_ptr),Y
CMP #$40
BEQ pattern_end
.rdseq
LDA (pat_ptr),Y
INY
STA ctrl_a
LDA (pat_ptr),Y
INY
STA row_timer
LDA (pat_ptr),Y
STA ch2_n
INY
LDA (pat_ptr),Y
STA ch1_n
INY
LDA ctrl_a
LSR A
BCS ld2
LDA (pat_ptr),Y
STA ch1_f
INY
LDA (pat_ptr),Y
STA ch1_f+1
INY
LDA (pat_ptr),Y
STA ch1_e
INY
LDA (pat_ptr),Y
STA ch1_e+1
INY
LDA #0
STA ch1_a
STA ch1_a+1
STY tmp_mix
LDY #0
LDA (ch1_e),Y
STA ch1_d
LDY tmp_mix
.ld2
LDA ctrl_a
AND #4
BNE ld3
LDA (pat_ptr),Y
STA ch2_f
INY
LDA (pat_ptr),Y
STA ch2_f+1
INY
LDA (pat_ptr),Y
STA ch2_e
INY
LDA (pat_ptr),Y
STA ch2_e+1
INY
LDA #0
STA ch2_a
STA ch2_a+1
STY tmp_mix
LDY #0
LDA (ch2_e),Y
STA ch2_d
LDY tmp_mix
.ld3
BIT ctrl_a
BMI ld4
LDA (pat_ptr),Y
STA ch3_f
INY
LDA (pat_ptr),Y
STA ch3_f+1
INY
LDA (pat_ptr),Y
STA ch3_e
INY
LDA (pat_ptr),Y
STA ch3_e+1
INY
LDA #0
STA ch3_a
STA ch3_a+1
STY tmp_mix
LDY #0
LDA (ch3_e),Y
STA ch3_d
LDY tmp_mix
.ld4
LDA (pat_ptr),Y
STA ctrl_b
INY
INY
LDA #0
STA drum_flag
LDA ctrl_b
AND #$04
BEQ no_kick
LDA #1
STA drum_flag
LDA #0
STA drum_index
STA drum_delay
LDA #SN_MUTE
STA drum_state
.no_kick
LDA ctrl_b
AND #$80
BEQ no_hat
LDA #2
STA drum_flag
LDA #0
STA drum_index
STA drum_delay
LDA #SN_MUTE
STA drum_state
.no_hat
LDA ctrl_b
AND #$40
BNE skip4
LDA (pat_ptr),Y
STA ch4_f
INY
LDA (pat_ptr),Y
STA ch4_f+1
INY
LDA (pat_ptr),Y
STA ch4_e
INY
LDA (pat_ptr),Y
STA ch4_e+1
INY
LDA #0
STA ch4_a
STA ch4_a+1
STY tmp_mix
LDY #0
LDA (ch4_e),Y
STA ch4_d
LDY tmp_mix
.skip4
LDA ctrl_b
AND #1
STA ch4_s
TYA
CLC
ADC pat_ptr
STA pat_ptr
BCC p_adv
INC pat_ptr+1
.p_adv
LDA ch1_n
BEQ ch1_no_noise_smc
LDA #$6A
STA ch1_noise_op
LDA #$EA
STA ch1_noise_op+1
JMP ch2_smc
.ch1_no_noise_smc
LDA #$EA
STA ch1_noise_op
STA ch1_noise_op+1
.ch2_smc
LDA ch2_n
BEQ ch2_no_noise_smc
LDA #$6A
STA ch2_noise_op
LDA #$EA
STA ch2_noise_op+1
JMP start_synth
.ch2_no_noise_smc
LDA #$EA
STA ch2_noise_op
STA ch2_noise_op+1
.start_synth
LDA #SAMPLES_LO
STA sample_count
LDA #SAMPLES_HI
STA sample_count+1
CLC
.synth_loop
LDA #0
STA tmp_mix
\ Channel 1
LDA ch1_a
ADC ch1_f
STA ch1_a
LDA ch1_a+1
ADC ch1_f+1
STA ch1_a+1
.ch1_noise_op
NOP
NOP
ADC ch1_d
ROL tmp_mix
\ Channel 2
LDA ch2_a
ADC ch2_f
STA ch2_a
LDA ch2_a+1
ADC ch2_f+1
STA ch2_a+1
.ch2_noise_op
NOP
NOP
ADC ch2_d
ROL tmp_mix
\ Channel 3
LDA ch3_a
ADC ch3_f
STA ch3_a
LDA ch3_a+1
ADC ch3_f+1
STA ch3_a+1
ADC ch3_d
ROL tmp_mix
\ Channel 4
LDA ch4_a
ADC ch4_f
STA ch4_a
LDA ch4_a+1
ADC ch4_f+1
STA ch4_a+1
ADC ch4_d
ROL tmp_mix
LDA tmp_mix
ADC #$0F
TAX
CPX #$10
LDA #SN_MUTE
BCS vol_set
LDA #SN_LOUD
.vol_set
TAY
LDX drum_flag
BEQ output_no_drum
LDX drum_delay
BEQ need_new_sample
DEC drum_delay
LDA drum_state
JMP mix_tone_drum
.need_new_sample
LDX drum_flag
DEX
BEQ need_load_kick
DEX
BEQ need_load_hat
LDA drum_state
JMP mix_tone_drum
.need_load_kick
LDX drum_index
CPX #20
BCS need_kick_end
LDA kick_data,X
STA drum_delay
INC drum_index
LDA drum_state
EOR #$0F
STA drum_state
JMP mix_tone_drum
.need_kick_end
LDA #0
STA drum_flag
STA drum_delay
LDA drum_state
JMP mix_tone_drum
.need_load_hat
LDX drum_index
CPX #20
BCS need_hat_end
LDA hat_data,X
STA drum_delay
INC drum_index
LDA drum_state
EOR #$0F
STA drum_state
JMP mix_tone_drum
.need_hat_end
LDA #0
STA drum_flag
STA drum_delay
LDA drum_state
JMP mix_tone_drum
.output_no_drum
TYA
STA VIA_ORA
LDA #0
STA VIA_ORB
LDA #8
STA VIA_ORB
JMP sample_decrement
\ Mix tone and drum
.mix_tone_drum
STA ctrl_a
CPY #SN_LOUD
BNE drum_only
CMP #SN_LOUD
BNE tone_only
LDA #$98
JMP output_mixed
.drum_only
LDA ctrl_a
JMP output_mixed
.tone_only
TYA
.output_mixed
STA VIA_ORA
LDA #0
STA VIA_ORB
LDA #8
STA VIA_ORB
.sample_decrement
LDA sample_count
BNE dec_lo
DEC sample_count+1
.dec_lo
DEC sample_count
LDA sample_count
ORA sample_count+1
BEQ update_timer
JMP synth_loop
.update_timer
LDY #0
INC ch1_e
BNE e1
INC ch1_e+1
.e1
LDA (ch1_e),Y
CMP #$80
BEQ e2
STA ch1_d
.e2
INC ch2_e
BNE e2_skip
INC ch2_e+1
.e2_skip
LDA (ch2_e),Y
CMP #$80
BEQ e3
STA ch2_d
.e3
INC ch3_e
BNE e3_skip
INC ch3_e+1
.e3_skip
LDA (ch3_e),Y
CMP #$80
BEQ e4
STA ch3_d
.e4
INC ch4_e
BNE e4_skip
INC ch4_e+1
.e4_skip
LDA (ch4_e),Y
CMP #$80
BEQ slide_proc
STA ch4_d
.slide_proc
LDA ch4_s
BEQ noslide
LDA ch4_f+1
LSR A
TAX
LDA ch4_f
ROR A
TAY
SEC
LDA ch4_f
STY tmp_mix
SBC tmp_mix
STA ch4_f
LDA ch4_f+1
STX tmp_mix
SBC tmp_mix
STA ch4_f+1
.noslide
DEC row_timer
BNE play_same_row
JMP check_row
.play_same_row
LDA #SAMPLES_LO
STA sample_count
LDA #SAMPLES_HI
STA sample_count+1
CLC
JMP synth_loop
.fetch_new_pattern
LDY #0
LDA (seq_ptr),Y
STA pat_ptr
INY
LDA (seq_ptr),Y
STA pat_ptr+1
LDA pat_ptr
ORA pat_ptr+1
BNE fetch_done
LDA music_data
STA seq_ptr
LDA music_data+1
STA seq_ptr+1
JMP fetch_new_pattern
.fetch_done
RTS
.kick_data
EQUB 1,1,1,1,2,2,2,2
EQUB 3,3,3,4,4,4,5,5
EQUB 6,6,7,7
.hat_data
EQUB 16,3,12,6,9
EQUB 20,4,8,2,14
EQUB 9,17,5,8,12
EQUB 4,7,16,13,22
EQUB 5,3,16,3,12
.init_hw
LDA #$9F
JSR sn_w
LDA #$BF
JSR sn_w
LDA #$DF
JSR sn_w
LDA #$FF
JSR sn_w
LDA #$FF
STA VIA_DDRA
LDA #$0F
STA VIA_DDRB
LDA #$81
JSR sn_w
LDA #$00
JSR sn_w
RTS
.sn_w
STA VIA_ORA
LDX #0
STX VIA_ORB
LDX #8
STX VIA_ORB
RTS
ORG $2000
INCLUDE "tracks\Squeeker Plus\1-bit_high_and_rising.asm"
.end
SAVE "MAIN",start,end