Hamazing/source/framework/musicplayers/raspberry_casket_wavegen.asm
chrisly42 9c48c11cd1 Big "squashed" update to latest version of Framework.
- Bugfix: WaitForFrame was completely broken. Now also caters for race-condition that would have waited one extra frame.
- Bugfix: InitPart would overwrite innocent memory (reported by Gigabates and Losso)
- Bugfix: Palette LERP had wrong bias.
- Removed extra paths in include statement, use default include paths instead
- Added Raspberry Casket no-jitter background calc mode (FW_MUSIC_PLAYER_CHOICE = 6)
- Updated Raspberry Casket to V2.0 presto branch (WIP)
- Removed fw_FrameCounterLong, use fw_FrameCounter-2 for debug purposes
- Support for blue noise palette LERPing (like in Is Real). Provide your own blue noise table (4 KB), stuff it into fw_BlueNoiseTablePtr, set FW_PALETTE_LERP_SUPPORT to 2
- Music tick routine is now replaceable during runtime (fw_MusicTickRoutine)
- Support for softints and audio interrupts
- LMB exit can also be disabled dynamically when using FW_LMB_EXIT_SUPPORT = 2 and fw_DisableLMBExit != 0
- Added LSP Micro support and LSP Nano (custom format that uses note pitches instead of periods)
- Minor other things
2024-09-15 17:43:33 +02:00

1295 lines
33 KiB
NASM

