Skip to content

Commit 4d9b7e4

Browse files
committed
NSS: add new opcodes for a more compact stream representation
Three new passes and their associated opcode are implemented: - New WAIT_LAST opcode to wait the same amount as previous WAIT (saves 1 byte per wait) - New opcode to play a NOTE_AND_WAIT_LAST (saves 1 byte per play/wait_last) - Replace sequence of CALL with a CALL_TABLE and a offset table (this saves 2 bytes per additional call to the same pattern)
1 parent 39ac72f commit 4d9b7e4

File tree

7 files changed

+400
-49
lines changed

7 files changed

+400
-49
lines changed

.github/workflows/build-and-publish.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ jobs:
6868

6969
macos:
7070
name: "macOS build"
71-
runs-on: macos-13
71+
runs-on: macos-15
7272
env:
7373
PREFIX: "/usr/local"
7474
PY3PATH: "/usr/local/opt/python3/bin"

.github/workflows/build-tests.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ jobs:
6868

6969
macos:
7070
name: "macOS build"
71-
runs-on: macos-13
71+
runs-on: macos-15
7272
env:
7373
PREFIX: "/usr/local"
7474
PY3PATH: "/usr/local/opt/python3/bin"

nullsound/nss-adpcm-a.s

+13-1
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,6 @@ adpcm_a_configure_vol:
445445
;;; ADPCM_A_ON
446446
;;; Start sound playback on the current ADPCM-A channel
447447
;;; ------
448-
;;; [ hl ]: ADPCM-A channel [0..5]
449448
adpcm_a_on::
450449
;; delay the start via the trigger FX?
451450
bit BIT_TRIGGER_ACTION_DELAY, TRIGGER_ACTION(ix)
@@ -469,6 +468,19 @@ _a_on_end:
469468
ret
470469

471470

471+
;;; ADPCM_A_ON_AND_WAIT
472+
;;; Start sound playback on the current ADPCM-A channel and
473+
;;; immediately wait as many rows as the last wait
474+
;;; ------
475+
adpcm_a_on_and_wait::
476+
;; process a regular note opcode
477+
call adpcm_a_on
478+
479+
;; wait rows
480+
call wait_last_rows
481+
ret
482+
483+
472484
;;; Release the note on a ADPCM-A channel and update the pipeline state
473485
;;; ------
474486
adpcm_a_stop_playback:

nullsound/nss-fm.s

+14
Original file line numberDiff line numberDiff line change
@@ -1083,6 +1083,20 @@ _fm_note_on_end:
10831083
ret
10841084

10851085

1086+
;;; FM_NOTE_ON_AND_WAIT
1087+
;;; Emit a specific note (frequency) on an FM channel and
1088+
;;; immediately wait as many rows as the last wait
1089+
;;; ------
1090+
;;; [ hl ]: note (0xAB: A=octave B=semitone)
1091+
fm_note_on_and_wait::
1092+
;; process a regular note opcode
1093+
call fm_note_on
1094+
1095+
;; wait rows
1096+
call wait_last_rows
1097+
ret
1098+
1099+
10861100
;;; Release the note on an FM channel and update the pipeline state
10871101
;;; ------
10881102
fm_stop_playback:

nullsound/nss-ssg.s

+14
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,20 @@ _ssg_note_on_end:
883883
ret
884884

885885

886+
;;; SSG_NOTE_ON_AND_WAIT
887+
;;; Emit a specific note (frequency) on a SSG channel and
888+
;;; immediately wait as many rows as the last wait
889+
;;; ------
890+
;;; [ hl ]: note (0xAB: A=octave B=semitone)
891+
ssg_note_on_and_wait::
892+
;; process a regular note opcode
893+
call ssg_note_on
894+
895+
;; wait rows
896+
call wait_last_rows
897+
ret
898+
899+
886900
;;; SSG_ENV_PERIOD
887901
;;; Set the period of the SSG envelope generator
888902
;;; ------

nullsound/stream.s

+142-5
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
.equ CH_STREAM_SAVED, (state_ch_stream_saved_pos-state_ch_stream)
2828
.equ CH_STREAM_START, (state_ch_stream_start-state_ch_stream)
2929
.equ CH_STREAM_POS, (state_ch_stream_pos-state_ch_stream)
30+
.equ CH_STREAM_ENTRIES, (state_ch_stream_entries-state_ch_stream)
3031
.equ CH_STREAM_SIZE, (state_ch_stream_end-state_ch_stream)
3132
.equ NB_YM2610_CHANNELS, 14
3233

@@ -75,6 +76,13 @@ state_ch_ctx_switch:: .blkb NB_YM2610_CHANNELS
7576
;;; the NSS data gets a dedicated wait state
7677
state_ch_wait_rows:: .blkb NB_YM2610_CHANNELS
7778

