Wavegen optimizations, cosmetics and another mystery solved.

This commit is contained in:
Chris Hodges 2023-08-24 22:07:42 +02:00
parent b805349bf0
commit ef1c519a6c
5 changed files with 69 additions and 58 deletions

View File

@ -1,7 +1,7 @@
# Raspberry Casket # Raspberry Casket
A fast and small open source Pretracker replayer A fast and small open source Pretracker replayer
## Raspberry Casket Player V2.x (22-Aug-2023) ## Raspberry Casket Player V2.x (24-Aug-2023)
Provided by Chris 'platon42' Hodges <chrisly@platon42.de> Provided by Chris 'platon42' Hodges <chrisly@platon42.de>
@ -101,7 +101,7 @@ The original code compressed with *Blueberry's* Shrinkler goes from
18052 bytes down to 9023 bytes. 18052 bytes down to 9023 bytes.
Raspberry Casket, depending on the features compiled in, is about Raspberry Casket, depending on the features compiled in, is about
5732 bytes and shrinkles down to ~4084 bytes (in isolation). 5716 bytes and shrinkles down to ~4071 bytes (in isolation).
So this means that the optimization is not just "on the outside". So this means that the optimization is not just "on the outside".
@ -137,18 +137,33 @@ about 34 on average!).
Watch out for *Presto*, the [LightSpeedPlayer](https://github.com/arnaud-carre/LSPlayer) variant that should Watch out for *Presto*, the [LightSpeedPlayer](https://github.com/arnaud-carre/LSPlayer) variant that should
solve this problem. solve this problem.
### Secrets
- Pink never actually documented how the 0xy command works (2nd instrument, not an ARP!).
It will play the instrument y for x+1 ticks before going to the actual instrument you wanted to trigger in the first place.
This works well, e.g. for bassdrums and other short percussion samples. Note that because y is a 4 bit nibble, you can only
specify the instruments $1-$f this way and not $10-$1f.
### Known issues ### Known issues
- Songs saved with earlier versions of Pretracker than 1.0 (internal version lower than $1b) have stored the ADSR values differently in the file.
There is no provision for fixing these values neither in the original player nor in Raspberry Casket. Loading the file in the tracker and saving
it again will cure this. This is more of a hypothetical problem as you are unlikely to use a Pretracker V0.9 beta version, but it took me quite a
while why Pink's "On and On" has a broken first wave sample in all the replayers but not on the tracker itself. This affects these tunes:
Attack and Release, On and On, Rewind, Cold and Tired, PreFix all by Pink and Cracksteady by Tecon.
- Behaviour for undefined volume slides with both up- and down nibble specified is different (e.g. A9A, hi Rapture!). Don't do that. - Behaviour for undefined volume slides with both up- and down nibble specified is different (e.g. A9A, hi Rapture!). Don't do that.
- Don't use loops with odd lengths and offsets (even if Pretracker allows this when dragging the loop points). - Don't use loops with odd lengths and offsets (even if Pretracker allows this when dragging the loop points).
- Don't stop the music with F00 and use a note delay (EDx) in the same line. - Don't stop the music with F00 and use a note delay (EDx) in the same line.
- Don't try to play music with no waves, instruments or patterns. - Don't try to play music with no waves, instruments or patterns.
- Pattern breaks with target row >= $7f will be ignored. - The original player had the internal state machine running for wave 1 even if no note had been triggered yet on the channel.
This could cause the first instrument using a 4xx command (trigger wave without sync) in the instrument pattern to start at
a more or less random first loop offset instead of from the beginning. This is fixed in Raspberry Casket.
- Shinobi seemed to have used an early beta version of Pretracker where it was possible to specify a Subloop Wait of 0. That's illegal and unsupported. - Shinobi seemed to have used an early beta version of Pretracker where it was possible to specify a Subloop Wait of 0. That's illegal and unsupported.
- Pattern breaks with target row >= $7f will be ignored.
- Pattern break (Dxx) + Song pos (Bxx) on the same line does not work in original Pretracker & Player: New Dxx position is ignored. - Pattern break (Dxx) + Song pos (Bxx) on the same line does not work in original Pretracker & Player: New Dxx position is ignored.
There is code to enable it in the player, so you could in theory make backwards running tracks like in Protracker. There is code to enable it in the player, so you could in theory make backwards running tracks like in Protracker.
But this doesn't make sense as long as the tracker itself does not support it. But this doesn't make sense as long as the tracker itself does not support it.
- Setting the same track delay multiple times will no longer mute the delayed channel. - Setting the same track delay multiple times will no longer mute the delayed channel and the new volume will take effect immediately.
- Clearing the track delay (multiple times) will no longer mute the delayed channel nor cause a delay of one tick to the note played in the no-longer delayed channel. - Clearing the track delay (multiple times) will no longer mute the delayed channel nor cause a delay of one tick to the note played in the no-longer delayed channel.
## Changelog ## Changelog
@ -168,9 +183,9 @@ solve this problem.
- Bugfix: Songend detection for back-jumps was broken since at least V1.1. - Bugfix: Songend detection for back-jumps was broken since at least V1.1.
- Optimized some more wave selection code. - Optimized some more wave selection code.
- Nosync/sync wave selection optimized. - Nosync/sync wave selection optimized.
- Optimized wave generation a bit more (noise generator). - Optimized wave generation a lot (esp. noise generator).
- Added Presto player draft. - Added Presto player draft.
- Drop-in replacement code size: 5732 bytes. - Drop-in replacement code size: 5716 bytes.
### V1.x (unreleased) ### V1.x (unreleased)
- Fixed a bug regarding the copper output mode with looping waves having a loop-offset. - Fixed a bug regarding the copper output mode with looping waves having a loop-offset.

Binary file not shown.

View File

@ -1,5 +1,5 @@
;-------------------------------------------------------------------- ;--------------------------------------------------------------------
; Raspberry Casket Player V2.x (22-Aug-2023) ; Raspberry Casket Player V2.x (24-Aug-2023)
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; ;
; Provided by Chris 'platon42' Hodges <chrisly@platon42.de> ; Provided by Chris 'platon42' Hodges <chrisly@platon42.de>
@ -96,7 +96,7 @@
; 18052 bytes down to 9023 bytes. ; 18052 bytes down to 9023 bytes.
; ;
; Raspberry Casket, depending on the features compiled in, is about ; Raspberry Casket, depending on the features compiled in, is about
; 5732 bytes and shrinkles down to ~4084 bytes (in isolation). ; 5716 bytes and shrinkles down to ~4071 bytes (in isolation).
; ;
; So this means that the optimization is not just "on the outside". ; So this means that the optimization is not just "on the outside".
; ;
@ -2478,7 +2478,7 @@ pre_PlayerTick:
rts rts
;-------------------------------------------------------------------- ;--------------------------------------------------------------------
; table data currently about 446 bytes ; table data currently about 450 bytes
; Tables used by WaveGen ; Tables used by WaveGen
pre_roll_off_table: ; 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 $400,$200,$180,$140,$100,$C0,$A0,$80,$78,$74,$6E
@ -2490,11 +2490,6 @@ pre_roll_off_table: ; used by WaveGen
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,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 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 ; 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 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 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 dc.w $4D,$125,$21B,$437,$539,$755,$96D,$BD7
@ -2515,8 +2510,8 @@ pre_ramp_up_16:
dc.b 0,1,3,6,7,9,10,11,12,13,14,16,19,35,55,143 dc.b 0,1,3,6,7,9,10,11,12,13,14,16,19,35,55,143
pre_fast_roll_off_16: pre_fast_roll_off_16:
dc.w $400,$200,$80,$64,$50,$40,$30,$20,$10,14,12,10,8 dc.w $400,$200,$80,$64,$50,$40,$30,$20
dc.w 4,2,1 dc.w 16,14,12,10,8,4,2,1
IFNE PRETRACKER_DUBIOUS_PITCH_SHIFT_FOR_DELAYED_TRACK IFNE PRETRACKER_DUBIOUS_PITCH_SHIFT_FOR_DELAYED_TRACK
; -4,-3,-1,1,2,3,4,0 ; -4,-3,-1,1,2,3,4,0

View File

@ -1,6 +1,6 @@
; Pretracker song format description: ; Pretracker song format description:
; ;
; $0000 4: PRT<version> ($19 (V0.x), $1b (V1.0), $1e (V1.5)) ; $0000 4: PRT<version> ($19/$1a (V0.x), $1b (V1.0), $1e (V1.5))
; $0004 4: File offset to position data (POSD) ; $0004 4: File offset to position data (POSD)
; $0008 4: File offset to pattern data (PATT) ; $0008 4: File offset to pattern data (PATT)
; $000C 4: File offset to instruments (INST) ; $000C 4: File offset to instruments (INST)
@ -281,7 +281,6 @@ pcd_out_unused_l = pcd_out_base+ocd_unused ; copied for track delay,
owb_saw_waves rs.b 128 owb_saw_waves rs.b 128
owb_sqr_waves rs.b 128 owb_sqr_waves rs.b 128
owb_tri_waves rs.b 128 owb_tri_waves rs.b 128
owb_wave_length rs.b 1
owb_SIZEOF rs.b 0 owb_SIZEOF rs.b 0
; ---------------------------------------- ; ----------------------------------------

View File

@ -41,7 +41,7 @@ CLIPTO8BITAFTERADD MACRO
pre_WaveGen: pre_WaveGen:
; ---------------------------------------- ; ----------------------------------------
lea pre_log12_table(pc),a0 ; 128, 121, 114, 107, 102, 96, 90, 85, 80, 76, 72, 67 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 lea pv_osc_buffers+owb_sqr_waves(a4),a3
moveq.l #NOTES_IN_OCTAVE-1,d7 moveq.l #NOTES_IN_OCTAVE-1,d7
.noteloop .noteloop
@ -49,7 +49,6 @@ pre_WaveGen:
moveq.l #0,d6 moveq.l #0,d6
move.w d6,d7 ; tabpos move.w d6,d7 ; tabpos
move.b (a0)+,d6 ; period move.b (a0)+,d6 ; period
move.b d6,owb_wave_length-owb_sqr_waves(a3)
move.l #$ff00,d5 move.l #$ff00,d5
divu d6,d5 ; frac increment divu d6,d5 ; frac increment
@ -184,7 +183,6 @@ pre_WaveGen:
move.b d2,(a1)+ move.b d2,(a1)+
move.b d3,(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 clr.w pv_wg_chord_note_num_b(a4) ; and pv_wg_chord_note_num_b
.wavegen_chordloop .wavegen_chordloop
@ -199,32 +197,32 @@ pre_WaveGen:
cmp.b wi_osc_basenote_b(a3),d0 cmp.b wi_osc_basenote_b(a3),d0
beq .wave_gen_tone_done ; skip chord notes that are same as base note beq .wave_gen_tone_done ; skip chord notes that are same as base note
.base_note_is_never_skipped .base_note_is_never_skipped
moveq.l #0,d1 moveq.l #0,d5
moveq.l #NOTES_IN_OCTAVE,d2 moveq.l #NOTES_IN_OCTAVE,d2
move.w d0,d1 move.w d0,d5
move.w d0,a2 ; save base note, used later (much later, noise generator)! 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 add.w #NOTES_IN_OCTAVE*NOTES_IN_OCTAVE,d5 ; make sure we don't run into negative modulo
divu d2,d1 divu d2,d5
swap d1 sub.w d2,d5 ; restore octave, result may be negative
move.w d1,d0 ; note within octave move.w d5,d1 ; +-octave
swap d1 swap d5 ; note within octave
sub.w d2,d1 ; restore octave, result may be negative
mulu #owb_SIZEOF,d0 moveq.l #0,d7
lea (a4,d0.w),a1 move.b .pre_log12_table(pc,d5.w),d7 ; 128, 121, 114, 107, 102, 96, 90, 85, 80, 76, 72, 67
lea pv_osc_buffers+owb_saw_waves(a1),a6
moveq.l #3,d0 moveq.l #3,d0
mulu d0,d5
and.b wi_flags_b(a3),d0 and.b wi_flags_b(a3),d0
beq.s .osc_selected beq.s .osc_selected
lea owb_tri_waves-owb_saw_waves(a6),a6 addq.w #2,d5
subq.b #1,d0 subq.w #1,d0
beq.s .osc_selected beq.s .osc_selected
lea owb_sqr_waves-owb_tri_waves(a6),a6 subq.w #1,d5
subq.b #1,d0 subq.w #1,d0
beq.s .osc_selected
suba.l a6,a6 ; noise selected
.osc_selected .osc_selected
lea pv_osc_buffers+owb_saw_waves(a4),a6
lsl.w #7,d5
adda.w d5,a6
; ---------------------------------------- ; ----------------------------------------
; pitch ramp ; pitch ramp
@ -233,15 +231,20 @@ pre_WaveGen:
ext.l d2 ext.l d2
btst #4,wi_flags_b(a3) ; pitch linear flag btst #4,wi_flags_b(a3) ; pitch linear flag
beq.s .pitch_not_linear beq.s .pitch_not_linear
tst.b d2 tst.w d2
bgt.s .pitch_ramp_positive bgt.s .pitch_ramp_positive
; FIXME what happens if d1 is negative? rolls out by 63?
lsl.l d1,d2 lsl.l d1,d2
add.l d2,d2 add.l d2,d2
bra.s .pitch_ramp_cont bra.s .pitch_ramp_cont
.pre_log12_table
dc.b $400000/$8000,$400000/$871d,$400000/$8f2f,$400000/$97b7,$400000/$9fc4,$400000/$a9de
dc.b $400000/$b505,$400000/$bf49,$400000/$cb31,$400000/$d645,$400000/$e215,$400000/$f1a0
.pitch_not_linear .pitch_not_linear
tst.b d2 tst.w d2
ble.s .pitch_ramp_cont ble.s .pitch_ramp_cont
.pitch_ramp_positive .pitch_ramp_positive
muls d2,d2 muls d2,d2
@ -250,8 +253,8 @@ pre_WaveGen:
lsl.l #2,d2 lsl.l #2,d2
; check whether we have a noise oscillator or something else ; check whether we have a noise oscillator or something else
move.l a6,d4 tst.w d0
bne .no_noise beq .no_noise
; ---------------------------------------- ; ----------------------------------------
; d0 = scratch ; d0 = scratch
@ -260,6 +263,7 @@ pre_WaveGen:
; d4 = scratch ; d4 = scratch
; a2 = base note ; a2 = base note
.gen_noise .gen_noise
suba.l a6,a6
IFNE PRETRACKER_PARANOIA_MODE IFNE PRETRACKER_PARANOIA_MODE
tst.w pv_wg_curr_sample_len_w(a4) tst.w pv_wg_curr_sample_len_w(a4)
beq .wave_gen_tone_done beq .wave_gen_tone_done
@ -349,7 +353,7 @@ pre_WaveGen:
.gen_noise_innerloop .gen_noise_innerloop
move.b d1,(a0)+ move.b d1,(a0)+
cmpa.l pv_wg_curr_samend_ptr(a4),a0 cmp.l pv_wg_curr_samend_ptr(a4),a0
beq .wave_gen_tone_done beq .wave_gen_tone_done
adda.l a1,a5 adda.l a1,a5
@ -370,14 +374,14 @@ pre_WaveGen:
sub.l d4,d2 sub.l d4,d2
.noise_nonlinear_pitch .noise_nonlinear_pitch
cmpa.w #$1ff,a1 cmp.w #$1ff,a1
bgt.s .gen_noise_no_end_of_pitch_ramp bgt.s .gen_noise_no_end_of_pitch_ramp
moveq.l #0,d2 ; stop pitch ramping moveq.l #0,d2 ; stop pitch ramping
move.l d2,a5 move.l d2,a5
movea.w #$200,a1 movea.w #$200,a1
.gen_noise_no_end_of_pitch_ramp .gen_noise_no_end_of_pitch_ramp
.gen_noise_no_pitch_ramping .gen_noise_no_pitch_ramping
cmpa.w a5,a5 cmp.w a5,a5
beq.s .gen_noise_innerloop beq.s .gen_noise_innerloop
bra .gen_noise_outerloop bra .gen_noise_outerloop
@ -389,8 +393,6 @@ pre_WaveGen:
; a2 = base note ; a2 = base note
.no_noise .no_noise
moveq.l #0,d7
move.b pv_osc_buffers+owb_wave_length(a1),d7 ; get period
moveq.l #15,d5 moveq.l #15,d5
lsl.l d5,d7 lsl.l d5,d7
@ -535,7 +537,7 @@ pre_WaveGen:
moveq.l #0,d2 moveq.l #0,d2
moveq.l #0,d1 moveq.l #0,d1
.chordtone_done .chordtone_done
cmpa.l pv_wg_curr_samend_ptr(a4),a0 cmp.l pv_wg_curr_samend_ptr(a4),a0
bne.s .chordtoneloop bne.s .chordtoneloop
.wave_gen_tone_done .wave_gen_tone_done
@ -768,14 +770,14 @@ pre_WaveGen:
CLIPTO8BIT d7 CLIPTO8BIT d7
.filter_outputbyte .filter_outputbyte
move.b d7,(a0)+ move.b d7,(a0)+
cmpa.l a0,a1 cmp.l a0,a1
bne.s .filter_innerloop bne.s .filter_innerloop
.filterloop_end_test .filterloop_end_test
movem.w d3-d6,pv_wg_flt_taps(a4) movem.w d3-d6,pv_wg_flt_taps(a4)
movem.l (sp)+,d3-d5 movem.l (sp)+,d3-d5
cmpa.l pv_wg_curr_samend_ptr(a4),a0 cmp.l pv_wg_curr_samend_ptr(a4),a0
bhs.s .filter_done bhs.s .filter_done
move.l a6,d0 move.l a6,d0
bra .entry_to_filter_loop bra .entry_to_filter_loop
@ -809,7 +811,7 @@ pre_WaveGen:
moveq.l #0,d0 moveq.l #0,d0
move.b wi_vol_attack_b(a3),d0 move.b wi_vol_attack_b(a3),d0
bne.s .has_attack_volume bne.s .has_attack_volume
cmpi.b #$FF,wi_vol_sustain_b(a3) cmp.b #$ff,wi_vol_sustain_b(a3)
beq .vol_envelope_finished beq .vol_envelope_finished
; no attack but not full sustain -> go to delay ; no attack but not full sustain -> go to delay
;move.l #$100<<16,d3 ;move.l #$100<<16,d3
@ -836,7 +838,7 @@ pre_WaveGen:
lsl.l #4,d1 ; multiply speed by 16 lsl.l #4,d1 ; multiply speed by 16
.vol_no_fast .vol_no_fast
add.l d1,d3 ; increase volume add.l d1,d3 ; increase volume
cmpi.l #$FFFFFF,d3 cmp.l #$ffffff,d3
ble.s .vol_do_attack ; first step overshooting? ble.s .vol_do_attack ; first step overshooting?
.vol_skip_attack .vol_skip_attack
btst #3,wi_flags_b(a3) ; boost flag btst #3,wi_flags_b(a3) ; boost flag
@ -862,7 +864,7 @@ pre_WaveGen:
subq.w #1,d4 subq.w #1,d4
bmi .vol_envelope_finished bmi .vol_envelope_finished
add.l d1,d3 ; increase volume add.l d1,d3 ; increase volume
cmpi.l #$FFFFFF,d3 cmp.l #$ffffff,d3
ble.s .vol_attack_normal_loop ble.s .vol_attack_normal_loop
; ---------------------------------------- ; ----------------------------------------
@ -882,7 +884,7 @@ pre_WaveGen:
ELSE ELSE
lea 2(a0,d0.w),a1 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? 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 .vol_delay_normal_loop
move.b (a0),d0 move.b (a0),d0
IFNE 1 IFNE 1
@ -896,7 +898,7 @@ pre_WaveGen:
ENDC ENDC
move.b d0,(a0)+ move.b d0,(a0)+
cmpa.l a1,a0 cmp.l a1,a0
dbeq d4,.vol_delay_normal_loop dbeq d4,.vol_delay_normal_loop
bne .vol_envelope_finished bne .vol_envelope_finished
ENDC ENDC
@ -920,7 +922,7 @@ pre_WaveGen:
subq.w #1,d4 subq.w #1,d4
bmi .vol_envelope_finished bmi .vol_envelope_finished
add.l d1,d3 add.l d1,d3
cmpi.l #$FFFFFF,d3 cmp.l #$ffffff,d3
ble.s .vol_attack_boosted_loop ble.s .vol_attack_boosted_loop
; ---------------------------------------- ; ----------------------------------------
@ -941,7 +943,7 @@ pre_WaveGen:
add.b d0,d0 add.b d0,d0
CLIPTO8BITAFTERADD d0 CLIPTO8BITAFTERADD d0
ELSE ELSE
move.w #$FF,d3 ; FIXME I don't think that this is quite right. It should be $100 to boost by full volume 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 .vol_delay_boosted_loop
move.b (a0),d0 move.b (a0),d0
ext.w d0 ext.w d0
@ -951,7 +953,7 @@ pre_WaveGen:
ENDC ENDC
move.b d0,(a0)+ move.b d0,(a0)+
cmpa.l a1,a0 cmp.l a1,a0
dbeq d4,.vol_delay_boosted_loop dbeq d4,.vol_delay_boosted_loop
bne .vol_envelope_finished bne .vol_envelope_finished