; Pretracker song format description: ; ; $0000 4: PRT ($19/$1a (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 ; ; 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 ; 0x00 / 0x01 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_clone_wave_b = $12 ; only used by tracker itself 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_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_inst_infos_table rs.b MAX_INSTRUMENTS*uii_SIZEOF sv_pattern_table rs.l 256 sv_SIZEOF rs.b 0 ; ---------------------------------------- ; channel output data (part of pcd structure below) -- FIXED ORDER! 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_last_wave_was_looping_b rs.b 1 ; -1 if the last wave was a looping one so no-sync is actually allowed pcd_wave_nosync rs.b 1 ; For Presto (otherwise padding): Store if the wave currently uses nosync or not 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, $xx = track delay xx (this is for the next channel!) pcd_track_delay_vol16_b rs.b 1 ; needs to be at even address (using word access to shift << 8) 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_wave_ptr rs.l 1 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_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_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_sample_buffer_ptr rs.l 1 ; pointer to start of sample buffer pv_stop_len_lof rs.l 1 ; $0002 / $0000 pv_stop_per_vol_trg rs.l 1 ; $007b / $00 / $00 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