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
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>
@ -101,7 +101,7 @@ 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
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".
@ -137,18 +137,33 @@ about 34 on average!).
Watch out for *Presto*, the [LightSpeedPlayer](https://github.com/arnaud-carre/LSPlayer) variant that should
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
- 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.
- 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 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.
- 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.
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.
- 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.
## Changelog
@ -168,9 +183,9 @@ solve this problem.
- Bugfix: Songend detection for back-jumps was broken since at least V1.1.
- Optimized some more wave selection code.
- 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.
- Drop-in replacement code size: 5732 bytes.
- Drop-in replacement code size: 5716 bytes.
### V1.x (unreleased)
- 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>
@ -96,7 +96,7 @@
; 18052 bytes down to 9023 bytes.
;
; 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".
;
@ -2478,7 +2478,7 @@ pre_PlayerTick:
rts
;--------------------------------------------------------------------
; table data currently about 446 bytes
; table data currently about 450 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
@ -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,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
;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
@ -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
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
dc.w $400,$200,$80,$64,$50,$40,$30,$20
dc.w 16,14,12,10,8,4,2,1
IFNE PRETRACKER_DUBIOUS_PITCH_SHIFT_FOR_DELAYED_TRACK
; -4,-3,-1,1,2,3,4,0

View File

@ -1,6 +1,6 @@
; 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)
; $0008 4: File offset to pattern data (PATT)
; $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_sqr_waves rs.b 128
owb_tri_waves rs.b 128
owb_wave_length rs.b 1
owb_SIZEOF rs.b 0
; ----------------------------------------

View File

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