
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
