Optimized pattern / song advance code. Prepared release 1.1.
This commit is contained in:
parent
b177277d40
commit
39d5e5e91e
33
README.md
33
README.md
@ -1,7 +1,7 @@
|
||||
# Raspberry Casket
|
||||
A fast and small open source Pretracker replayer
|
||||
|
||||
## Raspberry Casket Player V1.0 (26-Dec-2022)
|
||||
## Raspberry Casket Player V1.1 (28-Dec-2022)
|
||||
|
||||
Provided by Chris 'platon42' Hodges <chrisly@platon42.de>
|
||||
|
||||
@ -83,12 +83,15 @@ 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
|
||||
6374 bytes and goes down to ~4410 bytes (in isolation).
|
||||
6216 bytes and goes down to ~4348 bytes (in isolation).
|
||||
|
||||
So this means that the optimization is not just "on the outside".
|
||||
|
||||
### Timing
|
||||
|
||||
Sample generation is a bit faster (I guess around 10-15%), but most of the time is spent on muls operations, so this is the limiting factor.
|
||||
Raspberry Casket is about twice as fast as the old replayer for playback.
|
||||
|
||||
Unfortunately, the replayer is still pretty slow and has high
|
||||
jitter compared to other standard music replayers.
|
||||
|
||||
@ -103,24 +106,30 @@ solve this problem.
|
||||
### Known issues
|
||||
|
||||
- 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.
|
||||
- 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.
|
||||
- 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.
|
||||
- Pattern breaks with target row >= $7f will be ignored.
|
||||
- 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 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.
|
||||
|
||||
## Changelog
|
||||
|
||||
### V1.1 (unreleased)
|
||||
- Optimized base displacement by reordering variables
|
||||
- Further optimized ADSR code
|
||||
- Optimized wave loop code
|
||||
- Bake in this strange vibrato speed multiplication to precalculated vibrato value (where possible)
|
||||
- Various small optimizations
|
||||
- Store instrument number * 4 on loading to avoid using two adds every frame
|
||||
### V1.1 (28-Dec-22)
|
||||
- Optimized base displacement by reordering variables.
|
||||
- Further optimized ADSR code.
|
||||
- Optimized wave loop code.
|
||||
- Bake in this strange vibrato speed multiplication to precalculated vibrato value (where possible).
|
||||
- Various small optimizations.
|
||||
- Store instrument number * 4 on loading to avoid using two adds every frame.
|
||||
- Optimized speed/shuffle code. Idea of using xor turned out to make things too complicated for pattern breaks/jumps.
|
||||
- Rearranged code for more short branches.
|
||||
- Optimized track delay code further.
|
||||
- Drop-in replacement code size: 6304 bytes.
|
||||
- Optimized pattern / song advance code.
|
||||
- Maximum jitter now about one rasterline less, average about 0.5 rasterlines less (measurements, your mileage may vary).
|
||||
- Drop-in replacement code size: 6228 bytes.
|
||||
|
||||
### V1.0 (26-Dec-22)
|
||||
|
||||
|
Binary file not shown.
@ -1,5 +1,5 @@
|
||||
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.
|
||||
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.0).
|
||||
It has been assembled from src/drop_in_replacement.asm (version V1.1).
|
Binary file not shown.
@ -3,7 +3,7 @@ It features Pink's song Plastic Dove (from the Coda Intro).
|
||||
|
||||
Even though it features the full replayer code and tune,
|
||||
the replayer including my demo framework and the song only
|
||||
takes a mere 6560 bytes (shrinkled), which is even smaller
|
||||
takes a mere 6448 bytes (shrinkled), which is even smaller
|
||||
than the new streaming replayer used in Pink's new streaming
|
||||
player demonstrated (closed source) in
|
||||
|
||||
@ -11,7 +11,7 @@ https://www.pouet.net/prod.php?which=91551
|
||||
|
||||
which is 6860 bytes.
|
||||
|
||||
The Raspberry Casket replayer takes an average of 14
|
||||
The Raspberry Casket replayer takes an average of 13.5
|
||||
rasterlines while Pink's new streaming player takes
|
||||
only about 10 rasterlines.
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
;--------------------------------------------------------------------
|
||||
; Raspberry Casket Player V1.1beta (28-Dec-2022)
|
||||
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
; Raspberry Casket Player V1.1 (28-Dec-2022)
|
||||
; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
;
|
||||
; Provided by Chris 'platon42' Hodges <chrisly@platon42.de>
|
||||
;
|
||||
@ -87,15 +87,22 @@
|
||||
; 18052 bytes down to 9023 bytes.
|
||||
;
|
||||
; Raspberry Casket, depending on the features compiled in, is about
|
||||
; 6374 bytes and goes down to ~4410 bytes (in isolation).
|
||||
; 6216 bytes and goes down to ~4348 bytes (in isolation).
|
||||
;
|
||||
; So this means that the optimization is not just "on the outside".
|
||||
;
|
||||
; Timing
|
||||
; ~~~~~~
|
||||
; Sample generation is a bit faster (I guess around 10-15%), but most
|
||||
; of the time is spent on muls operations, so this is the limiting
|
||||
; factor.
|
||||
;
|
||||
; Raspberry Casket is about twice as fast as the old replayer for
|
||||
; playback.
|
||||
;
|
||||
; Unfortunately, the replayer is still pretty slow and has high
|
||||
; jitter compared to other standard music replayers.
|
||||
; This means it may take up to 33 raster lines (14-19 on average)
|
||||
; This means it may take up to 32 raster lines (13-18 on average)
|
||||
; which is significant more than a standard Protracker replayer
|
||||
; (the original one could take about 60 raster lines worst case and
|
||||
; about 34 on average!).
|
||||
@ -639,7 +646,7 @@ pre_FuncTable
|
||||
dc.l pre_PlayerInit-pre_FuncTable
|
||||
dc.l pre_PlayerTick-pre_FuncTable
|
||||
ENDC
|
||||
;dc.b '$VER: Raspberry Casket 1.0',0
|
||||
;dc.b '$VER: Raspberry Casket 1.1',0
|
||||
;even
|
||||
|
||||
IFNE PRETRACKER_COPPER_OUTPUT
|
||||
@ -2906,29 +2913,66 @@ pre_PlayerTick:
|
||||
; end of pattern loop
|
||||
|
||||
; ----------------------------------------
|
||||
; pattern advancing FIXME try to figure out all the cases
|
||||
; Pattern advancing and pattern break and jump handling. Song looping and song-end detection.
|
||||
.pattern_advancing
|
||||
subq.b #1,pv_pat_line_ticks_b(a4)
|
||||
bne .no_pattern_advance
|
||||
|
||||
; clear note delay info
|
||||
moveq.l #0,d1
|
||||
moveq.l #0,d0
|
||||
REPT NUM_CHANNELS
|
||||
move.b d1,pv_channeldata+pcd_note_delay_b+REPTN*pcd_SIZEOF(a4)
|
||||
move.b d0,pv_channeldata+pcd_note_delay_b+REPTN*pcd_SIZEOF(a4)
|
||||
ENDR
|
||||
|
||||
move.b sv_num_steps_b(a6),d1
|
||||
subq.b #1,d1
|
||||
move.b pv_next_pat_row_b(a4),d0
|
||||
blt.s .no_pattern_break
|
||||
cmp.b d0,d1
|
||||
bgt.s .has_legal_break_pos
|
||||
move.b d1,d0 ; limit to last step
|
||||
.has_legal_break_pos
|
||||
move.b d0,pv_pat_curr_row_b(a4)
|
||||
move.b sv_num_steps_b(a6),d1 ; number of steps in pattern
|
||||
|
||||
move.w sv_curr_pat_pos_w(a6),d3 ; go to next pattern pos
|
||||
addq.w #1,d3
|
||||
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.b pv_next_pat_row_b(a4),d2 ; $ff means no pattern break
|
||||
bmi.s .no_pattern_break
|
||||
st pv_next_pat_row_b(a4) ; processed break, set to $ff
|
||||
move.b d2,d0
|
||||
IFNE 0 ; PRETRACKER_BUGFIX_CODE ; currently disabled to keep old behaviour
|
||||
moveq.l #0,d2 ; clear mask
|
||||
ENDC
|
||||
cmp.b d1,d0
|
||||
blo.s .has_legal_break_pos
|
||||
move.b d1,d0 ; limit to last step
|
||||
subq.b #1,d0
|
||||
bra.s .has_legal_break_pos
|
||||
|
||||
.no_pattern_break
|
||||
cmp.b d1,d0
|
||||
blo.s .pattern_end_not_reached
|
||||
moveq.l #0,d0
|
||||
IFNE PRETRACKER_PARANOIA_MODE
|
||||
move.b pv_loop_pattern_b(a4),d0 ; keep same pattern rolling?
|
||||
bne.s .pattern_end_not_reached
|
||||
ENDC
|
||||
.has_legal_break_pos
|
||||
addq.w #1,d3 ; pattern break will increment song pos -- if there is no new pattern position
|
||||
|
||||
.pattern_end_not_reached
|
||||
move.b pv_next_pat_pos_b(a4),d4
|
||||
bmi.s .no_new_position ; has a new pattern position
|
||||
st pv_next_pat_pos_b(a4)
|
||||
IFNE PRETRACKER_SONG_END_DETECTION
|
||||
cmp.b d4,d3
|
||||
bgt.s .no_backjump
|
||||
st pv_songend_detected_b(a4) ; detect jumping back
|
||||
.no_backjump
|
||||
ENDC
|
||||
move.b d4,d3 ; load new position
|
||||
IFNE 0 ; PRETRACKER_BUGFIX_CODE ; currently disabled to keep old behaviour
|
||||
not.b d2
|
||||
and.b d2,d0 ; if we had NO pattern break, we will clear d0
|
||||
ELSE
|
||||
moveq.l #0,d0
|
||||
ENDC
|
||||
.no_new_position
|
||||
|
||||
cmp.w sv_pat_pos_len_w(a6),d3
|
||||
blt.s .no_restart_song
|
||||
@ -2937,87 +2981,15 @@ pre_PlayerTick:
|
||||
st pv_songend_detected_b(a4)
|
||||
ENDC
|
||||
.no_restart_song
|
||||
move.w d3,sv_curr_pat_pos_w(a6)
|
||||
|
||||
st pv_next_pat_row_b(a4) ; processed break, set to $ff
|
||||
|
||||
move.b pv_next_pat_pos_b(a4),d3
|
||||
bge.s .has_new_position ; has a new pattern position together with a break
|
||||
move.b d0,d2 ; backup pv_pat_curr_row_b
|
||||
cmp.b d0,d1
|
||||
ble.s .end_of_pattern_reached
|
||||
bra.s .done_pat_advance
|
||||
|
||||
.no_pattern_break
|
||||
move.b pv_next_pat_pos_b(a4),d3
|
||||
bge.s .has_new_position
|
||||
move.b pv_pat_curr_row_b(a4),d0
|
||||
move.b d0,d2
|
||||
cmp.b d1,d2
|
||||
blt.s .advancetonextpos
|
||||
|
||||
.end_of_pattern_reached
|
||||
clr.b pv_pat_curr_row_b(a4)
|
||||
IFNE PRETRACKER_PARANOIA_MODE
|
||||
move.b pv_loop_pattern_b(a4),d0 ; keep same pattern rolling?
|
||||
bne .done_pat_advance
|
||||
ENDC
|
||||
bra.s .advance_song_pos
|
||||
|
||||
.advancetonextpos
|
||||
addq.b #1,d2
|
||||
move.b sv_num_steps_b(a6),d1
|
||||
addq.b #1,d0
|
||||
cmp.b d2,d1
|
||||
bgt.s .dont_go_to_top_row
|
||||
moveq.l #0,d0
|
||||
.dont_go_to_top_row
|
||||
move.b d0,pv_pat_curr_row_b(a4)
|
||||
bra.s .done_pat_advance
|
||||
|
||||
.has_new_position
|
||||
clr.b pv_pat_curr_row_b(a4)
|
||||
IFNE PRETRACKER_PARANOIA_MODE
|
||||
move.b pv_loop_pattern_b(a4),d0
|
||||
bne .no_restart_song_after_jump
|
||||
ENDC
|
||||
|
||||
cmp.w sv_pat_pos_len_w(a6),d3
|
||||
blt.s .set_song_pos2
|
||||
move.w sv_pat_restart_pos_w(a6),d3
|
||||
IFNE PRETRACKER_SONG_END_DETECTION
|
||||
st pv_songend_detected_b(a4)
|
||||
ENDC
|
||||
.set_song_pos2
|
||||
move.w d3,sv_curr_pat_pos_w(a6)
|
||||
; enters with d0 = 0
|
||||
.no_restart_song_after_jump
|
||||
st pv_next_pat_pos_b(a4) ; processed jump, set to $ff
|
||||
|
||||
subq.b #1,d2
|
||||
bhi.s .done_pat_advance
|
||||
clr.b pv_pat_curr_row_b(a4)
|
||||
tst.b d0
|
||||
bne.s .done_pat_advance
|
||||
|
||||
.advance_song_pos
|
||||
move.w sv_curr_pat_pos_w(a6),d0
|
||||
addq.w #1,d0
|
||||
cmp.w sv_pat_pos_len_w(a6),d0
|
||||
blt.s .set_song_pos
|
||||
move.w sv_pat_restart_pos_w(a6),d0
|
||||
IFNE PRETRACKER_SONG_END_DETECTION
|
||||
st pv_songend_detected_b(a4)
|
||||
ENDC
|
||||
.set_song_pos
|
||||
move.w d0,sv_curr_pat_pos_w(a6)
|
||||
.done_pat_advance
|
||||
move.b pv_pat_speed_even_b(a4),d0
|
||||
btst #0,pv_pat_curr_row_b(a4)
|
||||
beq.s .set_speed_even
|
||||
move.b pv_pat_speed_odd_b(a4),d0
|
||||
move.b pv_pat_speed_even_b(a4),d1
|
||||
lsr.b #1,d0
|
||||
bcc.s .set_speed_even
|
||||
move.b pv_pat_speed_odd_b(a4),d1
|
||||
.set_speed_even
|
||||
move.b d0,pv_pat_line_ticks_b(a4)
|
||||
move.b d1,pv_pat_line_ticks_b(a4)
|
||||
.no_pattern_advance
|
||||
|
||||
; ----------------------------------------
|
||||
|
Loading…
Reference in New Issue
Block a user