79+
;;; per-channel wait opcode cache
80+
;;; ---
81+
;;; Wait value used by the last wait opcode.
82+
;;; When multiple streams are used, each YM2610 channel used in
83+
;;; the NSS data gets a dedicated wait state
84+
state_ch_wait_op_val:: .blkb NB_YM2610_CHANNELS
85+
7886
;;; per-channel playback state
7987
;;; ---
8088
;;; Keep track of positional information for streams.
@@ -87,15 +95,24 @@ state_ch_stream:
8795
state_ch_stream_saved_pos:: .blkb 2
8896
state_ch_stream_start:: .blkb 2
8997
state_ch_stream_pos:: .blkb 2
98+
state_ch_stream_entries:: .blkb 1
9099
state_ch_stream_end:
91100
.blkb CH_STREAM_SIZE*(NB_YM2610_CHANNELS-1)
92101

93102
;;; addresses/indices that points to state of the currently processed stream
94103
state_current_ch_ctx:: .blkb 2
95104
state_current_ch_wait_rows:: .blkb 2
105+
state_current_ch_wait_op_val:: .blkb 2
96106
state_current_ch_stream:: .blkb 2
97107
state_stream_idx:: .blkb 1
98108

109+
;;; generic function pointer for current NSS processing function
110+
state_nss_process::
111+
.blkb 1 ; jp
112+
state_nss_process_func::
113+
.blkb 2 ; func offset in ROM
114+
115+
99116
;; FIXME: temporary padding to ensures the next data sticks into
100117
;; a single 256 byte boundary to make 16bit arithmetic faster
101118
.blkb 70
@@ -109,6 +126,8 @@ init_stream_state_tracker::
109126
ld (state_stream_in_use), a
110127
ld bc, #0
111128
ld (state_stream_instruments), bc
129+
ld a, #0xc3 ; jp
130+
ld (state_nss_process), a
112131
;; init nss subsystems that may get called prior to playing music
113132
call init_nss_fm_state_tracker
114133
ret
@@ -151,6 +170,8 @@ process_streams_opcodes::
151170
ld (state_stream_idx), a
152171
ld bc, #state_ch_wait_rows
153172
ld (state_current_ch_wait_rows), bc
173+
ld bc, #state_ch_wait_op_val
174+
ld (state_current_ch_wait_op_val), bc
154175
ld bc, #state_ch_ctx_switch
155176
ld (state_current_ch_ctx), bc
156177
ld bc, #state_ch_stream
@@ -175,7 +196,7 @@ _loop_chs:
175196
ld l, CH_STREAM_POS(iy)
176197
ld h, CH_STREAM_POS+1(iy)
177198
_loop_opcode:
178-
call process_nss_opcode
199+
call state_nss_process
179200
or a
180201
jp nz, _loop_opcode
181202
;; no more opcodes can be processed, save stream's new pos
@@ -193,6 +214,9 @@ _post_ch_process:
193214
ld hl, (state_current_ch_wait_rows)
194215
inc hl
195216
ld (state_current_ch_wait_rows), hl
217+
ld hl, (state_current_ch_wait_op_val)
218+
inc hl
219+
ld (state_current_ch_wait_op_val), hl
196220
ld hl, (state_current_ch_ctx)
197221
inc hl
198222
ld (state_current_ch_ctx), hl
@@ -397,6 +421,10 @@ stream_play_multi::
397421
push iy
398422
pop hl
399423

424+
;; setup the generic NSS processing function
425+
ld bc, #process_nss_opcode
426+
ld (state_nss_process_func), bc
427+
400428
;; init streams state
401429
ld iy, #state_ch_stream
402430
ld de, #CH_STREAM_SIZE
@@ -460,13 +488,13 @@ nss_opcodes:
460488
.nss_op nss_jmp
461489
.nss_op nss_end
462490
.nss_op timer_tempo
463-
.nss_op wait_rows
491+
.nss_op wait_n_rows
464492
.nss_op nss_call
465493
.nss_op nss_ret
466494
.nss_op nss_nop
467495
.nss_op row_speed
468496
.nss_op row_groove
469-
.nss_op nss_nop2
497+
.nss_op wait_last_rows
470498
.nss_op adpcm_b_instrument
471499
.nss_op adpcm_b_note_on
472500
.nss_op adpcm_b_note_off
@@ -533,6 +561,10 @@ nss_opcodes:
533561
.nss_op adpcm_a_pan
534562
.nss_op adpcm_b_pan
535563
.nss_op adpcm_b_vibrato
564+
.nss_op nss_call_table
565+
.nss_op fm_note_on_and_wait
566+
.nss_op ssg_note_on_and_wait
567+
.nss_op adpcm_a_on_and_wait
536568