CLIPTO8BIT MACRO
cmp.w #-$80,\1
bge.s .nominclip\@
moveq.l #-$80,\1
.nominclip\@
cmp.w #$7f,\1
ble.s .nomaxclip\@
moveq.l #$7f,\1
.nomaxclip\@
ENDM
CLIPORTRUNC8BIT MACRO
beq.s .unboosted\@
asr.l #6,\1
cmp.w #-$80,\1
bge.s .nominclip\@
moveq.l #-$80,\1
.nominclip\@
cmp.w #$7f,\1
ble.s .nomaxclip\@
moveq.l #$7f,\1
bra.s .nomaxclip\@
.unboosted\@
asr.l #8,\1
.nomaxclip\@
ENDM
CLIPTO8BITAFTERADD MACRO
bvc.s .noclip\@
spl \1
eor.b #$7f,\1
.noclip\@
ENDM
; ----------------------------------------
; proposed register assignment:
; a1 = Wave table order
; a4 = MyPlayer
; a6 = MySong / waveinfo
pre_WaveGen:
; ----------------------------------------
lea .pre_log12_table(pc),a0 ; 128, 121, 114, 107, 102, 96, 90, 85, 80, 76, 72, 67
lea pv_osc_buffers+owb_sqr_waves(a4),a3
moveq.l #NOTES_IN_OCTAVE-1,d7
.noteloop
swap d7
moveq.l #0,d6
move.w d6,d7 ; tabpos
move.b (a0)+,d6 ; period
move.l #$ff00,d5
divu d6,d5 ; frac increment
move.w d6,d4
lsr.w #1,d4 ; half-period
move.w d4,d3
lsr.w #1,d3 ; quarter-period
moveq.l #0,d0 ; acc
lea (a3,d6.w),a2
lea owb_tri_waves-owb_sqr_waves(a2),a2
suba.w d3,a2
.notewaveloop
move.w d0,d2
lsr.w #8,d2
moveq.l #$7f,d1
sub.b d2,d1
move.b d1,owb_saw_waves-owb_sqr_waves(a3,d7.w)
add.b d2,d2
cmp.w d7,d3 ; tabpos == negquarter
bne.s .nowrapback
suba.w d6,a2 ; go back to start of period
.nowrapback
cmp.w d0,d7
ble.s .otherhalf
moveq.l #$7f,d1
sub.b d2,d1
move.b d1,(a2)+
bra.s .clip80
.otherhalf
add.b #$80,d2
move.b d2,(a2)+
moveq.l #$7f,d2
cmp.w d7,d4
bne.s .noclip80
.clip80 moveq.l #-$80,d2
.noclip80
move.b d2,owb_sqr_waves-owb_sqr_waves(a3,d7.w)
add.w d5,d0 ; increment acc by frac
addq.w #1,d7 ; increment pos
cmp.w d7,d6
bne.s .notewaveloop
swap d7
lea owb_SIZEOF(a3),a3
dbra d7,.noteloop
; ----------------------------------------
; proposed register assignment:
; a0 = sample output
; a1 = scratch
; a3 = waveinfo
; a4 = MyPlayer
; a6 = MySong / waveinfo
.wavegenloop
;movea.l pv_my_song(a4),a6
moveq.l #0,d1
move.b (a1)+,d1 ; apply wave order redirection
move.l a1,-(sp) ; what used to be sv_wavegen_order_table
IFNE PRETRACKER_PARANOIA_MODE ; same wave for mixing cannot be selected in Pretracker
move.b d1,pv_wg_curr_wave_num_b(a4)
ENDC
lsl.w #2,d1
move.l pv_wave_sample_table(a4,d1.w),a0
move.l a0,pv_wg_curr_sample_ptr(a4)
IFND PRESTO_UNIFIED_STRUCT
add.w #sv_wavelength_table,d1
adda.w d1,a6
move.l sv_wavelength_table-sv_wavelength_table(a6),d0
move.l d0,pv_wg_curr_sample_len_l(a4)
IFNE PRETRACKER_PROGRESS_SUPPORT
move.l sv_wavetotal_table-sv_wavelength_table(a6),pv_precalc_sample_size(a4)
ENDC
move.l sv_waveinfo_table-sv_wavelength_table(a6),a3
ELSE ; PRESTO_UNIFIED_STRUCT
; Presto has no MySong structure
lea pv_wavelength_table(a4,d1.w),a6
; copied from raspberry_casket
moveq.l #0,d0
move.b wi_sam_len_b(a3),d0
addq.w #1,d0
lsl.w #7,d0
move.l d0,pv_wavelength_table-pv_wavelength_table(a6)
move.l d0,d1
btst #2,wi_flags_b(a3)
beq.s .onlythreeocts
mulu #15,d1
lsr.l #3,d1 ; * 1.875
.onlythreeocts
move.l d1,pv_wavetotal_table-pv_wavelength_table(a6)
; end stuff
move.l d0,pv_wg_curr_sample_len_l(a4)
IFNE PRETRACKER_PROGRESS_SUPPORT
move.l d1,pv_precalc_sample_size(a4)
ENDC
move.l pv_waveinfo_table-pv_wavelength_table(a6),a3
ENDC ; PRESTO_UNIFIED_STRUCT
; clear sample data (a0 and d0 from above)
bsr pre_MemClr
move.l a0,pv_wg_curr_samend_ptr(a4)
; read out chord information
lea wi_chord_note1_b(a3),a1
move.b (a1)+,d1
move.b (a1)+,d2
move.b (a1)+,d3
moveq.l #0,d4
move.b d1,d4
or.b d2,d4
or.b d3,d4
seq d4
neg.b d4
move.w d4,pv_wg_chord_flag_w(a4) ; has chord flag (0/1)
move.b wi_osc_basenote_b(a3),d0
add.b d0,d1
add.b d0,d2
add.b d0,d3
lea pv_wg_chord_pitches(a4),a1
move.b d0,(a1)+
move.b d1,(a1)+
move.b d2,(a1)+
move.b d3,(a1)+
clr.w pv_wg_chord_note_num_b(a4) ; and pv_wg_chord_note_num_b
.wavegen_chordloop
lea pv_wg_chord_pitches(a4),a1
moveq.l #0,d1
move.b pv_wg_chord_note_num_b(a4),d1 ; chord note counter
move.b (a1,d1.w),d0 ; get chord note
ext.w d0
tst.w d1
beq.s .base_note_is_never_skipped ; is base note?
cmp.b wi_osc_basenote_b(a3),d0
beq .wave_gen_tone_done ; skip chord notes that are same as base note
.base_note_is_never_skipped
moveq.l #0,d5
moveq.l #NOTES_IN_OCTAVE,d2
move.w d0,d5
move.w d0,a2 ; save base note, used later (much later, noise generator)!
add.w #NOTES_IN_OCTAVE*NOTES_IN_OCTAVE,d5 ; make sure we don't run into negative modulo
divu d2,d5
sub.w d2,d5 ; restore octave, result may be negative
move.w d5,d1 ; +-octave
swap d5 ; note within octave
moveq.l #0,d7
move.b .pre_log12_table(pc,d5.w),d7 ; 128, 121, 114, 107, 102, 96, 90, 85, 80, 76, 72, 67
moveq.l #3,d0
mulu d0,d5
and.b wi_flags_b(a3),d0
beq.s .osc_selected
addq.w #2,d5
subq.w #1,d0
beq.s .osc_selected
subq.w #1,d5
subq.w #1,d0
.osc_selected
lea pv_osc_buffers+owb_saw_waves(a4),a6
lsl.w #7,d5
adda.w d5,a6
; ----------------------------------------
; pitch ramp
move.b wi_pitch_ramp_b(a3),d2
ext.w d2
ext.l d2
btst #4,wi_flags_b(a3) ; pitch linear flag
beq.s .pitch_not_linear
tst.w d2
bgt.s .pitch_ramp_positive
; FIXME what happens if d1 is negative? rolls out by 63?
lsl.l d1,d2
add.l d2,d2
bra.s .pitch_ramp_cont
.pre_log12_table
dc.b $400000/$8000,$400000/$871d,$400000/$8f2f,$400000/$97b7,$400000/$9fc4,$400000/$a9de
dc.b $400000/$b505,$400000/$bf49,$400000/$cb31,$400000/$d645,$400000/$e215,$400000/$f1a0
.pitch_not_linear
tst.w d2
ble.s .pitch_ramp_cont
.pitch_ramp_positive
muls d2,d2
.pitch_ramp_cont
lsl.l #8,d2
lsl.l #2,d2
; check whether we have a noise oscillator or something else
tst.w d0
beq .no_noise
; ----------------------------------------
; d0 = scratch
; d1 = octave
; d2 = pitch ramping value
; d4 = scratch
; a2 = base note
.gen_noise
suba.l a6,a6
IFNE PRETRACKER_PARANOIA_MODE
tst.w pv_wg_curr_sample_len_w(a4)
beq .wave_gen_tone_done
ENDC
moveq.l #1,d5
ror.w #1,d5 ; $00008000
move.l d5,a5
tst.w d1
bge.s .gen_noise_positive_octave
.gen_noise_negative_octave
moveq.l #NOTES_IN_OCTAVE,d1
move.l a2,d3
neg.l d3
move.l d3,d0
divu d1,d0
IFNE PRETRACKER_PARANOIA_MODE
bvs.s .divisionoverflow
ENDC
addq.w #1,d0
lsr.w d0,d5
moveq.l #0,d0
move.w d5,d0
divu d1,d0
moveq.l #0,d4
move.w d0,d4
IFNE PRETRACKER_PARANOIA_MODE
bra.s .returnfromoverflow
.divisionoverflow
move.l #$AAA,d4 ; some dummy value, I would expect
.returnfromoverflow
ENDC
moveq.l #0,d0
move.w d3,d0
.cheap_mod12
sub.w d1,d0
bpl.s .cheap_mod12
neg.w d0
mulu d4,d0
add.l d0,d5
.gen_noise_positive_octave
moveq.l #0,d0
move.b wi_osc_phase_min_b(a3),d0
moveq.l #0,d1
move.b wi_chord_shift_b(a3),d1
add.w d1,d0
addq.w #1,d0
; sum of phase min and shift are used as root for noise
movea.l d5,a1
movea.l pv_wg_curr_sample_ptr(a4),a0
moveq.l #0,d1
moveq.l #0,d6
moveq.l #0,d3
move.b wi_osc_gain_b(a3),d3
.gen_noise_outerloop
move.w d0,d1 ; random noise generator
lsl.w #8,d1
lsl.w #5,d1
eor.w d1,d0
move.w d0,d1
lsr.w #8,d1
lsr.w #1,d1
eor.w d1,d0
move.w d0,d1
lsl.w #7,d1
eor.w d1,d0
move.b d0,d1 ; take the random seed
ext.w d1
muls d3,d1 ; multiply by gain
asr.w #7,d1
CLIPTO8BIT d1
add.b (a0),d1
move.w a5,d4
subq.w #1,d4
and.w #$7fff,d4
move.w d4,a5
addq.w #1,a5
.gen_noise_innerloop
move.b d1,(a0)+
cmp.l pv_wg_curr_samend_ptr(a4),a0
beq .wave_gen_tone_done
adda.l a1,a5
tst.l d2
beq.s .gen_noise_no_pitch_ramping
add.l d2,d6
move.l d6,d4
asr.l #8,d4
asr.l #2,d4
add.l d5,d4
movea.l d4,a1
btst #4,wi_flags_b(a3) ; pitch linear flag
beq.s .noise_nonlinear_pitch
move.l d2,d4 ; filter pitch speed
asr.l #7,d4
sub.l d4,d2
.noise_nonlinear_pitch
cmp.w #$1ff,a1
bgt.s .gen_noise_no_end_of_pitch_ramp
moveq.l #0,d2 ; stop pitch ramping
move.l d2,a5
movea.w #$200,a1
.gen_noise_no_end_of_pitch_ramp
.gen_noise_no_pitch_ramping
cmp.w a5,a5
beq.s .gen_noise_innerloop
bra .gen_noise_outerloop
; ----------------------------------------
; d1 = octave
; d2 = pitch ramping value
; d5 = osc phase speed
; a2 = base note
.no_noise
moveq.l #15,d5
lsl.l d5,d7
sub.w d1,d5 ; 15-octave
lsl.w #3,d5
moveq.l #0,d3
move.b wi_osc_phase_min_b(a3),d3
mulu d5,d3
lsl.l #6,d3
moveq.l #0,d0
move.b wi_osc_phase_max_b(a3),d0
mulu d5,d0
lsl.l #6,d0
move.l d0,a5
moveq.l #0,d5
move.b wi_osc_phase_spd_b(a3),d5
lsl.l #8,d5
lsl.l #3,d5
cmp.l d3,d0
bge.s .osc_with_positive_phase_speed
neg.l d5
movea.l d3,a5
bra.s .osc_continue
.osc_with_positive_phase_speed
move.l d3,d0
.osc_continue
move.l d0,pv_wg_osc_speed_l(a4)
; I think this calculates the base oscillator speed for higher and lower octaves
moveq.l #1,d6
moveq.l #15,d0
add.w d1,d0
lsl.l d0,d6
; d0 = d6 * chord_shift * chordnum + d6 * phase_min = d6 * (chord_shift * chordnum + phase_min)
moveq.l #0,d4
move.b wi_chord_shift_b(a3),d4
move.w pv_wg_chord_flag_w(a4),d0
add.b pv_wg_chord_note_num_b(a4),d0
mulu d0,d4
moveq.l #0,d0
move.b wi_osc_phase_min_b(a3),d0
add.w d0,d4
move.l d6,d0
lsr.l #4,d0
lsl.l #4,d4
mulu d4,d0
.osc_loop_until_in_range
sub.l d7,d0
bgt.s .osc_loop_until_in_range
add.l d7,d0
move.l d6,d1
tst.b pv_wg_unisono_run_b(a4)
beq.s .is_not_in_unisono
moveq.l #3<<3,d1
and.b wi_mod_density_b(a3),d1
lsr.w #3,d1
moveq.l #9,d4
sub.w d1,d4
move.l d6,d1
asr.l d4,d1
add.l d6,d1
.is_not_in_unisono
IFNE PRETRACKER_PARANOIA_MODE
tst.w pv_wg_curr_sample_len_w(a4)
beq .wave_gen_tone_done
ENDC
; ----------------------------------------
; chord gen
; in: d0/d1/d2/d3/d5/d7
; in: a0
move.l d3,a1
movea.l pv_wg_curr_sample_ptr(a4),a0
suba.l a2,a2
.chordtoneloop
move.l d0,d4
sub.l a1,d4
bpl.s .noclip_osc_phase
moveq.l #0,d4
.noclip_osc_phase
asr.l #8,d4
asr.l #7,d4
move.b (a6,d4.w),d4 ; fetch precalced sample
ext.w d4
moveq.l #0,d3
move.b wi_osc_gain_b(a3),d3
muls d4,d3
asr.w #7,d3
move.b (a0),d4
ext.w d4
add.w d3,d4
CLIPTO8BIT d4
move.b d4,(a0)+
add.l d1,d0
cmp.l d7,d0
blt.s .lbC0025A2
sub.l d7,d0
add.l d5,a1
cmp.l a5,a1
blt.s .lbC00259A
neg.l d5
move.l a5,a1
.lbC00259A
cmp.l pv_wg_osc_speed_l(a4),a1
bgt.s .lbC0025A2
neg.l d5
move.l pv_wg_osc_speed_l(a4),a1
.lbC0025A2
tst.l d2
beq.s .chordtone_done
adda.l d2,a2
move.l a2,d1
asr.l #8,d1
asr.l #2,d1
add.l d6,d1
btst #4,wi_flags_b(a3) ; pitch linear flag
beq.s .no_linear_pitch
move.l d2,d4
asr.l #7,d4
sub.l d4,d2
.no_linear_pitch
cmp.l d7,d1
bcs.s .chordtone_done
moveq.l #0,d2
moveq.l #0,d1
.chordtone_done
cmp.l pv_wg_curr_samend_ptr(a4),a0
bne.s .chordtoneloop
.wave_gen_tone_done
addq.b #1,pv_wg_chord_note_num_b(a4)
cmp.b #4,pv_wg_chord_note_num_b(a4)
bne .wavegen_chordloop
moveq.l #3<<3,d0
and.b wi_mod_density_b(a3),d0 ; unisono
beq.s .chords_done
move.l a6,d1
beq.s .chords_done
tst.b pv_wg_unisono_run_b(a4)
bne.s .chords_done
move.w #$0001,pv_wg_chord_note_num_b(a4) ; sets also pv_wg_unisono_run_b
bra .wavegen_chordloop
.chords_done
; ----------------------------------------
; filters
; proposed register assignment:
; a0 = sample output
; a1 = end of filter chunk
; a2 = filter func
; d7/a6 = filter start
; a4 = MyPlayer
; a5 = unused
; a3 = waveinfo
; d3/d4/d5/d6 = filter taps
; d0/d1/d7 = scratch
moveq.l #0,d0
move.b wi_flt_type_b(a3),d0
beq .filter_done
IFNE PRETRACKER_PARANOIA_MODE
tst.w pv_wg_curr_sample_len_w(a4)
beq .filter_done
ENDC
add.w d0,d0
lea .filterfunc_jmptable(pc),a2
add.w -1*2(a2,d0.w),a2
moveq.l #0,d4 ; filter tap values
moveq.l #0,d5 ; filter tap values
movem.l d4-d5,pv_wg_flt_taps(a4)
lea wi_flt_start_b(a3),a0
moveq.l #0,d0
move.b (a0)+,d0 ; wi_flt_start_b
lsl.w #8,d0
move.b (a0)+,d4 ; wi_flt_min_b
lsl.w #8,d4 ; flt_min*256
move.b (a0)+,d5 ; wi_flt_max_b
lsl.w #8,d5 ; flt_max*256
move.b (a0)+,d3 ; wi_flt_speed_b
ext.w d3
ext.l d3 ; flt_speed*128
lsl.l #7,d3
movea.l pv_wg_curr_sample_ptr(a4),a0
.entry_to_filter_loop
move.l d0,a6
move.l d3,d1 ; flt_speed_b*128
adda.l d1,a6 ; suppress M68kUnexpectedConditionalInstruction
bgt.s .filter_speed_pos
.filter_speed_neg
move.l d4,d1 ; flt_min*256
cmp.l d1,d0
blt.s .lbC002790
cmp.l d1,a6
bgt.s .lbC002936
move.l d1,a6
cmp.l d5,d1 ; flt_max*256
beq.s .filter_load_min
neg.l d3 ; flt_speed_b*128
bra.s .filter_load_min
.filterfunc_jmptable
dc.w .lowpassfilter-.filterfunc_jmptable
dc.w .highpassfilter-.filterfunc_jmptable
dc.w .bandpassfilter-.filterfunc_jmptable
dc.w .notchfilter-.filterfunc_jmptable
.lbC002790
tst.l d0
blt.s .lbC002936
move.l a6,d7
bgt.s .lbC002936
neg.l d3 ; flt_speed_b*128
move.w #$FF,d2
move.w d2,d1
sub.l a6,a6
bra.s .filter_cont
.filter_speed_pos
cmp.l d5,d0 ; flt_max*256
bgt.s .lbC002D2A
cmp.l d5,a6 ; flt_max*256
blt.s .lbC002936
move.l d4,d2 ; flt_min*256
cmp.l d5,d2 ; flt_max*256
beq.s .filter_load_max_no_flip
neg.l d3 ; flt_speed_b*128
move.l d5,a6 ; flt_max*256
bra.s .filter_load_max
.lbC002D2A
cmpi.l #$FF00,d0
bgt.s .lbC002936
cmp.l #$FEFF,a6
ble.s .lbC002936
neg.l d3 ; flt_speed_b*128
moveq.l #0,d2
move.l #$FF00,a6
bra.s .filter_cont
.lbC002936
move.w a6,d2
lsr.w #8,d2
not.b d2
bra.s .filter_cont
.filter_load_max_no_flip
movea.l d2,a6
.filter_load_max
moveq.l #0,d2
move.b wi_flt_max_b(a3),d2
not.b d2
bra.s .filter_cont
.filter_load_min
moveq.l #0,d2
move.b wi_flt_min_b(a3),d2
not.b d2
.filter_cont
btst #0,wi_flt_type_b(a3)
bne.s .not_notch_or_highpass
.highpass_or_notch ; entered for 2 or 4
not.b d2
.not_notch_or_highpass ; entered for 1 or 3
move.w d2,d0
add.w d0,d0
moveq.l #0,d7
move.b wi_flt_resonance_b(a3),d7
beq.s .filter_no_resonance
move.w d2,d1
ext.l d1
lsl.l #8,d1
moveq.l #$B6/2,d0
sub.w d7,d0
add.w d0,d0
cmpi.w #$36,d0
bge.s .filter_no_clip_resonance
moveq.l #$36,d0
.filter_no_clip_resonance
divu d0,d1
move.w d2,d0
add.w d1,d0
.filter_no_resonance
lea $40(a0),a1 ; end of sample chunk
movem.l d3-d5,-(sp)
movem.w pv_wg_flt_taps(a4),d3-d6
; d0/d2 relevant for inner loop
.filter_innerloop
move.b (a0),d1
ext.w d1
move.w d4,d7
sub.w d5,d7
muls d0,d7
asr.l #8,d7
sub.w d4,d7
add.w d1,d7
muls d2,d7
asr.l #8,d7
add.w d7,d4
move.w d4,d7
sub.w d5,d7
muls d2,d7
asr.l #8,d7
add.w d7,d5
move.w d5,d7
sub.w d6,d7
muls d2,d7
asr.l #8,d7
add.w d7,d6
move.w d6,d7
sub.w d3,d7
muls d2,d7
asr.l #8,d7
add.w d7,d3
move.w d3,d7
jmp (a2)
.highpassfilter
sub.w d1,d7
bra.s .filterclipresult
.bandpassfilter
sub.w d4,d7
sub.w d5,d7
sub.w d6,d7
asr.w #1,d7
bra.s .filterclipresult
.notchfilter
sub.w d4,d7
neg.w d7
.lowpassfilter
.filterclipresult
CLIPTO8BIT d7
.filter_outputbyte
move.b d7,(a0)+
cmp.l a0,a1
bne.s .filter_innerloop
.filterloop_end_test
movem.w d3-d6,pv_wg_flt_taps(a4)
movem.l (sp)+,d3-d5
cmp.l pv_wg_curr_samend_ptr(a4),a0
bhs.s .filter_done
move.l a6,d0
bra .entry_to_filter_loop
.filter_done
; ----------------------------------------
; Optional Pre-Modulator
btst #5,wi_mod_density_b(a3) ; post bit
bne.s .nopremodulator
bsr pre_Modulator
.nopremodulator
; ----------------------------------------
; start with volume envelope
; a0 = output sample buffer
; d0 = scratch (e.g. sample)
; d1 = increment for attack phase
; d3 = current volume for attack and decay phases
; d4 = remaining sample length - 1
; a3 = wave info
.vol_do_envelope
move.l pv_wg_curr_sample_ptr(a4),a0 ; load buffer pointer
move.w pv_wg_curr_sample_len_w(a4),d4 ; load length
IFNE PRETRACKER_PARANOIA_MODE
beq .vol_envelope_finished ; paranoia
ENDC
subq.w #1,d4 ; we use length-1, <0 is end
moveq.l #2,d1 ; turns into $20000 through swap
moveq.l #0,d0
move.b wi_vol_attack_b(a3),d0
bne.s .has_attack_volume
cmp.b #$ff,wi_vol_sustain_b(a3)
beq .vol_envelope_finished
; no attack but not full sustain -> go to delay
;move.l #$100<<16,d3
bra.s .vol_skip_attack
.vol_avoid_overflow_with_1
moveq.l #1,d1
bra.s .cont_vol_envelope
.has_attack_volume
moveq.l #0,d3
cmp.w #1,d0
beq.s .cont_vol_envelope
cmp.w #2,d0
beq.s .vol_avoid_overflow_with_1
swap d1 ; turn into $20000
divu d0,d1
swap d1
clr.w d1
; swap is done below
.cont_vol_envelope
swap d1 ; move to high word (should be max $20000 then)
btst #5,wi_flags_b(a3) ; vol fast flag
beq.s .vol_no_fast
lsl.l #4,d1 ; multiply speed by 16
.vol_no_fast
add.l d1,d3 ; increase volume
cmp.l #$ffffff,d3
ble.s .vol_do_attack ; first step overshooting?
.vol_skip_attack
btst #3,wi_flags_b(a3) ; boost flag
bne.s .vol_delay_boosted
bra.s .vol_delay_normal
.vol_do_attack
btst #3,wi_flags_b(a3) ; boost flag
bne.s .vol_attack_boosted
; ----------------------------------------
; attack phase with volume boosted
.vol_attack_normal
.vol_attack_normal_loop
move.b (a0),d0
ext.w d0
swap d3
muls d3,d0
swap d3
asr.w #8,d0
move.b d0,(a0)+
subq.w #1,d4
bmi .vol_envelope_finished
add.l d1,d3 ; increase volume
cmp.l #$ffffff,d3
ble.s .vol_attack_normal_loop
; ----------------------------------------
; delay phase (normal)
.vol_delay_normal ; moved this label two inst up, didn't make sense there
moveq.l #0,d0
move.b wi_vol_delay_b(a3),d0
lsl.w #4,d0
IFNE PRETRACKER_FASTER_CODE
; skip the delay -- we don't change the volume for this section
addq.w #1,d0
sub.w d0,d4
bmi .vol_envelope_finished
lea 1(a0,d0.w),a0
ELSE
lea 2(a0,d0.w),a1
move.w #$ff,d3 ; FIXME I don't think that this is quite right. Shouldn't the max volume NOT change the value?
.vol_delay_normal_loop
move.b (a0),d0
IFNE 1
ext.w d0
muls d3,d0
asr.w #8,d0
ELSE
; this should be the same as above (*(256-1))
spl d3
add.b d3,d0
ENDC
move.b d0,(a0)+
cmp.l a1,a0
dbeq d4,.vol_delay_normal_loop
bne .vol_envelope_finished
ENDC
bra.s .vol_delay_end_reached
; ----------------------------------------
; attack with volume boosted
.vol_attack_boosted
.vol_attack_boosted_loop
move.b (a0),d0
ext.w d0
swap d3
muls d3,d0
swap d3
asr.w #6,d0
CLIPTO8BIT d0
move.b d0,(a0)+
subq.w #1,d4
bmi .vol_envelope_finished
add.l d1,d3
cmp.l #$ffffff,d3
ble.s .vol_attack_boosted_loop
; ----------------------------------------
; delay with max volume boosted
.vol_delay_boosted
moveq.l #0,d0
move.b wi_vol_delay_b(a3),d0
lsl.w #4,d0
lea 2(a0,d0.w),a1
IFNE PRETRACKER_FASTER_CODE
.vol_delay_boosted_loop
move.b (a0),d0
add.b d0,d0
CLIPTO8BITAFTERADD d0
add.b d0,d0
CLIPTO8BITAFTERADD d0
ELSE
move.w #$ff,d3 ; FIXME I don't think that this is quite right. It should be $100 to boost by full volume
.vol_delay_boosted_loop
move.b (a0),d0
ext.w d0
muls d3,d0
asr.w #6,d0
CLIPTO8BIT d0
ENDC
move.b d0,(a0)+
cmp.l a1,a0
dbeq d4,.vol_delay_boosted_loop
bne .vol_envelope_finished
.vol_delay_end_reached
subq.w #1,d4
; ----------------------------------------
; decay phase
; d0 = scratch
; d1 = current volume decrement
; d2 = table index boundary
; d3 = 16:16 decay pos
; d4 = sample length counter
; d5 = volume
; d6 = scratch
; d7 = decay increment
; a0 = sample pointer
; a1 = (current) roll off table pointer (points to upper bound)
; a2 = lower bound
.vol_do_decay
moveq.l #0,d3
move.b wi_vol_decay_b(a3),d3
beq .vol_do_sustain
move.w d3,d7
mulu d7,d7
lsr.w #2,d7
add.w d3,d7 ; d7 = (d3^2)/4+d3 (<= 16511)
btst #5,wi_flags_b(a3) ; vol fast flag
beq.s .vol_decay_not_fast
moveq.l #0,d3 ; will cause a5=$400,a2=$200,d2=0, decay value has no effect on the ramp used
.vol_decay_not_fast
lsl.w #8,d3
lsl.l #4,d3
move.l d3,d2
swap d2
lea pre_roll_off_table(pc),a1
add.w d2,d2
adda.w d2,a1
move.w (a1)+,a2 ; first index in table
lsr.w #1,d2 ; update next boundary
moveq.l #0,d1 ; current volume decrement
moveq.l #0,d5
not.w d5 ; set maximum volume
.vol_decay_normal_loop
add.l d7,d3 ; increment position in decay
swap d3
cmp.w #$8e,d3 ; pos in table where it makes no sense to do lerp anymore
bhi.s .vol_keep_voldec
cmp.w d2,d3
bls.s .vol_do_lerp
.vol_lerp_next_section
move.w (a1),a2
IFNE PRETRACKER_BUGFIX_CODE
lea pre_roll_off_table+2(pc),a1 ; Take the right boundary value
ELSE
lea pre_roll_off_table(pc),a1 ; This will set a wrong boundary and thus plateau the slope decay speed
ENDC
add.w d3,a1
add.w d3,a1
move.w d3,d2 ; update next boundary
.vol_do_lerp ; ((lowerbound-upperbound)*(d3<<8))>>8 + upperbound
move.w a2,d1
move.w (a1),d0
sub.w d1,d0 ; delta between lower and upper bound (negative value)
beq.s .vol_skip_lerp
swap d3
move.w d3,d1
lsr.w #8,d1
muls d0,d1
asr.l #8,d1
add.w a2,d1
swap d3
.vol_keep_voldec
.vol_skip_lerp
swap d3
sub.w d1,d5
bls.s .vol_do_sustain
move.w d5,d6
lsr.w #8,d6
cmp.b wi_vol_sustain_b(a3),d6
bls.s .vol_do_sustain
move.b (a0),d0
ext.w d0
muls d6,d0
btst #3,wi_flags_b(a3) ; boost flag
CLIPORTRUNC8BIT d0
move.b d0,(a0)+
dbra d4,.vol_decay_normal_loop
bra.s .vol_envelope_finished
; ----------------------------------------
; sustain phase
.vol_do_sustain
moveq.l #0,d3
move.b wi_vol_sustain_b(a3),d3
beq.s .vol_sustain_silence
btst #3,wi_flags_b(a3) ; boost flag
beq.s .vol_sustain_normal
.vol_sustain_boosted
.vol_sustain_boosted_loop
move.b (a0),d0
ext.w d0
muls d3,d0
asr.w #6,d0
CLIPTO8BIT d0
move.b d0,(a0)+
dbra d4,.vol_sustain_boosted_loop
bra.s .vol_envelope_finished
.vol_sustain_silence
moveq.l #0,d0
.vol_sustain_silence_loop
move.b d0,(a0)+
dbra d4,.vol_sustain_silence_loop
bra.s .vol_envelope_finished
.vol_sustain_normal
IFNE PRETRACKER_FASTER_CODE
cmp.b #$ff,d3
beq.s .vol_envelope_finished
ENDC
.vol_sustain_normal_loop
move.b (a0),d0
ext.w d0
muls d3,d0
asr.w #8,d0
move.b d0,(a0)+
dbra d4,.vol_sustain_normal_loop
.vol_envelope_finished
; ----------------------------------------
; Optional Post-Modulator
btst #5,wi_mod_density_b(a3) ; post bit
beq.s .nopostmodulator
bsr.s pre_Modulator
.nopostmodulator
; ----------------------------------------
; wave mixing (removed some code here that was doing nothing as result
; because below higher octaves code would overwrite it anyway).
IFND PRESTO_UNIFIED_STRUCT
movea.l pv_my_song(a4),a6
ENDC
moveq.l #0,d0
move.b wi_mix_wave_b(a3),d0
beq.s .mix_no_wave_mixing ; no mixing selected
subq.b #1,d0
IFNE PRETRACKER_PARANOIA_MODE ; same wave for mixing cannot be selected in Pretracker
cmp.b pv_wg_curr_wave_num_b(a4),d0
beq .mix_no_wave_mixing ; same wave number!
ENDC
lsl.w #2,d0
move.l pv_wave_sample_table(a4,d0.w),a1
IFND PRESTO_UNIFIED_STRUCT
add.w #sv_wavelength_table,d0
move.l (a6,d0.w),d3
ELSE
move.l pv_wavelength_table(a4,d0.w),d3
ENDC
move.w pv_wg_curr_sample_len_w(a4),d4 ; length of the sample to mix to
cmp.w d3,d4
ble.s .mix_picked_shorter
move.w d3,d4
.mix_picked_shorter
move.l pv_wg_curr_sample_ptr(a4),a0
subq.w #1,d4
.mix_mixloop
move.b (a0),d0
add.b (a1)+,d0
CLIPTO8BITAFTERADD d0
move.b d0,(a0)+
dbra d4,.mix_mixloop
.mix_no_wave_mixing
; ----------------------------------------
; create higher octaves (this has been massively shortened)
btst #2,wi_flags_b(a3)
beq.s .oct_has_no_extra_octaves
move.l pv_wg_curr_sample_len_l(a4),d4
IFNE PRETRACKER_PARANOIA_MODE
beq.s .oct_has_no_extra_octaves
ENDC
movea.l pv_wg_curr_sample_ptr(a4),a1
lea (a1,d4.l),a0 ; needs to be .l due to 32678 max length
mulu #7,d4
lsr.l #3,d4 ; * 0.875
subq.w #1,d4
.oct_downsample_loop
move.b (a1),(a0)+
addq.l #2,a1
dbra d4,.oct_downsample_loop
.oct_has_no_extra_octaves
; ----------------------------------------
IFNE PRETRACKER_PROGRESS_SUPPORT
move.l pv_precalc_progress_ptr(a4),d0
beq.s .no_progress_out
move.l d0,a0
move.l pv_precalc_sample_size(a4),d0
add.l d0,(a0)
.no_progress_out
ENDC
move.l (sp)+,a1
subq.w #1,pv_wg_wave_counter_w(a4)
bgt .wavegenloop
rts
;--------------------------------------------------------------------
; a3: waveinfo
;
; uses all data registers and a0-a1 (a2/a3 unchanged)
pre_Modulator:
tst.b wi_mod_wetness_b(a3)
beq.s .earlyexit
moveq.l #7,d0
and.b wi_mod_density_b(a3),d0
bne.s .has_density
.earlyexit
rts
.has_density
move.l pv_wg_curr_sample_ptr(a4),a0
move.w pv_wg_curr_sample_len_w(a4),d4
IFNE PRETRACKER_PARANOIA_MODE
bne.s .not_zero
rts
.not_zero
ENDC
moveq.l #0,d6
move.b wi_mod_wetness_b(a3),d6
moveq.l #0,d7
lea pre_modulator_ramp_8(pc),a1
.loop moveq.l #0,d5
move.b wi_mod_length_b(a3),d5
mulu (a1)+,d5 ; result is a long value
moveq.l #0,d1
move.b wi_mod_predelay_b(a3),d1
btst #5,wi_mod_density_b(a3) ; post-modulator?
bne.s .factor1_256
; factor 1/4 and 64
lsr.l #2,d5
lsl.l #6,d1
bra.s .cont
.factor1_256
lsl.w #8,d1
.cont add.l d1,d5 ; sum up length and predelay
moveq.l #0,d2
moveq.l #0,d3
.innerloop
moveq.l #0,d1
add.w d7,d3
addq.w #8,d3
smi d1
ext.w d1
eor.w d3,d1 ; flip order if it was negative
lsr.w #6,d1 ; 4 bit key is bits 14 to 11, needs to be 8 to 5
and.w #15<<5,d1
add.l d5,d1
lsr.l #6,d1
move.w d2,d0
sub.w d1,d0
bmi.s .is_outside_sample
move.b (a0,d0.w),d1
ext.w d1
btst #0,d7
beq.s .keep_dc
neg.w d1
.keep_dc
muls d6,d1
asr.w #8,d1
add.b (a0,d2.w),d1
CLIPTO8BITAFTERADD d1
move.b d1,(a0,d2.w)
.is_outside_sample
addq.w #1,d2
cmp.w d4,d2
bcs.s .innerloop
.restartloop
addq.w #1,d7
moveq.l #7,d0
and.b wi_mod_density_b(a3),d0
cmp.w d0,d7
bcs.s .loop
rts
;--------------------------------------------------------------------
pre_MemClr
lsr.w #1,d0
subq.w #1,d0
bmi.s .skipmemclr
moveq.l #0,d1
.fillmemloop
move.w d1,(a0)+
dbra d0,.fillmemloop
.skipmemclr
rts