diff --git a/README.md b/README.md index fc1000a..b326b75 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,12 @@ solve this problem. ## Changelog +### V2.x (unreleased) +- Split wave generation out of main file, reorganised content into header files. +- Optimized some more code paths for Raspberry Casket replayer. +- In the wave generator optimized away a table (32 words), replacement code is even smaller! +- Added Presto player draft. + ### V1.x (unreleased) - Fixed a bug regarding the copper output mode with looping waves having a loop-offset. - Fixed wrong register use on triggering waves regarding the loop offset. diff --git a/binaries/raspberry_casket.bin b/binaries/raspberry_casket.bin index 2f641c2..3b88e85 100644 Binary files a/binaries/raspberry_casket.bin and b/binaries/raspberry_casket.bin differ diff --git a/binaries/readme.txt b/binaries/readme.txt index 6ae6124..39bbd13 100644 --- a/binaries/readme.txt +++ b/binaries/readme.txt @@ -2,4 +2,4 @@ This file "raspberry_casket.bin" can replace the original "player.bin" provided that you used the 16 KB + 16 KB allocation for player variables as in the original player (you need only about 2 + 12 KB). -It has been assembled from src/drop_in_replacement.asm (version V1.1). \ No newline at end of file +It has been assembled from src/drop_in_replacement.asm (version V2.0). \ No newline at end of file diff --git a/src/drop_in_replacement.asm b/src/drop_in_replacement.asm index 92e5789..d849a2d 100644 --- a/src/drop_in_replacement.asm +++ b/src/drop_in_replacement.asm @@ -1,4 +1,4 @@ -; vasmm68k_mot.exe -devpac -Fbin -o ..\binaries\raspberry_casket.bin -opt-allbra drop_in_replacement.asm +; vasmm68k_mot.exe -I..\includes -devpac -Fbin -o ..\binaries\raspberry_casket.bin -opt-allbra drop_in_replacement.asm PRETRACKER_SUPPORT_V1_5 = 0 PRETRACKER_PARANOIA_MODE = 0 diff --git a/src/raspberry_casket.asm b/src/raspberry_casket.asm index 2e72a22..6c03816 100755 --- a/src/raspberry_casket.asm +++ b/src/raspberry_casket.asm @@ -1,5 +1,5 @@ ;-------------------------------------------------------------------- -; Raspberry Casket Player V1.1 (30-May-2023) +; Raspberry Casket Player V2.x (26-Jul-2023) ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; ; Provided by Chris 'platon42' Hodges @@ -80,14 +80,14 @@ ; Size ; ~~~~ ; The original C compiled code was... just bad. The new binary is -; about 1/3 of the original one. +; about 1/3rd of the original one. ; ; The code has been also optimized in a way that it compresses better. ; The original code compressed with Blueberry's Shrinkler goes from ; 18052 bytes down to 9023 bytes. ; ; Raspberry Casket, depending on the features compiled in, is about -; 6216 bytes and goes down to ~4348 bytes (in isolation). +; 5992 bytes and goes down to ~4238 bytes (in isolation). ; ; So this means that the optimization is not just "on the outside". ; @@ -254,398 +254,22 @@ PRETRACKER_DONT_TRASH_REGS = 1 PRETRACKER_COPPER_OUTPUT = 0 ; 0 = standard CPU wait, 1 = Copperlist ENDC -; Pretracker song format description: -; -; $0000 4: PRT ($19 (V0.x), $1b (V1.0), $1e (V1.5)) -; $0004 4: File offset to position data (POSD) -; $0008 4: File offset to pattern data (PATT) -; $000C 4: File offset to instruments (INST) -; $0010 4: File offset to waves (WAVE) -; $0014 20: Songname -; $0028 20: Author -; $003C 1: Restart position for song (<=V1.0) -; $003D 1: Number of patterns (<=V1.0) -; $003E 1: Songlength in patterns (<=V1.0) -; $003F 1: Number of steps per pattern (<=V1.0) -; $0040 1: Number of instruments (<=V1.0), $40 for V1.5 -; $0041 1: Number of waves -; $0042 24: Wave generation ordering (>=V1.0) -; $005a 1: Number of subsongs (>=V1.5) -; [...] -; Position data (POSD): -; - Per subsong (>=V1.5) -; - 1: Restart pos -; - 1: #patterns -; - 1: #numsteps -; - 1: songlength -; - 4: relative pattern offset in pattern data -; - Positions x 4 x [Pattern number (byte), pitch shift (signed byte)] -; -; Pattern data (PATT): -; Each pattern line consists of three bytes: -; - 1 Bit : Bit 4 of Inst Number -; - 1 Bit : ARP instead of effect -; - 6 Bits: Pitch ($01 is C-0, $3d is NOTE OFF) -; -; - 4 Bits: Bit 0-3 of Inst Number -; - 4 Bits: Effect command -; - 8 Bits: Effect data -; - Patterns x steps x 3 bytes -; -; Unknown data after pattern data: (12 10 00 00 00 00) -; -; Instrument definitions (INST): -; - 32 (!) x Null terminated string (or 23 chars max) (for V1.5 this is 64 strings) -; - For each instrument: Instrument Info (ININ) -; - $00 1: Vibrato Delay -; - $01 1: Vibrato Depth -; - $02 1: Vibrato Speed (-1) -; - $03 1: ADSR Attack -; - $04 1: ADSR Decay -; - $05 1: ADSR Sustain -; - $06 1: ADSR Release -; - $07 1: Number of Inst Pattern steps -; -; - For each instrument: -; - 1 Byte: number of steps -; - 3 Bytes x number of steps: Inst Pattern (IPTT) -; -; Inst pattern data (IPTT): -; Each pattern line consists of three bytes: -; - 1 Bit : Next note stitched to this one -; - 1 Bit : Fixed Pitch Note -; - 6 Bits : Pitch ($01 is C-0) -; - 4 Bits : unused? -; - 12 Bits: Effect -; - Patterns x steps x 3 bytes -; -; Wave definitions (WAVE): -; - 24 (!) x Null terminated string (or 23 chars max) -; - Optional padding to even address, if necessary -; - For each wave: -; - 42 Bytes: Wave info structure (see definition below) - -; ---------------------------------------- -; Some constants for clarity - -MAX_VOLUME = $40 -MAX_SPEED = $2f -MAX_WAVES = 24 -MAX_INSTRUMENTS = 32 -MAX_TRACK_DELAY = 32 -NOTE_OFF_PITCH = $3d -NOTES_IN_OCTAVE = 12 -NUM_CHANNELS = 4 ; yes, you can reduce the number of channels if you want - -; ---------------------------------------- -; Pretracker file structures - -; Pattern data (PATT and IPTT) -pdb_pitch_ctrl = 0 -pdb_inst_effect = 1 ; for normal pattern data -pdb_effect_cmd = 1 ; for inst pattern -pdb_effect_data = 2 - -; Pattern pos data (POSD) -ppd_pat_num = 0 -ppd_pat_shift = 1 - -; Instrument Info (ININ) -ii_vibrato_delay = 0 -ii_vibrato_depth = 1 -ii_vibrato_speed = 2 -ii_adsr_attack = 3 -ii_adsr_decay = 4 -ii_adsr_sustain = 5 -ii_adsr_release = 6 -ii_pattern_steps = 7 -ii_SIZEOF = 8 - -; Wave Info (WAVE) -wi_loop_start_w = $00 -wi_loop_end_w = $02 -wi_subloop_len_w = $04 -wi_allow_9xx_b = $06 -wi_subloop_wait_b = $07 -wi_subloop_step_w = $08 -wi_chipram_w = $0a -wi_loop_offset_w = $0c -wi_chord_note1_b = $0e -wi_chord_note2_b = $0f -wi_chord_note3_b = $10 -wi_chord_shift_b = $11 -wi_osc_unknown_b = $12 ; always $00? (unused in code?) -wi_osc_phase_spd_b = $13 -wi_flags_b = $14 ; bit 0/1: osc type, bit 2: needs extra octaves, bit 3: boost, bit 4: pitch linear, bit 5: vol fast -wi_osc_phase_min_b = $15 -wi_osc_phase_max_b = $16 -wi_osc_basenote_b = $17 -wi_osc_gain_b = $18 -wi_sam_len_b = $19 ; in multiples of 128, zero-based (0 == 128) -wi_mix_wave_b = $1a -wi_vol_attack_b = $1b -wi_vol_delay_b = $1c -wi_vol_decay_b = $1d -wi_vol_sustain_b = $1e -wi_flt_type_b = $1f ; 1=lowpass, 2=highpass, 3=bandpass, 4=notch -wi_flt_resonance_b = $20 -wi_pitch_ramp_b = $21 -wi_flt_start_b = $22 -wi_flt_min_b = $23 -wi_flt_max_b = $24 -wi_flt_speed_b = $25 -wi_mod_params_l = $26 -wi_mod_wetness_b = $26 -wi_mod_length_b = $27 -wi_mod_predelay_b = $28 -wi_mod_density_b = $29 ; (1-7), unisono (bits 3/4) and post bit 5 -wi_SIZEOF = $2a - -; ---------------------------------------- -; Unpacked Instrument Info (addition to player for faster processing) - rsreset -uii_vibrato_delay rs.w 1 -uii_vibrato_depth rs.w 1 -uii_vibrato_speed rs.w 1 -uii_adsr_release rs.b 1 - rs.b 1 ; dummy -uii_adsr_attack rs.w 1 -uii_adsr_decay rs.w 1 -uii_adsr_sustain rs.w 1 -uii_pattern_steps rs.b 1 - rs.b 1 ; padding -uii_SIZEOF rs.b 0 - -; ---------------------------------------- -; MySong offsets - rsreset -sv_waveinfo_table rs.l MAX_WAVES ; 24 pointers to wave infos to avoid mulu -sv_inst_patterns_table rs.l MAX_INSTRUMENTS ; 32 pointers to pattern data - ; --- 127 byte displacement limit --- -sv_wavelength_table rs.l MAX_WAVES ; 24 longwords to sample lengths (standard octave) (NEW) -sv_wavetotal_table rs.l MAX_WAVES ; 24 longwords to sample lengths for all octaves (NEW) -sv_wavegen_order_table rs.b MAX_WAVES ; 24 bytes -sv_num_waves_b rs.b 1 -sv_num_steps_b rs.b 1 -sv_patterns_ptr rs.l 1 -sv_curr_pat_pos_w rs.w 1 ; only byte used FIXME why is this part of MySong? Should be in Player -sv_pat_pos_len_w rs.w 1 ; only byte used -sv_pat_restart_pos_w rs.w 1 ; only byte used -sv_pos_data_adr rs.l 1 -sv_waveinfo_ptr rs.l 1 ; base pointer of wave info -sv_pattern_table rs.l 256 -sv_inst_infos_table rs.b MAX_INSTRUMENTS*uii_SIZEOF -sv_SIZEOF rs.b 0 - -; ---------------------------------------- -; channel output data (part of pcd structure below) - rsreset -ocd_sam_ptr rs.l 1 ; 0 -ocd_length rs.w 1 ; 4 -ocd_loop_offset rs.w 1 ; 6 -ocd_period rs.w 1 ; 8 -ocd_volume rs.b 1 ; 10 -ocd_trigger rs.b 1 ; 11 needs to be after volume -ocd_unused rs.l 1 ; 12 unused, but makes the structure an even 16 bytes -ocd_SIZEOF rs.b 0 - -; channel structure (part of pv structure) - rsreset -; DO NOT CHANGE ORDER -- OPTIMIZED CLEARING -pcd_pat_portamento_dest_w rs.w 1 ; portamento destination pitch -pcd_pat_pitch_slide_w rs.w 1 - -pcd_pat_vol_ramp_speed_b rs.b 1 -pcd_pat_2nd_inst_num4_b rs.b 1 -pcd_pat_2nd_inst_delay_b rs.b 1 -pcd_wave_offset_b rs.b 1 - -pcd_inst_pitch_slide_w rs.w 1 -pcd_inst_sel_arp_note_w rs.w 1 - -pcd_inst_note_pitch_w rs.w 1 -pcd_inst_curr_port_pitch_w rs.w 1 - -pcd_inst_line_ticks_b rs.b 1 -pcd_inst_pitch_pinned_b rs.b 1 -pcd_inst_vol_slide_b rs.b 1 -pcd_inst_step_pos_b rs.b 1 - -pcd_inst_wave_num_w rs.w 1 ; current wave number (1 based) (lower byte used) - -pcd_track_delay_offset_b rs.b 1 ; $ff = no track delay -pcd_inst_speed_stop_b rs.b 1 ; speed byte, $ff stops processing -pcd_inst_pitch_w rs.w 1 - -pcd_inst_vol_w rs.w 1 -pcd_loaded_inst_vol_b rs.b 1 -pcd_pat_vol_b rs.b 1 ; Multiplied with volume of instrument. -; DO NOT CHANGE ORDER -- OPTIMIZED CLEARING END - -pcd_arp_notes_l rs.b 0 -pcd_arp_note_1_b rs.b 1 -pcd_arp_note_2_b rs.b 1 -pcd_arp_note_3_b rs.b 1 - rs.b 1 ; gets cleared - -pcd_last_trigger_pos_w rs.w 1 ; I think this makes sure that we don't retrigger the note on same pos - -pcd_pat_portamento_speed_b rs.b 1 -pcd_pat_adsr_rel_delay_b rs.b 1 ; counts down until adsr release. Seems unused? -pcd_note_off_delay_b rs.b 1 ; time before note is released ($ff = disabled) -pcd_inst_pattern_steps_b rs.b 1 ; number of steps in instrument pattern - -pcd_note_delay_b rs.b 1 ; $ff = no note delay -pcd_track_delay_steps_b rs.b 1 ; $00 = no track delay, $ff = stop track delay (this is for the next channel!) -pcd_track_delay_vol16_b rs.b 1 -pcd_track_init_delay_b rs.b 1 ; number of frames to ignore the delay - -pcd_inst_num4_w rs.w 1 ; current instrument number * 4 -;pcd_inst_new_step_w rs.w 1 ; seems to be unused -pcd_inst_subloop_wait_w rs.w 1 -pcd_inst_loop_offset_w rs.w 1 -pcd_inst_info_ptr rs.l 1 ; pointer to currently active instrument - -pcd_waveinfo_ptr rs.l 1 ; pointer to currently active waveinfo -pcd_channel_mask_b rs.b 1 -pcd_channel_num_b rs.b 1 -pcd_adsr_phase_w rs.w 1 ; 0=attack, 1=decay, 2=sustain, 3=release ! do not change order -pcd_adsr_volume_w rs.w 1 ; 0 for restart / $400 (word only) ! do not change order -pcd_adsr_phase_speed_b rs.b 1 -pcd_inst_ping_pong_dir_b rs.b 1 ; direction of ping-pong (-1 == $00 / +1 = $ff) -pcd_adsr_pos_w rs.w 1 ; pos in adsr curve -pcd_adsr_vol64_w rs.w 1 ; some adsr volume - -pcd_new_inst_num_b rs.b 1 ; load new instrument (number) ! do not change order - rs.b 1 ; gets cleared -pcd_vibrato_pos_w rs.w 1 ; -pcd_vibrato_delay_w rs.w 1 ; is a byte value ! do not change order -pcd_vibrato_depth_w rs.w 1 ; is a byte value ! do not change order -pcd_vibrato_speed_w rs.w 1 ; is a byte value ! do not change order -pcd_adsr_release_b rs.b 1 ; is a byte value ! do not change order - rs.b 1 ; padding will be overwritten! - -pcd_out_base rs.b ocd_SIZEOF -pcd_track_delay_buffer rs.b MAX_TRACK_DELAY*ocd_SIZEOF -pcd_SIZEOF rs.b 0 - -pcd_out_ptr_l = pcd_out_base+ocd_sam_ptr -pcd_out_len_w = pcd_out_base+ocd_length -pcd_out_lof_w = pcd_out_base+ocd_loop_offset -pcd_out_per_w = pcd_out_base+ocd_period -pcd_out_vol_b = pcd_out_base+ocd_volume -pcd_out_trg_b = pcd_out_base+ocd_trigger -pcd_out_unused_l = pcd_out_base+ocd_unused ; copied for track delay, but not used? - - rsreset -owb_saw_waves rs.b 128 -owb_sqr_waves rs.b 128 -owb_tri_waves rs.b 128 -owb_wave_length rs.b 1 -owb_SIZEOF rs.b 0 - -; ---------------------------------------- -; MyPlayer global variables (not bound to channel) - rsreset -; DO NOT CHANGE ORDER -- OPTIMIZED INIT -pv_pat_curr_row_b rs.b 1 ; current step -pv_next_pat_row_b rs.b 1 -pv_next_pat_pos_b rs.b 1 -pv_pat_speed_even_b rs.b 1 ; even shuffle speed - -pv_pat_speed_odd_b rs.b 1 ; odd shuffle speed -pv_pat_line_ticks_b rs.b 1 -pv_pat_stopped_b rs.b 1 ; 0 = stop, $ff = run -pv_songend_detected_b rs.b 1 -; DO NOT CHANGE ORDER -- OPTIMIZED INIT END - -pv_loop_pattern_b rs.b 1 ; repeat current pattern, do not advance - rs.b 1 ; padding - -pv_trigger_mask_w rs.w 1 - -pv_my_song rs.l 1 -pv_sample_buffer_ptr rs.l 1 ; pointer to start of sample buffer -pv_copperlist_ptr rs.l 1 -pv_wave_sample_table rs.l MAX_WAVES ; 24 pointers to sample starts -pv_period_table rs.w 16*NOTES_IN_OCTAVE*3 - ; --- 127 byte displacement limit --- -pv_channeldata rs.b NUM_CHANNELS*pcd_SIZEOF - - IFNE PRETRACKER_VOLUME_TABLE -pv_osc_buffers rs.b 0 ; reuse space of volume_table, which is bigger than NOTES_IN_OCTAVE*owb_SIZEOF -pv_volume_table rs.b (MAX_VOLUME+1)*MAX_VOLUME*2 - ELSE -pv_osc_buffers rs.b NOTES_IN_OCTAVE*owb_SIZEOF - ENDC - -pv_precalc_sample_size rs.l 1 -pv_precalc_progress_ptr rs.l 1 -pv_wg_wave_ord_num_w rs.w 1 - IFNE PRETRACKER_PARANOIA_MODE ; same wave for mixing cannot be selected in Pretracker -pv_wg_curr_wave_num_b rs.b 1 - rs.b 1 - ENDC -pv_wg_curr_sample_ptr rs.l 1 -pv_wg_curr_samend_ptr rs.l 1 -pv_wg_curr_sample_len_w rs.w 1 -pv_wg_chord_note_num_b rs.b 1 ; don't change order -pv_wg_unisono_run_b rs.b 1 ; don't change order -pv_wg_chord_flag_w rs.w 1 -pv_wg_chord_pitches rs.l 1 -pv_wg_osc_speed_l rs.l 1 -pv_wg_flt_taps rs.w 4 -pv_SIZEOF rs.b 0 - ;-------------------------------------------------------------------- - include "../includes/hardware/custom.i" - include "../includes/hardware/dmabits.i" - -CLIPTO8BIT MACRO - cmpi.w #-$80,\1 - bge.s .nominclip\@ - moveq.l #-$80,\1 -.nominclip\@ - cmpi.w #$7F,\1 - ble.s .nomaxclip\@ - moveq.l #$7F,\1 -.nomaxclip\@ - ENDM - -CLIPORTRUNC8BIT MACRO - beq.s .unboosted\@ - asr.l #6,\1 - cmpi.w #-$80,\1 - bge.s .nominclip\@ - moveq.l #-$80,\1 -.nominclip\@ - cmpi.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 + include "raspberry_casket.i" + include "hardware/custom.i" + include "hardware/dmabits.i" ;-------------------------------------------------------------------- ; Code starts here IFNE PRETRACKER_KEEP_JUMP_TABLE -pre_FuncTable - dc.l pre_SongInit-pre_FuncTable - dc.l pre_PlayerInit-pre_FuncTable - dc.l pre_PlayerTick-pre_FuncTable +pre_FuncTable: + dc.l pre_SongInit-pre_FuncTable + dc.l pre_PlayerInit-pre_FuncTable + dc.l pre_PlayerTick-pre_FuncTable ENDC - ;dc.b '$VER: Raspberry Casket 1.1',0 + ;dc.b '$VER: Raspberry Casket 1.1',0 ;even IFNE PRETRACKER_COPPER_OUTPUT @@ -727,8 +351,8 @@ pre_SongInit: moveq.l #0,d0 move.l $0000(a2),d1 move.b d1,d2 - clr.b d1 - cmpi.l #$50525400,d1 ; "PRE"-Text + move.b d0,d1 + cmp.l #$50525400,d1 ; "PRE"-Text bne .error moveq.l #MAX_INSTRUMENTS-1,d7 ; notice there's one extra name (available in 1.5, but not usable)! IFNE PRETRACKER_SUPPORT_V1_5 @@ -742,7 +366,7 @@ pre_SongInit: moveq.l #2*MAX_INSTRUMENTS-1,d7 ; v1.5 has 32 slots (the other ones used for sfx) .nopatchv15 ELSE - cmpi.b #$1b,d2 + cmp.b #$1b,d2 bgt .error ENDC @@ -933,6 +557,8 @@ pre_PlayerInit: move.w #pv_SIZEOF,d0 bsr pre_MemClr ; keeps a1 unchanged! + move.l a6,pv_my_song(a4) + ; ---------------------------------------- ; proposed register assignment: ; a0 = sample output / scratch @@ -941,7 +567,6 @@ pre_PlayerInit: ; a4 = MyPlayer ; a6 = MySong - move.l a2,pv_my_song(a4) IFNE PRETRACKER_PROGRESS_SUPPORT move.l a3,pv_precalc_progress_ptr(a4) ENDC @@ -951,9 +576,10 @@ pre_PlayerInit: beq.s .hasnosamplebuffer ; PARANOIA ENDC - clr.w (a1)+ ; empty sample moveq.l #0,d7 + move.w d7,(a1)+ ; empty sample move.b sv_num_waves_b(a6),d7 + move.w d7,pv_wg_wave_counter_w(a4) IFNE PRETRACKER_PARANOIA_MODE beq.s .hasnosamplebuffer ; PARANOIA ENDC @@ -1022,7 +648,9 @@ pre_PlayerInit: .chaninitloop2 move.b #MAX_VOLUME,pcd_pat_vol_b(a0) st pcd_track_delay_offset_b(a0) - move.l a1,pcd_waveinfo_ptr(a0) + IFEQ PRETRACKER_BUGFIX_CODE + move.l a1,pcd_waveinfo_ptr(a0) ; we should actually have no wave selected + ENDC move.w #3,pcd_adsr_phase_w(a0) move.l pv_sample_buffer_ptr(a4),pcd_out_ptr_l(a0) @@ -1034,1137 +662,20 @@ pre_PlayerInit: lea pcd_SIZEOF(a0),a0 dbra d7,.chaninitloop2 -; ---------------------------------------- - - 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),a1 - moveq.l #NOTES_IN_OCTAVE-1,d7 -.noteloop - moveq.l #0,d6 - move.l d6,a3 ; tabpos - move.b (a0)+,d6 ; period - move.b d6,owb_wave_length-owb_sqr_waves(a1) - - 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 (a1,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(a1,a3.w) - - add.b d2,d2 - cmp.w a3,d3 ; tabpos == negquarter - bne.s .nowrapback - suba.w d6,a2 ; go back to start of period -.nowrapback - cmp.w d0,a3 - 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 a3,d4 - bne.s .noclip80 -.clip80 moveq.l #-$80,d2 -.noclip80 - move.b d2,owb_sqr_waves-owb_sqr_waves(a1,a3.w) - - add.w d5,d0 ; increment acc by frac - addq.w #1,a3 ; increment pos - - cmp.w a3,d6 - bne.s .notewaveloop - - lea owb_SIZEOF(a1),a1 - dbra d7,.noteloop - ; ---------------------------------------- .audioinit + IFND PRESTO_SKIP_OUTPUT bset #1,$BFE001 ; filter off + ENDC IFNE PRETRACKER_PARANOIA_MODE tst.b sv_num_waves_b(a6) beq .earlyexit ; PARANOIA ENDC -; ---------------------------------------- -; proposed register assignment: -; a0 = sample output -; a1 = scratch -; a3 = songinfo -; a4 = MyPlayer -; a6 = MySong / waveinfo - -.wavegenloop - ;movea.l pv_my_song(a4),a6 lea sv_wavegen_order_table(a6),a1 - move.w pv_wg_wave_ord_num_w(a4),d0 ; counter through all 24 waves - moveq.l #0,d1 - move.b (a1,d0.w),d1 ; apply wave order redirection - 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) - - add.w #sv_wavelength_table,d1 - adda.w d1,a6 - move.l sv_wavelength_table-sv_wavelength_table(a6),d0 - move.w d0,pv_wg_curr_sample_len_w(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 - - ; 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)+ - - suba.l a5,a5 - 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,d1 - moveq.l #NOTES_IN_OCTAVE,d2 - move.w d0,d1 - move.w d0,a2 ; save base note, used later (much later, noise generator)! - add.w #NOTES_IN_OCTAVE*NOTES_IN_OCTAVE,d1 ; make sure we don't run into negative modulo - divu d2,d1 - swap d1 - move.w d1,d0 ; note within octave - swap d1 - sub.w d2,d1 ; restore octave - - mulu #owb_SIZEOF,d0 - lea (a4,d0.w),a1 - - lea pv_osc_buffers+owb_saw_waves(a1),a6 - moveq.l #3,d0 - and.b wi_flags_b(a3),d0 - beq.s .osc_selected - lea owb_tri_waves-owb_saw_waves(a6),a6 - subq.b #1,d0 - beq.s .osc_selected - lea owb_sqr_waves-owb_tri_waves(a6),a6 - subq.b #1,d0 - beq.s .osc_selected - suba.l a6,a6 ; noise selected -.osc_selected - - move.l #$8000,d6 - move.w d1,d0 ; check octave shift - bgt.s .shiftleft - beq.s .contshift -;.shiftright - move.w d0,d3 - neg.w d3 - asr.l d3,d6 - bra.s .contshift -.shiftleft - lsl.l d0,d6 -.contshift - -; ---------------------------------------- -; pitch ramp - move.b wi_pitch_ramp_b(a3),d3 - ext.w d3 - ext.l d3 - btst #4,wi_flags_b(a3) ; pitch linear flag - beq.s .pitch_not_linear - tst.b d3 - bgt.s .pitch_ramp_positive - - lsl.l d0,d3 - add.l d3,d3 - bra.s .pitch_ramp_cont - -.pitch_not_linear - tst.b d3 - ble.s .pitch_ramp_cont -.pitch_ramp_positive - muls d3,d3 -.pitch_ramp_cont - move.l d3,d2 - lsl.l #8,d2 - lsl.l #2,d2 - - moveq.l #0,d7 - move.b pv_osc_buffers+owb_wave_length(a1),d7 ; get period - moveq.l #15,d5 - lsl.l d5,d7 - - sub.w d0,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) - - ; 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 - - cmp.l d7,d0 - ble.s .lbC002516 -.lbC002510 - sub.l d7,d0 - cmp.l d7,d0 - bgt.s .lbC002510 -.lbC002516 - move.l a6,d4 - bne .no_noise - -; ---------------------------------------- -; d1 = octave -; d5 = osc phase speed -; a2 = base note -.gen_noise - IFNE PRETRACKER_PARANOIA_MODE - tst.w pv_wg_curr_sample_len_w(a4) - beq .wave_gen_tone_done - ENDC - - move.l #$8000,d5 - 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 - - 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 - - cmpa.l #$8000,a5 ; if symmetrical - beq.s .gen_noise_centered - ; FIXME what does this do? d4 = (a5 - $8000) d1 = (a5 + $7fff)&$ffff8000 -> d4 - d1 == ((a5 - $8000) - ((a5 + $7fff)&$ffff8000) - move.l a5,d4 - addi.l #$FFFF8000,d4 - move.l a5,d1 - addi.l #$FFFF7FFF,d1 - andi.w #$8000,d1 - movea.l d4,a5 - suba.l d1,a5 -.gen_noise_centered - - move.b d0,d1 - ext.w d1 - move.w d3,d4 - muls d1,d4 - move.l d4,d1 - asr.l #7,d1 - CLIPTO8BIT d1 - add.b (a0),d1 - -.gen_noise_innerloop - move.b d1,(a0)+ - adda.l a1,a5 - tst.l d2 - beq.s .lbC002BAC - 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 - asr.l #7,d4 - sub.l d4,d2 -.noise_nonlinear_pitch - - cmpa.w #$1FF,a1 - bgt.s .lbC002BAC - moveq.l #0,d2 - move.l d2,a5 - ;suba.l a5,a5 - movea.w #$200,a1 -.lbC002BAC - cmpa.l pv_wg_curr_samend_ptr(a4),a0 - beq .wave_gen_tone_done - cmpa.w #$7FFF,a5 - ble.s .gen_noise_innerloop - bra .gen_noise_outerloop - -.no_noise - 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.b #3,d1 - moveq.l #9,d4 - sub.b 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 - cmpa.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)+ - cmpa.l a0,a1 - bne.s .filter_innerloop - -.filterloop_end_test - movem.w d3-d6,pv_wg_flt_taps(a4) - movem.l (sp)+,d3-d5 - - cmpa.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 - movea.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 - cmpi.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 - cmpi.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 - cmpi.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)+ - - cmpa.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 - cmpi.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)+ - - cmpa.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 pre_Modulator -.nopostmodulator - -; ---------------------------------------- -; wave mixing (removed some code here that was doing nothing as result -; because below higher octaves code would overwrite it anyway). - movea.l pv_my_song(a4),a6 - - 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 - add.w #sv_wavelength_table,d0 - move.l (a6,d0.w),d3 - - 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 - - moveq.l #0,d4 - move.b wi_sam_len_b(a3),d4 ; length of the sample - IFNE PRETRACKER_PARANOIA_MODE - beq.s .oct_has_no_extra_octaves - ENDC - addq.w #1,d4 - lsl.w #7,d4 - - 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.b sv_num_waves_b(a6),d0 - addq.b #1,pv_wg_wave_ord_num_w+1(a4) - cmp.b pv_wg_wave_ord_num_w+1(a4),d0 - bgt .wavegenloop + bsr.s pre_WaveGen ; ---------------------------------------- IFNE PRETRACKER_VOLUME_TABLE @@ -2191,109 +702,7 @@ pre_PlayerInit: ENDC rts -;-------------------------------------------------------------------- -; a3: waveinfo -; -; d6: wetness (word) -; uses all data registers and a0-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 - lea pre_ramp_up_down_32(pc),a2 -.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 - add.w d7,d3 - addq.w #8,d3 - moveq.l #0,d1 - move.w d3,d1 - lsr.w #8,d1 - lsr.w #3,d1 - add.w d1,d1 - move.w (a2,d1.w),d1 ; 4 bit value - add.l d5,d1 - lsr.l #6,d1 - - move.w d2,d0 - sub.w d1,d0 - bmi.s .isneg - - 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) -.isneg - 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 + include "raspberry_casket_wavegen.asm" ;******************************************************************** ;-------------------------------------------------------------------- @@ -2392,7 +801,7 @@ pre_PlayerTick: move.l d1,(a1)+ ; pcd_inst_line_ticks_b, pcd_inst_pitch_pinned_b, pcd_inst_vol_slide_b, pcd_inst_step_pos_b subq.b #1,d1 - move.w d1,(a1)+ ; pcd_inst_wave_num_w + move.w d1,(a1)+ ; pcd_inst_wave_num4_w move.l #$ff010010,(a1)+ ; pcd_track_delay_offset_b, pcd_inst_speed_stop_b, pcd_inst_pitch_w move.l #(MAX_VOLUME<<16)|(MAX_VOLUME<<8)|MAX_VOLUME,(a1)+ ; pcd_inst_vol_w / pcd_loaded_inst_vol_b / pcd_pat_vol_b @@ -2467,7 +876,7 @@ pre_PlayerTick: .no_note_delay moveq.l #0,d5 move.b pcd_channel_num_b(a5),d5 - move.w sv_curr_pat_pos_w(a6),d2 + move.w pv_curr_pat_pos_w(a4),d2 add.w d2,d2 add.w d2,d2 ; *4 add.w d5,d2 @@ -2500,15 +909,15 @@ pre_PlayerTick: add.w d2,d2 add.w d2,a0 ; pattern data - moveq.l #15,d2 move.b pdb_inst_effect(a0),d4 ; instrument and command byte + moveq.l #15,d2 and.w d4,d2 lsr.w #4,d4 ; instrument nr bits 0-4 moveq.l #0,d5 move.b pdb_effect_data(a0),d5 - cmpi.b #$e,d2 + cmp.b #$e,d2 bne.s .pat_exy_cmd_cont ; handle $exy commands tst.b pcd_note_delay_b(a5) @@ -2544,6 +953,8 @@ pre_PlayerTick: ; read out pattern editor data moveq.l #0,d6 ; clear arp flag + move.b d6,pcd_pat_vol_ramp_speed_b(a5) + move.w d6,pcd_pat_pitch_slide_w(a5) move.b pdb_pitch_ctrl(a0),d3 ; pitch and control byte bpl.s .noselinst16plus add.w #16,d4 ; add high bit of instrument number @@ -2570,49 +981,39 @@ pre_PlayerTick: ; d2 = effect cmd, d3 = pitch_ctrl, d4 = inst number, d5 = effect data, d7 = pitch - andi.b #$40,d3 ; ARP bit - bne.s .has_arp_note -.no_arp_note + and.w #$40,d3 ; ARP bit + bne.s .is_an_arp_note ; d3 is zero in this case, no no 2nd inst number + + ; d3.l must be 0 in this case + ; normal note, not an ARP node tst.b d2 bne.s .arp_processing_done + + ; d2.l is guaranteed to be zero + ; 0xx: play second instrument tst.b d5 beq.s .no_effect - moveq.l #15,d1 ; FIXME seems like it only supports the lower 15 instruments - and.b d5,d1 - add.w d1,d1 - add.w d1,d1 + + move.w d4,d3 ; 1st instrument num + + moveq.l #15,d4 ; FIXME seems like it only supports the lower 15 instruments + and.w d5,d4 + add.w d4,d4 + add.w d4,d4 ; 2nd instrument from pattern effect tst.b d7 - bne.s .play_2nd_inst_without_trigger + bne.s .arp_processing_done -.play_2nd_inst_with_no_pitch + ; play 2nd inst without (new) pitch addq.w #1,d0 ; pattern pitch shift lsl.w #4,d0 + bra.s .check_for_2nd_instrument - tst.b d1 - beq.s .clear_note_arp - - moveq.l #0,d2 - move.w d4,d3 - move.w d1,d4 - bra.s .trigger_new_instrument - -.play_2nd_inst_without_trigger - move.w d4,d3 ; 1st instrument num - move.w d1,d4 ; 2nd instrument num - bra.s .arp_processing_done - -.clear_note_arp - clr.l pcd_arp_notes_l(a5) - move.b d7,d2 - move.b d4,d3 - bra .clear_portamento - -.has_arp_note +.is_an_arp_note move.b d2,d3 or.b d5,d3 - beq.s .all_arp_notes_zero ; if we go there, d3 MUST be 0 already + beq.s .all_arp_notes_zero ; if we branch there, both d2 and d3 MUST be 0 already move.b d2,pcd_arp_note_1_b(a5) @@ -2624,40 +1025,32 @@ pre_PlayerTick: and.b d5,d2 move.b d2,pcd_arp_note_3_b(a5) -.all_arp_notes_zero - moveq.l #1,d6 -.no_effect moveq.l #0,d2 ; make sure we don't get a random command here + +.all_arp_notes_zero + moveq.l #1,d6 ; set ARP flag +.no_effect moveq.l #0,d3 ; ---------------------------------------- ; d2 = effect cmd, d3 = alt inst number (or 0), d4 = inst number, d5 = effect cmd, d6 = ARP flag, d7 = pitch .arp_processing_done - cmpi.b #NOTE_OFF_PITCH,d7 - bne.s .has_no_note_off + cmp.b #NOTE_OFF_PITCH,d7 + beq.s .release_note -.release_note - ; release note - ; FIXME we have the identical code (different regs) three times (one is inactive) - move.w pcd_adsr_volume_w(a5),d4 - asr.w #6,d4 - move.w d4,pcd_adsr_vol64_w(a5) - moveq.l #16,d7 - move.w d7,pcd_adsr_pos_w(a5) - sub.w d4,d7 - lsr.w #1,d7 - add.b pcd_adsr_release_b(a5),d7 - move.b d7,pcd_adsr_phase_speed_b(a5) - move.w #3,pcd_adsr_phase_w(a5) - bra .start_patt_effect_handling + tst.b d7 + beq.s .start_patt_effect_handling -.has_inst_number - add.w d7,d0 ; pattern pitch shift? + add.w d7,d0 ; pattern pitch shift lsl.w #4,d0 - cmpi.b #3,d2 ; is command portamento? - beq.s .pat_set_portamento + cmp.b #3,d2 ; is command portamento? + beq.s .cont_after_inst_trigger + +.check_for_2nd_instrument + tst.b d4 + beq.s .cont_after_inst_trigger .trigger_new_instrument move.w d4,d1 @@ -2681,39 +1074,39 @@ pre_PlayerTick: move.l d1,(a1)+ ; pcd_inst_line_ticks_b, pcd_inst_pitch_pinned_b, pcd_inst_vol_slide_b, pcd_inst_step_pos_b subq.b #1,d1 - move.w d1,(a1)+ ; pcd_inst_wave_num_w + move.w d1,(a1)+ ; pcd_inst_wave_num4_w move.l #$ff010010,(a1)+ ; pcd_track_delay_offset_b, pcd_inst_speed_stop_b, pcd_inst_pitch_w move.l #(MAX_VOLUME<<16)|(MAX_VOLUME<<8)|MAX_VOLUME,(a1)+ ; pcd_inst_vol_w / pcd_loaded_inst_vol_b / pcd_pat_vol_b bra.s .cont_after_inst_trigger -.has_no_note_off - tst.b d7 - beq.s .start_patt_effect_handling - tst.b d4 - bne.s .has_inst_number - - add.w d7,d0 ; pattern pitch shift - lsl.w #4,d0 +.release_note + ; FIXME we have the identical code (different regs) three times (one is inactive) + move.w pcd_adsr_volume_w(a5),d4 + asr.w #6,d4 + move.w d4,pcd_adsr_vol64_w(a5) + moveq.l #16,d7 + move.w d7,pcd_adsr_pos_w(a5) + sub.w d4,d7 + lsr.w #1,d7 + add.b pcd_adsr_release_b(a5),d7 + move.b d7,pcd_adsr_phase_speed_b(a5) + move.w #3,pcd_adsr_phase_w(a5) + bra.s .start_patt_effect_handling .cont_after_inst_trigger tst.b d6 ; has ARP? - bne.s .lbC001852 - bra.s .lbC00193C + bne.s .has_arp_check_portamento -.pat_set_portamento - tst.b d6 - bne.s .pat_new_portamento -.lbC00193C - clr.l pcd_arp_notes_l(a5) - moveq.l #0,d6 +.clear_arp_notes + move.l d6,pcd_arp_notes_l(a5) ; the whole ARP flag in d6 must be 0 -.lbC001852 - cmpi.b #3,d2 ; is command portamento? +.has_arp_check_portamento + cmp.b #3,d2 ; is command portamento? beq.s .pat_new_portamento -.clear_portamento + ; clear portamento move.w #$10,pcd_inst_pitch_w(a5) move.w d0,pcd_inst_curr_port_pitch_w(a5) clr.w pcd_pat_portamento_dest_w(a5) @@ -2727,9 +1120,10 @@ pre_PlayerTick: add.w d1,pcd_inst_curr_port_pitch_w(a5) clr.w pcd_inst_pitch_w(a5) tst.b d5 - beq.s .pat_keep_old_portamento + beq.s .execute_pattern_command move.b d5,pcd_pat_portamento_speed_b(a5) .pat_keep_old_portamento + bra.s .execute_pattern_command ; ---------------------------------------- .start_patt_effect_handling @@ -2742,10 +1136,9 @@ pre_PlayerTick: move.b d3,pcd_pat_2nd_inst_delay_b(a5) .has_no_second_inst - clr.b pcd_pat_vol_ramp_speed_b(a5) - clr.w pcd_pat_pitch_slide_w(a5) - tst.b d6 + tst.b d6 ; ARP bit is set, cannot have a command bne .pat_play_cont +.execute_pattern_command add.w d2,d2 move.w .pattern_command_jmptable(pc,d2.w),d2 jmp .pattern_command_jmptable(pc,d2.w) @@ -2754,7 +1147,7 @@ pre_PlayerTick: dc.w .pat_play_nop-.pattern_command_jmptable dc.w .pat_slide_up-.pattern_command_jmptable dc.w .pat_slide_down-.pattern_command_jmptable - dc.w .pat_play_nop-.pattern_command_jmptable + dc.w .pat_play_nop-.pattern_command_jmptable ; portamento is handled above dc.w .pat_set_vibrato-.pattern_command_jmptable dc.w .pat_set_track_delay-.pattern_command_jmptable dc.w .pat_play_nop-.pattern_command_jmptable @@ -2817,17 +1210,33 @@ pre_PlayerTick: beq.s .pat_play_cont ; we are at channel 3 -- track delay not available here lea pcd_SIZEOF+pcd_track_delay_buffer+ocd_volume(a5),a1 + moveq.l #0,d3 moveq.l #MAX_TRACK_DELAY-1,d2 .clr_track_delay_buffer_loop - clr.b (a1) ; ocd_volume + move.b d3,(a1) ; ocd_volume lea ocd_SIZEOF(a1),a1 dbra d2,.clr_track_delay_buffer_loop tst.b d5 bne.s .pat_track_delay_set + IFNE PRETRACKER_BUGFIX_CODE ; clearing track delay when it already was cleared will overwrite the note needlessly + tst.b pcd_track_delay_steps_b(a5) + beq.s .pat_play_cont + ENDC st pcd_track_delay_steps_b(a5) bra.s .handle_track_delay +.pat_track_delay_set + moveq.l #15,d2 + and.b d5,d2 + add.b d2,d2 + move.b d2,pcd_track_delay_steps_b(a5) +; subq.b #1,d2 +; move.b d2,pcd_SIZEOF+pcd_track_init_delay_b(a5) + lsr.b #4,d5 + move.b d5,pcd_track_delay_vol16_b(a5) + bra.s .pat_play_cont + ; ---------------------------------------- .pat_volume_ramp tst.b d5 @@ -2846,17 +1255,6 @@ pre_PlayerTick: move.b d5,pcd_pat_vol_ramp_speed_b(a5) bra.s .pat_play_cont -.pat_track_delay_set - moveq.l #15,d2 - and.b d5,d2 - add.b d2,d2 - move.b d2,pcd_track_delay_steps_b(a5) -; subq.b #1,d2 -; move.b d2,pcd_SIZEOF+pcd_track_init_delay_b(a5) - lsr.b #4,d5 - move.b d5,pcd_track_delay_vol16_b(a5) - bra.s .pat_play_cont - ; ---------------------------------------- .pat_slide_down neg.w d5 @@ -2924,7 +1322,7 @@ pre_PlayerTick: move.b pv_pat_curr_row_b(a4),d0 addq.b #1,d0 ; normal step increment - move.w sv_curr_pat_pos_w(a6),d3 ; current song position + move.w pv_curr_pat_pos_w(a4),d3 ; current song position move.b pv_next_pat_row_b(a4),d2 ; $ff means no pattern break bmi.s .no_pattern_break @@ -2977,7 +1375,7 @@ pre_PlayerTick: ENDC .no_restart_song move.b d0,pv_pat_curr_row_b(a4) - move.w d3,sv_curr_pat_pos_w(a6) + move.w d3,pv_curr_pat_pos_w(a4) move.b pv_pat_speed_even_b(a4),d1 lsr.b #1,d0 @@ -3133,6 +1531,7 @@ pre_PlayerTick: ; d0 = current step / next step ; d5 = command parameter data / scratch ; d2 = note stitched flag +; d3 = scratch ; d6 = scratch ; ---------------------------------------- .inst_select_wave @@ -3141,28 +1540,33 @@ pre_PlayerTick: bhs .inst_cmd_cont_next add.w d5,d5 add.w d5,d5 - cmp.w pcd_inst_wave_num_w(a5),d5 + cmp.w pcd_inst_wave_num4_w(a5),d5 beq .inst_cmd_cont_next - move.w d5,pcd_inst_wave_num_w(a5) + move.w d5,pcd_inst_wave_num4_w(a5) move.l sv_waveinfo_table(a6,d5.w),a3 move.l a3,pcd_waveinfo_ptr(a5) - move.b pcd_channel_mask_b(a5),d3 - move.b d3,pcd_out_trg_b(a5) - or.b d3,pv_trigger_mask_w+1(a4) - move.l pv_wave_sample_table(a4,d5.w),a1 + + pea .inst_cmd_cont_next(pc) +.inst_select_wave_subroutine + move.w wi_chipram_w(a3),d5 + + move.b pcd_channel_mask_b(a5),d3 + or.b d3,pv_trigger_mask_w+1(a4) + move.b d3,pcd_out_trg_b(a5) + + moveq.l #0,d3 + tst.w d6 bne.s .inst_select_wave_nosync - moveq.l #0,d3 move.w wi_loop_offset_w(a3),d6 ; is unlikely 32768 - move.w wi_subloop_len_w(a3),d5 + tst.w wi_subloop_len_w(a3) bne.s .inst_set_wave_has_subloop - +.inst_set_wave_has_no_subloop adda.w d6,a1 ; add loop offset - move.w wi_chipram_w(a3),d5 sub.w d6,d5 ;cmp.w #1,d5 ; not necessary as increases in steps of 2 bhi.s .inst_set_wave_has_min_length @@ -3174,6 +1578,7 @@ pre_PlayerTick: .inst_set_wave_has_subloop move.w d3,pcd_out_lof_w(a5) move.l a1,pcd_out_ptr_l(a5) + move.w d6,pcd_inst_loop_offset_w(a5) st pcd_inst_ping_pong_dir_b(a5) moveq.l #0,d5 @@ -3181,16 +1586,19 @@ pre_PlayerTick: addq.w #1,d5 move.w d5,pcd_inst_subloop_wait_w(a5) - move.w d6,pcd_inst_loop_offset_w(a5) - bra .inst_cmd_cont_next + rts ; ---------------------------------------- .inst_select_wave_nosync - move.w wi_chipram_w(a3),d5 - moveq.l #0,d3 + IFNE PRETRACKER_BUGFIX_CODE + move.w wi_loop_offset_w(a3),d6 + tst.w wi_subloop_len_w(a3) + beq.s .inst_set_wave_has_no_subloop + ELSE tst.w wi_subloop_len_w(a3) bne.s .inst_set_wave_ns_has_subloop + ; note that nosync on non-looping waves doesn't effectivly do anything special move.w wi_loop_offset_w(a3),d6 adda.w d6,a1 @@ -3202,21 +1610,27 @@ pre_PlayerTick: move.w d5,pcd_out_len_w(a5) moveq.l #-1,d3 + ENDC .inst_set_wave_ns_has_subloop move.w d3,pcd_out_lof_w(a5) move.l a1,pcd_out_ptr_l(a5) + IFEQ PRETRACKER_BUGFIX_CODE move.w pcd_inst_loop_offset_w(a5),d6 cmp.w d6,d5 + ELSE + cmp.w pcd_inst_loop_offset_w(a5),d5 + ENDC bhs.s .inst_set_wave_ns_keep_pp st pcd_inst_ping_pong_dir_b(a5) .inst_set_wave_ns_keep_pp - moveq.l #0,d5 - move.w d5,pcd_inst_subloop_wait_w(a5) + clr.w pcd_inst_subloop_wait_w(a5) + IFEQ PRETRACKER_BUGFIX_CODE ; This adds an extra jump to the wave that's not desired sub.w wi_subloop_step_w(a3),d6 move.w d6,pcd_inst_loop_offset_w(a5) - bra .inst_cmd_cont_next + ENDC + rts ; ---------------------------------------- .inst_slide_down @@ -3364,54 +1778,18 @@ pre_PlayerTick: move.b d0,pcd_inst_step_pos_b(a5) ; update inst step pos .inst_still_ticking - tst.b pcd_inst_wave_num_w+1(a5) + tst.b pcd_inst_wave_num4_w+1(a5) bpl.s .inst_wave_selected -.inst_no_wave_selected - moveq.l #0,d3 - move.w d3,pcd_inst_wave_num_w(a5) ; FIXME why set to wave 0? just asking, because this is zero based +.inst_no_wave_selected ; FIXME this code is dubious at best -- it selects wave 0 if no wave was selected before + clr.w pcd_inst_wave_num4_w(a5) move.l sv_waveinfo_ptr(a6),a3 move.l a3,pcd_waveinfo_ptr(a5) - move.b pcd_channel_mask_b(a5),d0 - move.b d0,pcd_out_trg_b(a5) - or.b d0,pv_trigger_mask_w+1(a4) - - tst.w wi_subloop_len_w(a3) - bne.s .inst_nowave_has_subloop - - move.w wi_loop_offset_w(a3),d5 move.l pv_wave_sample_table(a4),a1 - adda.w d5,a1 - move.l a1,pcd_out_ptr_l(a5) - move.w wi_chipram_w(a3),d0 - move.w d0,d6 - subq.w #1,d6 - cmp.w d5,d6 - ble.s .lbC00118E - sub.w d5,d0 - bra.s .lbC000F48 -.lbC00118E - moveq.l #2,d0 -.lbC000F48 - move.w d0,pcd_out_len_w(a5) - subq.w #1,d3 - bra.s .inst_set_no_lof - -.inst_nowave_has_subloop - move.l pv_wave_sample_table(a4),pcd_out_ptr_l(a5) - - move.w wi_loop_offset_w(a3),d5 -.inst_set_no_lof - move.w d3,pcd_out_lof_w(a5) - moveq.l #0,d0 - move.b wi_subloop_wait_b(a3),d0 - addq.w #1,d0 - move.w d0,pcd_inst_subloop_wait_w(a5) - - move.w d5,pcd_inst_loop_offset_w(a5) - st pcd_inst_ping_pong_dir_b(a5) + moveq.l #0,d6 + bsr .inst_select_wave_subroutine .inst_wave_selected cmpi.b #$FF,d2 @@ -3419,16 +1797,18 @@ pre_PlayerTick: subq.b #1,d2 move.b d2,pcd_inst_line_ticks_b(a5) -.inst_no_inst_active .inst_pat_loop_exit3 +.inst_no_inst_active ; ---------------------------------------- - -; expects d2 = inst num ; a5 = channel move.w pcd_inst_vol_w(a5),d1 tst.b pcd_new_inst_num_b(a5) bne.s .load_instrument + IFNE PRETRACKER_BUGFIX_CODE + move.l a3,d3 + beq.s .no_inst_selected + ENDC .dont_load_instrument move.w pcd_adsr_volume_w(a5),d2 @@ -3595,7 +1975,7 @@ pre_PlayerTick: move.w d5,pcd_inst_subloop_wait_w(a5) tst.b d4 - bpl.s .wave_is_moving_backwards + bpl.s .loop_is_moving_backwards add.w d2,d1 ; increment offset in forward direction one step move.w d1,d4 @@ -3614,7 +1994,7 @@ pre_PlayerTick: clr.b pcd_inst_ping_pong_dir_b(a5) ; mark going backwards bra.s .wave_loop_dir_changed -.wave_is_moving_backwards +.loop_is_moving_backwards sub.w d2,d1 ; decrement offset in backward direction one step move.w wi_loop_start_w(a3),d4 @@ -3644,7 +2024,7 @@ pre_PlayerTick: .done_lof_calc move.w d4,pcd_out_lof_w(a5) - move.w pcd_inst_wave_num_w(a5),d1 ; FIXME can we move this to wave loading? + move.w pcd_inst_wave_num4_w(a5),d1 ; FIXME can we move this to wave loading? move.l pv_wave_sample_table(a4,d1.w),pcd_out_ptr_l(a5) bra.s .loop_handling_done @@ -3661,8 +2041,8 @@ pre_PlayerTick: clr.b pcd_wave_offset_b(a5) move.b pcd_channel_mask_b(a5),d2 ; trigger output - move.b d2,pcd_out_trg_b(a5) or.b d2,pv_trigger_mask_w+1(a4) + move.b d2,pcd_out_trg_b(a5) move.w wi_chipram_w(a3),d2 sub.w d1,d2 @@ -3676,7 +2056,7 @@ pre_PlayerTick: .waveoffset_is_not_past_end move.w d2,pcd_out_len_w(a5) - move.w pcd_inst_wave_num_w(a5),d2 + move.w pcd_inst_wave_num4_w(a5),d2 add.l pv_wave_sample_table(a4,d2.w),d1 move.l d1,pcd_out_ptr_l(a5) @@ -3745,25 +2125,26 @@ pre_PlayerTick: lsr.w #6,d5 lea pre_octave_select_table(pc),a1 moveq.l #0,d1 - move.b (a1,d5.w),d1 + move.b (a1,d5.w),d1 ; higher octave 1-3 + + move.l pcd_out_ptr_l(a5),d4 move.w pcd_out_lof_w(a5),d7 addq.w #1,d7 ; compare to $ffff beq.s .has_no_loop_offset subq.w #1,d7 lsr.w d1,d7 - move.w d7,pcd_out_lof_w(a5) + move.w d7,pcd_out_lof_w(a5) ; halve/quarter/eighth loop offset lsr.w d1,d3 - move.w d3,pcd_out_len_w(a5) - bra.s .lbC0005C0 + move.w d3,pcd_out_len_w(a5) ; halve/quarter/eighth loop length + bra.s .cont_after_loop_fix .has_no_loop_offset tst.b pcd_out_trg_b(a5) beq.s .no_retrigger_new - move.w pcd_inst_wave_num_w(a5),d7 + move.w pcd_inst_wave_num4_w(a5),d7 movea.l pv_wave_sample_table(a4,d7.w),a3 - move.l pcd_out_ptr_l(a5),d4 sub.l a3,d4 move.w d3,d6 add.w d4,d6 @@ -3785,18 +2166,16 @@ pre_PlayerTick: lsr.w d1,d4 add.l a3,d4 - move.l d4,pcd_out_ptr_l(a5) -.lbC0005C0 - subq.b #1,d1 - bmi.s .is_normal_octave +.cont_after_loop_fix + subq.w #1,d1 + ;bmi.s .is_normal_octave ; this should never happen -- d1 is at least 1 ; find offset in sample buffer for the right octave - moveq.l #0,d4 .movetoloopposloop add.l d2,d4 lsr.w #1,d2 dbra d1,.movetoloopposloop - add.l d4,pcd_out_ptr_l(a5) + move.l d4,pcd_out_ptr_l(a5) ; move trigger start pos to right octave wave .no_retrigger_new .is_normal_octave @@ -3817,6 +2196,7 @@ pre_PlayerTick: .noclippitchlow2 tst.b pcd_out_trg_b(a5) beq.s .wasnottriggered + ; this code seems to move the sample start to "loop offset" for first trigger moveq.l #0,d0 move.w pcd_out_lof_w(a5),d0 addq.w #1,d0 ; compare to $ffff @@ -3826,19 +2206,28 @@ pre_PlayerTick: clr.w pcd_out_lof_w(a5) .wasnottriggered .hasnoloop2 - cmp.w pcd_last_trigger_pos_w(a5),d3 - beq.s .hassamesampos - move.w d3,pcd_last_trigger_pos_w(a5) + ; this code is probably here to ensure triggering the wave when the octave sample changes + cmp.w pcd_last_trigger_length_w(a5),d3 + beq.s .hassamesamlen + move.w d3,pcd_last_trigger_length_w(a5) move.b pcd_channel_mask_b(a5),d3 - move.b d3,pcd_out_trg_b(a5) + IFND PRESTO_SKIP_OUTPUT or.b d3,pv_trigger_mask_w+1(a4) -.hassamesampos + ELSE + cmp.b pcd_out_trg_b(a5),d3 + beq.s .hassamesamlen + or.b d3,pv_trigger_mask_w+1(a4) + tas d3 ; we need to mark the first length loading, without trigger that is actually not a real trigger, so we can filter it + ENDC + move.b d3,pcd_out_trg_b(a5) +.hassamesamlen add.w d6,d6 move.w pv_period_table(a4,d6.w),pcd_out_per_w(a5) ; ---------------------------------------- ; track delay handling +.no_inst_selected move.b pcd_track_delay_steps_b(a5),d3 beq .incrementchannel ; no track delay @@ -3924,7 +2313,7 @@ pre_PlayerTick: move.l (a1)+,(a3)+ ; ocd_sam_ptr move.l (a1)+,(a3)+ ; ocd_length/ocd_loop_offset move.l (a1)+,(a3)+ ; ocd_period/ocd_volume/ocd_trigger - ;move.l (a1)+,(a3)+ ; this is never used + ;move.l (a1)+,(a3)+ ; this is never used ;clr.b ocd_volume-ocd_unused(a1) ; does not seem to bother @@ -3949,6 +2338,7 @@ pre_PlayerTick: ; so this changed a lot from the original routine move.w pv_trigger_mask_w(a4),d2 + IFND PRESTO_SKIP_OUTPUT IFNE PRETRACKER_COPPER_OUTPUT move.l pv_copperlist_ptr(a4),d0 beq .skipcopperlist @@ -3988,8 +2378,8 @@ pre_PlayerTick: .is_looping_sample move.l ocd_sam_ptr(a0),d0 - add.l d2,d0 - move.l d0,d6 + add.l d2,d0 ; add loop offset to sample start + move.l d0,d6 ; make a copy for loop start move.w ocd_length(a0),d4 lsr.w #1,d4 @@ -3997,7 +2387,7 @@ pre_PlayerTick: tst.b ocd_trigger(a0) beq.s .setptrvolper move.b d5,ocd_trigger(a0) - sub.l d2,d0 + sub.l d2,d0 ; if triggered, deduct loop offset so we are back at sample start .setptrvolper move.w d0,1*4(a1) ; ac_ptr (lo) swap d0 @@ -4098,6 +2488,7 @@ pre_PlayerTick: .skiprasterwait ENDC + ENDC IFNE PRETRACKER_DONT_TRASH_REGS movem.l (sp)+,d2-d7/a2-a6 @@ -4106,12 +2497,26 @@ pre_PlayerTick: ;-------------------------------------------------------------------- ; table data currently about 594 bytes + ; Tables used by WaveGen +pre_roll_off_table: ; used by WaveGen + dc.w $400,$200,$180,$140,$100,$C0,$A0,$80,$78,$74,$6E + dc.w $69,$64,$5A,$46,$40,$38,$30,$28,$20,$1F,$1E,$1D + dc.w $1C,$1B,$1A,$19,$18,$17,$16,$15,$14,$13,$12,$11 + dc.w $10,15,14,13,13,12,12,11,11,10,10,9,9,8,8,8,8,7,7 + dc.w 7,7,6,6,6,6,5,5,5,5,4,4,4,4,4,4,4,4,4,4,3,4,4,3,4 + dc.w 4,3,4,3,4,3,4,3,4,3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3 + dc.w 2,3,3,2,3,3,2,3,2,3,2,3,2,3,2,3,2,2,2,2,2,2,2,2,1 + dc.w 2,1,2,1,2,1,2,1,1,2,1,1,1,2,1 -; I assume this is a log table for freq distances within an octave +; I assume this is a log table for freq distances within an octave ; used by WaveGen 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 +pre_modulator_ramp_8: ; used by WaveGen + ;dc.w 77,293,539,1079,1337,1877,2431,3031 ; the 1079 value is strange (938 better?) + dc.w $4D,$125,$21B,$437,$539,$755,$96D,$BD7 + ; linear then steep quadratic slope pre_vib_speed_table: dc.b 2,3,4,5,6,7,8,9,10,11,12,13,14,20,40,80 @@ -4131,16 +2536,6 @@ pre_fast_roll_off_16: dc.w $400,$200,$80,$64,$50,$40,$30,$20,$10,14,12,10,8 dc.w 4,2,1 -pre_roll_off_table: - dc.w $400,$200,$180,$140,$100,$C0,$A0,$80,$78,$74,$6E - dc.w $69,$64,$5A,$46,$40,$38,$30,$28,$20,$1F,$1E,$1D - dc.w $1C,$1B,$1A,$19,$18,$17,$16,$15,$14,$13,$12,$11 - dc.w $10,15,14,13,13,12,12,11,11,10,10,9,9,8,8,8,8,7,7 - dc.w 7,7,6,6,6,6,5,5,5,5,4,4,4,4,4,4,4,4,4,4,3,4,4,3,4 - dc.w 4,3,4,3,4,3,4,3,4,3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3 - dc.w 2,3,3,2,3,3,2,3,2,3,2,3,2,3,2,3,2,2,2,2,2,2,2,2,1 - dc.w 2,1,2,1,2,1,2,1,1,2,1,1,1,2,1 - pre_octave_note_offset_table: dc.b 1*NOTES_IN_OCTAVE*4,1*NOTES_IN_OCTAVE*4,1*NOTES_IN_OCTAVE*4 dc.b 2*NOTES_IN_OCTAVE*4,2*NOTES_IN_OCTAVE*4,2*NOTES_IN_OCTAVE*4 @@ -4179,14 +2574,6 @@ pre_minus4plus4_table: dc.b $FC,$FB,$FF,1,2,3,4,0 ENDC -pre_ramp_up_down_32: - dc.w 0*32,1*32,2*32,3*32,4*32,5*32,6*32,7*32,8*32,9*32,10*32,11*32,12*32,13*32,14*32,15*32 - dc.w 15*32,14*32,13*32,12*32,11*32,10*32,9*32,8*32,7*32,6*32,5*32,4*32,3*32,2*32,1*32,0*32 - -pre_modulator_ramp_8: - ;dc.w 77,293,539,1079,1337,1877,2431,3031 ; the 1079 value is strange (938 better?) - dc.w $4D,$125,$21B,$437,$539,$755,$96D,$BD7 - pre_period_table: dc.w $350,$320,$2F2,$2C8,$2A0,$279,$256,$236,$216,$1F8,$1DC,$1C0 dc.w $1A8,$190,$179,$164,$151,$13E,$12C,$11B,$10B,$FC,$EE,$E0 diff --git a/src/raspberry_casket.i b/src/raspberry_casket.i new file mode 100644 index 0000000..09fc2c6 --- /dev/null +++ b/src/raspberry_casket.i @@ -0,0 +1,344 @@ +; Pretracker song format description: +; +; $0000 4: PRT ($19 (V0.x), $1b (V1.0), $1e (V1.5)) +; $0004 4: File offset to position data (POSD) +; $0008 4: File offset to pattern data (PATT) +; $000C 4: File offset to instruments (INST) +; $0010 4: File offset to waves (WAVE) +; $0014 20: Songname +; $0028 20: Author +; $003C 1: Restart position for song (<=V1.0) +; $003D 1: Number of patterns (<=V1.0) +; $003E 1: Songlength in patterns (<=V1.0) +; $003F 1: Number of steps per pattern (<=V1.0) +; $0040 1: Number of instruments (<=V1.0), $40 for V1.5 +; $0041 1: Number of waves +; $0042 24: Wave generation ordering (>=V1.0) +; $005a 1: Number of subsongs (>=V1.5) +; [...] +; Position data (POSD): +; - Per subsong (>=V1.5) +; - 1: Restart pos +; - 1: #patterns +; - 1: #numsteps +; - 1: songlength +; - 4: relative pattern offset in pattern data +; - Positions x 4 x [Pattern number (byte), pitch shift (signed byte)] +; +; Pattern data (PATT): +; Each pattern line consists of three bytes: +; - 1 Bit : Bit 4 of Inst Number +; - 1 Bit : ARP instead of effect +; - 6 Bits: Pitch ($01 is C-0, $3d is NOTE OFF) +; +; - 4 Bits: Bit 0-3 of Inst Number +; - 4 Bits: Effect command +; - 8 Bits: Effect data +; - Patterns x steps x 3 bytes +; +; Unknown data after pattern data: (12 10 00 00 00 00) +; +; Instrument definitions (INST): +; - 32 (!) x Null terminated string (or 23 chars max) (for V1.5 this is 64 strings) +; - For each instrument: Instrument Info (ININ) +; - $00 1: Vibrato Delay +; - $01 1: Vibrato Depth +; - $02 1: Vibrato Speed (-1) +; - $03 1: ADSR Attack +; - $04 1: ADSR Decay +; - $05 1: ADSR Sustain +; - $06 1: ADSR Release +; - $07 1: Number of Inst Pattern steps +; +; - For each instrument: +; - 1 Byte: number of steps +; - 3 Bytes x number of steps: Inst Pattern (IPTT) +; +; Inst pattern data (IPTT): +; Each pattern line consists of three bytes: +; - 1 Bit : Next note stitched to this one +; - 1 Bit : Fixed Pitch Note +; - 6 Bits : Pitch ($01 is C-0) +; - 4 Bits : unused? +; - 12 Bits: Effect +; - Patterns x steps x 3 bytes +; +; Wave definitions (WAVE): +; - 24 (!) x Null terminated string (or 23 chars max) +; - Optional padding to even address, if necessary +; - For each wave: +; - 42 Bytes: Wave info structure (see definition below) + +; ---------------------------------------- +; Some constants for clarity + +MAX_VOLUME = $40 +MAX_SPEED = $2f +MAX_WAVES = 24 +MAX_INSTRUMENTS = 32 +MAX_TRACK_DELAY = 32 +NOTE_OFF_PITCH = $3d +NOTES_IN_OCTAVE = 12 +NUM_CHANNELS = 4 ; yes, you can reduce the number of channels if you want + +; ---------------------------------------- +; Pretracker file structures + +; Pattern data (PATT and IPTT) +pdb_pitch_ctrl = 0 +pdb_inst_effect = 1 ; for normal pattern data +pdb_effect_cmd = 1 ; for inst pattern +pdb_effect_data = 2 + +; Pattern pos data (POSD) +ppd_pat_num = 0 +ppd_pat_shift = 1 + +; Instrument Info (ININ) +ii_vibrato_delay = 0 +ii_vibrato_depth = 1 +ii_vibrato_speed = 2 +ii_adsr_attack = 3 +ii_adsr_decay = 4 +ii_adsr_sustain = 5 +ii_adsr_release = 6 +ii_pattern_steps = 7 +ii_SIZEOF = 8 + +; Wave Info (WAVE) +wi_loop_start_w = $00 +wi_loop_end_w = $02 +wi_subloop_len_w = $04 +wi_allow_9xx_b = $06 +wi_subloop_wait_b = $07 +wi_subloop_step_w = $08 +wi_chipram_w = $0a +wi_loop_offset_w = $0c +wi_chord_note1_b = $0e +wi_chord_note2_b = $0f +wi_chord_note3_b = $10 +wi_chord_shift_b = $11 +wi_osc_unknown_b = $12 ; always $00? (unused in code?) +wi_osc_phase_spd_b = $13 +wi_flags_b = $14 ; bit 0/1: osc type, bit 2: needs extra octaves, bit 3: boost, bit 4: pitch linear, bit 5: vol fast +wi_osc_phase_min_b = $15 +wi_osc_phase_max_b = $16 +wi_osc_basenote_b = $17 +wi_osc_gain_b = $18 +wi_sam_len_b = $19 ; in multiples of 128, zero-based (0 == 128) +wi_mix_wave_b = $1a +wi_vol_attack_b = $1b +wi_vol_delay_b = $1c +wi_vol_decay_b = $1d +wi_vol_sustain_b = $1e +wi_flt_type_b = $1f ; 1=lowpass, 2=highpass, 3=bandpass, 4=notch +wi_flt_resonance_b = $20 +wi_pitch_ramp_b = $21 +wi_flt_start_b = $22 +wi_flt_min_b = $23 +wi_flt_max_b = $24 +wi_flt_speed_b = $25 +wi_mod_params_l = $26 +wi_mod_wetness_b = $26 +wi_mod_length_b = $27 +wi_mod_predelay_b = $28 +wi_mod_density_b = $29 ; (1-7), unisono (bits 3/4) and post bit 5 +wi_SIZEOF = $2a + +; ---------------------------------------- +; Unpacked Instrument Info (addition to player for faster processing) + rsreset +uii_vibrato_delay rs.w 1 +uii_vibrato_depth rs.w 1 +uii_vibrato_speed rs.w 1 +uii_adsr_release rs.b 1 + rs.b 1 ; dummy +uii_adsr_attack rs.w 1 +uii_adsr_decay rs.w 1 +uii_adsr_sustain rs.w 1 +uii_pattern_steps rs.b 1 + rs.b 1 ; padding +uii_SIZEOF rs.b 0 + +; ---------------------------------------- +; MySong offsets + rsreset +sv_waveinfo_table rs.l MAX_WAVES ; 24 pointers to wave infos to avoid mulu +sv_inst_patterns_table rs.l MAX_INSTRUMENTS ; 32 pointers to pattern data + ; --- 127 byte displacement limit --- +sv_wavelength_table rs.l MAX_WAVES ; 24 longwords to sample lengths (standard octave) (NEW) +sv_wavetotal_table rs.l MAX_WAVES ; 24 longwords to sample lengths for all octaves (NEW) +sv_wavegen_order_table rs.b MAX_WAVES ; 24 bytes +sv_num_waves_b rs.b 1 +sv_num_steps_b rs.b 1 +sv_patterns_ptr rs.l 1 +sv_pat_pos_len_w rs.w 1 ; only byte used +sv_pat_restart_pos_w rs.w 1 ; only byte used +sv_pos_data_adr rs.l 1 +sv_waveinfo_ptr rs.l 1 ; base pointer of wave info +sv_pattern_table rs.l 256 +sv_inst_infos_table rs.b MAX_INSTRUMENTS*uii_SIZEOF +sv_SIZEOF rs.b 0 + +; ---------------------------------------- +; channel output data (part of pcd structure below) + rsreset +ocd_sam_ptr rs.l 1 ; 0 +ocd_length rs.w 1 ; 4 +ocd_loop_offset rs.w 1 ; 6 +ocd_period rs.w 1 ; 8 +ocd_volume rs.b 1 ; 10 +ocd_trigger rs.b 1 ; 11 needs to be after volume +ocd_unused rs.l 1 ; 12 unused, but makes the structure an even 16 bytes +ocd_SIZEOF rs.b 0 + +; channel structure (part of pv structure) + rsreset +; DO NOT CHANGE ORDER -- OPTIMIZED CLEARING +pcd_pat_portamento_dest_w rs.w 1 ; portamento destination pitch +pcd_pat_pitch_slide_w rs.w 1 + +pcd_pat_vol_ramp_speed_b rs.b 1 +pcd_pat_2nd_inst_num4_b rs.b 1 +pcd_pat_2nd_inst_delay_b rs.b 1 +pcd_wave_offset_b rs.b 1 + +pcd_inst_pitch_slide_w rs.w 1 +pcd_inst_sel_arp_note_w rs.w 1 + +pcd_inst_note_pitch_w rs.w 1 +pcd_inst_curr_port_pitch_w rs.w 1 + +pcd_inst_line_ticks_b rs.b 1 +pcd_inst_pitch_pinned_b rs.b 1 +pcd_inst_vol_slide_b rs.b 1 +pcd_inst_step_pos_b rs.b 1 + +pcd_inst_wave_num4_w rs.w 1 ; current wave number (1 based, times 4) (lower byte used) + +pcd_track_delay_offset_b rs.b 1 ; $ff = no track delay +pcd_inst_speed_stop_b rs.b 1 ; speed byte, $ff stops processing +pcd_inst_pitch_w rs.w 1 + +pcd_inst_vol_w rs.w 1 +pcd_loaded_inst_vol_b rs.b 1 +pcd_pat_vol_b rs.b 1 ; Multiplied with volume of instrument. +; DO NOT CHANGE ORDER -- OPTIMIZED CLEARING END + +pcd_arp_notes_l rs.b 0 +pcd_arp_note_1_b rs.b 1 +pcd_arp_note_2_b rs.b 1 +pcd_arp_note_3_b rs.b 1 + rs.b 1 ; gets cleared + +pcd_last_trigger_length_w rs.w 1 ; I think this makes sure that we trigger the note if the length changes + +pcd_pat_portamento_speed_b rs.b 1 +pcd_pat_adsr_rel_delay_b rs.b 1 ; counts down until adsr release. Seems unused? +pcd_note_off_delay_b rs.b 1 ; time before note is released ($ff = disabled) +pcd_inst_pattern_steps_b rs.b 1 ; number of steps in instrument pattern + +pcd_note_delay_b rs.b 1 ; $ff = no note delay +pcd_track_delay_steps_b rs.b 1 ; $00 = no track delay, $ff = stop track delay (this is for the next channel!) +pcd_track_delay_vol16_b rs.b 1 +pcd_track_init_delay_b rs.b 1 ; number of frames to ignore the delay + +pcd_inst_num4_w rs.w 1 ; current instrument number * 4 +;pcd_inst_new_step_w rs.w 1 ; seems to be unused +pcd_inst_subloop_wait_w rs.w 1 +pcd_inst_loop_offset_w rs.w 1 +pcd_inst_info_ptr rs.l 1 ; pointer to currently active instrument + +pcd_waveinfo_ptr rs.l 1 ; pointer to currently active waveinfo +pcd_channel_mask_b rs.b 1 +pcd_channel_num_b rs.b 1 +pcd_adsr_phase_w rs.w 1 ; 0=attack, 1=decay, 2=sustain, 3=release ! do not change order +pcd_adsr_volume_w rs.w 1 ; 0 for restart / $400 (word only) ! do not change order +pcd_adsr_phase_speed_b rs.b 1 +pcd_inst_ping_pong_dir_b rs.b 1 ; direction of ping-pong (-1 == $00 / +1 = $ff) +pcd_adsr_pos_w rs.w 1 ; pos in adsr curve +pcd_adsr_vol64_w rs.w 1 ; some adsr volume + +pcd_new_inst_num_b rs.b 1 ; load new instrument (number) ! do not change order + rs.b 1 ; gets cleared +pcd_vibrato_pos_w rs.w 1 ; +pcd_vibrato_delay_w rs.w 1 ; is a byte value ! do not change order +pcd_vibrato_depth_w rs.w 1 ; is a byte value ! do not change order +pcd_vibrato_speed_w rs.w 1 ; is a byte value ! do not change order +pcd_adsr_release_b rs.b 1 ; is a byte value ! do not change order + rs.b 1 ; padding will be overwritten! + +pcd_out_base rs.b ocd_SIZEOF +pcd_track_delay_buffer rs.b MAX_TRACK_DELAY*ocd_SIZEOF +pcd_SIZEOF rs.b 0 + +pcd_out_ptr_l = pcd_out_base+ocd_sam_ptr +pcd_out_len_w = pcd_out_base+ocd_length +pcd_out_lof_w = pcd_out_base+ocd_loop_offset +pcd_out_per_w = pcd_out_base+ocd_period +pcd_out_vol_b = pcd_out_base+ocd_volume +pcd_out_trg_b = pcd_out_base+ocd_trigger +pcd_out_unused_l = pcd_out_base+ocd_unused ; copied for track delay, but not used? + + rsreset +owb_saw_waves rs.b 128 +owb_sqr_waves rs.b 128 +owb_tri_waves rs.b 128 +owb_wave_length rs.b 1 +owb_SIZEOF rs.b 0 + +; ---------------------------------------- +; MyPlayer global variables (not bound to channel) + rsreset +; DO NOT CHANGE ORDER -- OPTIMIZED INIT +pv_pat_curr_row_b rs.b 1 ; current step +pv_next_pat_row_b rs.b 1 +pv_next_pat_pos_b rs.b 1 +pv_pat_speed_even_b rs.b 1 ; even shuffle speed + +pv_pat_speed_odd_b rs.b 1 ; odd shuffle speed +pv_pat_line_ticks_b rs.b 1 +pv_pat_stopped_b rs.b 1 ; 0 = stop, $ff = run +pv_songend_detected_b rs.b 1 +; DO NOT CHANGE ORDER -- OPTIMIZED INIT END + +pv_curr_pat_pos_w rs.w 1 ; only byte used +pv_loop_pattern_b rs.b 1 ; repeat current pattern, do not advance + rs.b 1 ; padding + +pv_trigger_mask_w rs.w 1 + +pv_my_song rs.l 1 +pv_copperlist_ptr rs.l 1 +pv_sample_buffer_ptr rs.l 1 ; pointer to start of sample buffer +pv_wave_sample_table rs.l MAX_WAVES ; 24 pointers to sample starts +pv_period_table rs.w 16*NOTES_IN_OCTAVE*3 + ; --- 127 byte displacement limit --- +pv_channeldata rs.b NUM_CHANNELS*pcd_SIZEOF + + IFNE PRETRACKER_VOLUME_TABLE +pv_osc_buffers rs.b 0 ; reuse space of volume_table, which is bigger than NOTES_IN_OCTAVE*owb_SIZEOF +pv_volume_table rs.b (MAX_VOLUME+1)*MAX_VOLUME*2 + ELSE +pv_osc_buffers rs.b NOTES_IN_OCTAVE*owb_SIZEOF + ENDC + +pv_precalc_sample_size rs.l 1 +pv_precalc_progress_ptr rs.l 1 +pv_wg_wave_counter_w rs.w 1 + IFNE PRETRACKER_PARANOIA_MODE ; same wave for mixing cannot be selected in Pretracker +pv_wg_curr_wave_num_b rs.b 1 + rs.b 1 + ENDC +pv_wg_curr_sample_ptr rs.l 1 +pv_wg_curr_samend_ptr rs.l 1 +pv_wg_curr_sample_len_l rs.w 1 +pv_wg_curr_sample_len_w rs.w 1 +pv_wg_chord_note_num_b rs.b 1 ; don't change order +pv_wg_unisono_run_b rs.b 1 ; don't change order +pv_wg_chord_flag_w rs.w 1 +pv_wg_chord_pitches rs.l 1 +pv_wg_osc_speed_l rs.l 1 +pv_wg_flt_taps rs.w 4 +pv_SIZEOF rs.b 0 + diff --git a/src/raspberry_casket_wavegen.asm b/src/raspberry_casket_wavegen.asm new file mode 100644 index 0000000..b41e2fa --- /dev/null +++ b/src/raspberry_casket_wavegen.asm @@ -0,0 +1,1297 @@ + +CLIPTO8BIT MACRO + cmpi.w #-$80,\1 + bge.s .nominclip\@ + moveq.l #-$80,\1 +.nominclip\@ + cmpi.w #$7F,\1 + ble.s .nomaxclip\@ + moveq.l #$7F,\1 +.nomaxclip\@ + ENDM + +CLIPORTRUNC8BIT MACRO + beq.s .unboosted\@ + asr.l #6,\1 + cmpi.w #-$80,\1 + bge.s .nominclip\@ + moveq.l #-$80,\1 +.nominclip\@ + cmpi.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.b d6,owb_wave_length-owb_sqr_waves(a3) + + 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)+ + + suba.l a5,a5 + 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,d1 + moveq.l #NOTES_IN_OCTAVE,d2 + move.w d0,d1 + move.w d0,a2 ; save base note, used later (much later, noise generator)! + add.w #NOTES_IN_OCTAVE*NOTES_IN_OCTAVE,d1 ; make sure we don't run into negative modulo + divu d2,d1 + swap d1 + move.w d1,d0 ; note within octave + swap d1 + sub.w d2,d1 ; restore octave + + mulu #owb_SIZEOF,d0 + lea (a4,d0.w),a1 + + lea pv_osc_buffers+owb_saw_waves(a1),a6 + moveq.l #3,d0 + and.b wi_flags_b(a3),d0 + beq.s .osc_selected + lea owb_tri_waves-owb_saw_waves(a6),a6 + subq.b #1,d0 + beq.s .osc_selected + lea owb_sqr_waves-owb_tri_waves(a6),a6 + subq.b #1,d0 + beq.s .osc_selected + suba.l a6,a6 ; noise selected +.osc_selected + + move.l #$8000,d6 + move.w d1,d0 ; check octave shift + bgt.s .shiftleft + beq.s .contshift +;.shiftright + move.w d0,d3 + neg.w d3 + asr.l d3,d6 + bra.s .contshift +.shiftleft + lsl.l d0,d6 +.contshift + +; ---------------------------------------- +; pitch ramp + move.b wi_pitch_ramp_b(a3),d3 + ext.w d3 + ext.l d3 + btst #4,wi_flags_b(a3) ; pitch linear flag + beq.s .pitch_not_linear + tst.b d3 + bgt.s .pitch_ramp_positive + + lsl.l d0,d3 + add.l d3,d3 + bra.s .pitch_ramp_cont + +.pitch_not_linear + tst.b d3 + ble.s .pitch_ramp_cont +.pitch_ramp_positive + muls d3,d3 +.pitch_ramp_cont + move.l d3,d2 + lsl.l #8,d2 + lsl.l #2,d2 + + moveq.l #0,d7 + move.b pv_osc_buffers+owb_wave_length(a1),d7 ; get period + moveq.l #15,d5 + lsl.l d5,d7 + + sub.w d0,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) + + ; 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 + + cmp.l d7,d0 + ble.s .lbC002516 +.lbC002510 + sub.l d7,d0 + cmp.l d7,d0 + bgt.s .lbC002510 +.lbC002516 + move.l a6,d4 + bne .no_noise + +; ---------------------------------------- +; d1 = octave +; d2 = pitch ramping value +; d5 = osc phase speed +; a2 = base note +.gen_noise + IFNE PRETRACKER_PARANOIA_MODE + tst.w pv_wg_curr_sample_len_w(a4) + beq .wave_gen_tone_done + ENDC + + move.l #$8000,d5 + 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 + + 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 + + cmpa.l #$8000,a5 ; if symmetrical + beq.s .gen_noise_centered + ; FIXME what does this do? d4 = (a5 - $8000) d1 = (a5 + $7fff)&$ffff8000 -> d4 - d1 == ((a5 - $8000) - ((a5 + $7fff)&$ffff8000) + move.l a5,d4 + addi.l #$FFFF8000,d4 + move.l a5,d1 + addi.l #$FFFF7FFF,d1 + andi.w #$8000,d1 + movea.l d4,a5 + suba.l d1,a5 +.gen_noise_centered + + move.b d0,d1 + ext.w d1 + move.w d3,d4 + muls d1,d4 + move.l d4,d1 + asr.l #7,d1 + CLIPTO8BIT d1 + add.b (a0),d1 + +.gen_noise_innerloop + move.b d1,(a0)+ + 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 + asr.l #7,d4 + sub.l d4,d2 +.noise_nonlinear_pitch + + cmpa.w #$1FF,a1 + bgt.s .gen_noise_no_pitch_ramping + moveq.l #0,d2 + move.l d2,a5 + ;suba.l a5,a5 + movea.w #$200,a1 +.gen_noise_no_pitch_ramping + cmpa.l pv_wg_curr_samend_ptr(a4),a0 + beq .wave_gen_tone_done + cmpa.w #$7FFF,a5 + ble.s .gen_noise_innerloop + bra .gen_noise_outerloop + +.no_noise + 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.b #3,d1 + moveq.l #9,d4 + sub.b 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 + cmpa.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)+ + cmpa.l a0,a1 + bne.s .filter_innerloop + +.filterloop_end_test + movem.w d3-d6,pv_wg_flt_taps(a4) + movem.l (sp)+,d3-d5 + + cmpa.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 + cmpi.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 + cmpi.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 + cmpi.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)+ + + cmpa.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 + cmpi.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)+ + + cmpa.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 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 +; +; d6: wetness (word) +; uses all data registers and a0-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 + add.w d7,d3 + addq.w #8,d3 + smi d1 + ext.w d1 + eor.w d3,d1 + lsr.w #6,d1 ; 4 bit key is bits 14 to 11, needs to be 8 to 5 + and.w #15<<5,d1 + ext.l d1 + + add.l d5,d1 + lsr.l #6,d1 + + move.w d2,d0 + sub.w d1,d0 + bmi.s .isneg + + 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) +.isneg + 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