537569

538570

@@ -630,16 +662,19 @@ nss_end::
630662
ret
631663

632664

633-
;;; WAIT_ROWS
665+
;;; WAIT_N_ROWS
634666
;;; Suspend stream playback, resume after a number of rows
635667
;;; worth of time has passed (Timer B interrupts * speed).
636668
;;; ------
637669
;;; [hl]: number of interrupts until playback resumes
638-
wait_rows::
670+
wait_n_rows::
639671
push bc
640672
;; how many interrupts to wait for before moving on
641673
ld a, (hl)
642674
inc hl
675+
;; recall this wait value for this channel
676+
ld bc, (state_current_ch_wait_op_val)
677+
ld (bc), a
643678
;; register the wait for this channel
644679
ld bc, (state_current_ch_wait_rows)
645680
ld (bc), a
@@ -654,6 +689,22 @@ _post_wait_rows:
654689
ret
655690

656691

692+
;;; WAIT_LAST_ROWS
693+
;;; Suspend stream playback, resume after a number of rows
694+
;;; worth of time has passed (same as the last wait_n_rows)
695+
;;; ------
696+
wait_last_rows::
697+
push bc
698+
;; last wait for this channel
699+
ld bc, (state_current_ch_wait_op_val)
700+
ld a, (bc)
701+
;; register the wait for this channel
702+
ld bc, (state_current_ch_wait_rows)
703+
ld (bc), a
704+
705+
jp _post_wait_rows
706+
707+
657708
;;; NSS_CALL
658709
;;; Continue playback to a new position in the stream
659710
;;; Recall the current position so that a NSS_RET opcode
@@ -687,6 +738,82 @@ nss_call::
687738
ret
688739

689740

741+
;;; NSS_CALL_TABLE
742+
;;; Set up a series of calls to different locations in the stream
743+
;;; ------
744+
;;; [ hl ]: number of calls
745+
nss_call_table::
746+
;; bc: number of calls
747+
ld a, (hl)
748+
inc hl
749+
750+
;; recall the number of entries in the call table
751+
ld iy, (state_current_ch_stream)
752+
ld CH_STREAM_ENTRIES(iy), a
753+
754+
push bc
755+
ld bc, #process_table_entry
756+
ld (state_nss_process_func), bc
757+
pop bc
758+
759+
ld a, #1
760+
ret
761+
762+
763+
;;; Continue playback to a new position in the stream
764+
;;; Recall the current position so that a NSS_RET opcode
765+
;;; continues execution from there.
766+
;;; Note: no CALL entry can be processed again before a NSS_RET
767+
;;; ------
768+
;;; [ hl ]: pattern offset in the entry table
769+
process_table_entry::
770+
push bc
771+
772+
;; a: entry
773+
ld a, (hl)
774+
inc hl
775+
776+
ld iy, (state_current_ch_stream)
777+
778+
;; save current stream pos
779+
ld CH_STREAM_SAVED(iy), l
780+
ld CH_STREAM_SAVED+1(iy), h
781+
782+
;; hl: start of stream
783+
ld l, CH_STREAM_START(iy)
784+
ld h, CH_STREAM_START+1(iy)
785+
786+
;; hl: offset in entry table
787+
ld b, #0xff
788+
ld c, a
789+
add hl, bc
790+
add hl, bc
791+
792+
;; bc: pattern offset
793+
ld c, (hl)
794+
inc hl
795+
ld b, (hl)
796+
797+
;; hl: start of stream
798+
ld l, CH_STREAM_START(iy)
799+
ld h, CH_STREAM_START+1(iy)
800+
801+
;; hl: new pos (call offset)
802+
add hl, bc
803+
ld CH_STREAM_POS(iy), l
804+
ld CH_STREAM_POS+1(iy), h
805+
806+
;; record that one call entry has been processed
807+
dec CH_STREAM_ENTRIES(iy)
808+
809+
ld bc, #process_nss_opcode
810+
ld (state_nss_process_func), bc
811+
812+
pop bc
813+
ld a, #1
814+
ret
815+
816+
690817
;;; NSS_RET
691818
;;; Continue playback past the previous NSS_CALL statement
692819
;;; ------
@@ -699,6 +826,16 @@ nss_ret::
699826
ld CH_STREAM_POS(iy), l
700827
ld CH_STREAM_POS+1(iy), h
701828

829+
push bc
830+
ld bc, #process_nss_opcode
831+
xor a
832+
cp CH_STREAM_ENTRIES(iy)
833+
jr z, _ret_set_process
834+
ld bc, #process_table_entry
835+
_ret_set_process:
836+
ld (state_nss_process_func), bc
837+
pop bc
838+
702839
ld a, #1
703840
ret
704841

0 commit comments

Comments
 (0)