Skip to content

Commit f282174

Browse files
committed
nullsound: big refactor and new pipeline processing
This commit holds a massive refactoring of the FM and SSG processing that is hapenning at every step. Now every channel has a fixed sound pipeline where every NSS opcode records actions to perform for a row, and the processing of those actions and FX takes place at every step. SSG channel has its macro processing reworked. Now every register can be updated at every step of the macro definition, and loop support has been added. This is a breaking commit that requires recompiling the NSS instruments and streams. The user API stays the same.
1 parent dad1c17 commit f282174

14 files changed

+1534
-1806
lines changed

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

+3-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ jobs:
8787
run: ./.github/scripts/build.sh
8888

8989
- name: Install dependencies for ngdevkit-examples
90-
run: brew install pyyaml ngdevkit-gngeo imagemagick sox glew sdl2 sdl2_image
90+
run: |
91+
brew install ngdevkit-gngeo imagemagick sox glew sdl2 sdl2_image
92+
$(brew --prefix python)/libexec/bin/pip install pyyaml --break-system-packages
9193
9294
- name: Test by compiling ngdevkit-examples
9395
run: ./.github/scripts/test.sh

.github/workflows/build-tests.yaml

+3-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ jobs:
8787
run: ./.github/scripts/build.sh
8888

8989
- name: Install dependencies for ngdevkit-examples
90-
run: brew install pyyaml ngdevkit-gngeo imagemagick sox glew sdl2 sdl2_image
90+
run: |
91+
brew install ngdevkit-gngeo imagemagick sox glew sdl2 sdl2_image
92+
$(brew --prefix python)/libexec/bin/pip install pyyaml --break-system-packages
9193
9294
- name: Test by compiling ngdevkit-examples
9395
run: ./.github/scripts/test.sh

nullsound/Makefile.in

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ all: nullsound.lib linkcheck.map
1919
-include ../Makefile.config
2020

2121
INCLUDE_FILES=helpers ports ym2610
22-
OBJS=entrypoint bios-commands adpcm ym2610 stream timer nss-fm nss-adpcm nss-ssg fx-vibrato fx-slide volume
22+
OBJS=entrypoint bios-commands adpcm ym2610 stream timer nss-fm nss-adpcm nss-ssg fx-vibrato fx-slide fx-vol-slide volume
2323
LIB=nullsound.lib
2424

2525
VERSION=@version@

nullsound/buffers.s

+28-7
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,33 @@ ssg_semitone_distance::
6161
.db 0x07, 0x07, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x04, 0, 0, 0
6262
.db 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0, 0, 0
6363

64-
;;; Sine precalc
64+
;;; Convert note flat representation to <octave,semitone> representation
6565
;;; ------
66-
;;; a 64 bytes 2*Pi sign precalc encoded as 3-bit magnitude + 1-bit sign
67-
;;; This is used by the vibrato effect
66+
;;; Precalc for 8 octaves
67+
.bndry 128
68+
note_to_octave_semitone::
69+
.db 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b
70+
.db 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b
71+
.db 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b
72+
.db 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b
73+
.db 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b
74+
.db 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b
75+
.db 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b
76+
.db 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b
77+
78+
;;; fixed-point sine precalc
79+
;;; ------
80+
;;; a 64 entries (128bytes) signed fixed point precalc of sin(x) for x in [0..2*pi],
81+
;;; encoded as [-1.0..1.0] as [s..iffffffff....]. This serves as a base increment
82+
;;; for vibrato displacement from 1..16, which yields a 9bits fixed point for
83+
;;; displacement of the current NSS note
84+
.bndry 128
6885
sine::
69-
.db 0, 0, 9, 10, 11, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 15
70-
.db 15, 15, 15, 15, 15, 15, 14, 14, 13, 13, 12, 11, 11, 10, 9, 0
71-
.db 0, 0, 1, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 7, 7, 7
72-
.db 7, 7, 7, 7, 7, 7, 6, 6, 5, 5, 4, 3, 3, 2, 1, 0
86+
.dw 0x0000, 0x0190, 0x0310, 0x04a0, 0x0610, 0x0780, 0x08e0, 0x0a20
87+
.dw 0x0b50, 0x0c50, 0x0d40, 0x0e10, 0x0ec0, 0x0f40, 0x0fb0, 0x0fe0
88+
.dw 0x1000, 0x0fe0, 0x0fb0, 0x0f40, 0x0ec0, 0x0e10, 0x0d40, 0x0c50
89+
.dw 0x0b50, 0x0a20, 0x08e0, 0x0780, 0x0610, 0x04a0, 0x0310, 0x0190
90+
.dw 0x8000, 0x8190, 0x8310, 0x84a0, 0x8610, 0x8780, 0x88e0, 0x8a20
91+
.dw 0x8b50, 0x8c50, 0x8d40, 0x8e10, 0x8ec0, 0x8f40, 0x8fb0, 0x8fe0
92+
.dw 0x9000, 0x8fe0, 0x8fb0, 0x8f40, 0x8ec0, 0x8e10, 0x8d40, 0x8c50
93+
.dw 0x8b50, 0x8a20, 0x88e0, 0x8780, 0x8610, 0x84a0, 0x8310, 0x8190

nullsound/fx-slide.s

+84-94
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,20 @@
2727
.area CODE
2828

2929

30-
;;; Enable slide effect for the current SSG channel
30+
;;; Enable slide effect for the current channel
3131
;;; ------
32-
;;; ix : FM state for channel
32+
;;; ix : state for channel
3333
;;; a : slide direction: 0 == up, 1 == down
3434
;;; [ hl ]: speed (4bits) and depth (4bits)
3535
slide_init::
36+
push bc
37+
push de
38+
3639
;; b: slide direction (from a)
3740
ld b, a
3841

39-
;; slide fx on
40-
ld a, FX(ix)
41-
set 1, a
42-
ld FX(ix), a
42+
;; enable slide FX
43+
set BIT_FX_SLIDE, FX(ix)
4344

4445
;; a: speed
4546
ld a, (hl)
@@ -48,6 +49,7 @@ slide_init::
4849
rra
4950
rra
5051
and #0xf
52+
5153
;; de: inc16 = speed / 8
5254
ld d, a
5355
ld e, #0
@@ -85,67 +87,86 @@ _post_depth_negate:
8587

8688
inc hl
8789

90+
;; init semitone position, fixed point representation
91+
ld a, #0
92+
ld SLIDE_POS16(ix), a
93+
ld SLIDE_POS16+1(ix), a
94+
95+
;; save target depth
96+
ld a, SLIDE_DEPTH(ix)
97+
ld SLIDE_END(ix), a
98+
99+
pop de
100+
pop bc
101+
88102
ret
89103

90104

91-
;;; Setup the end semitone for the currently configured slide
105+
;;; Enable slide effect for the current channel
92106
;;; ------
93-
;;; ix : state for channel
94-
;;; e : semitone to configure increments from
95-
slide_setup_increments::
107+
;;; ix : state for channel
108+
;;; a : slide direction: 0 == up, 1 == down
109+
;;; [ hl ]: speed (4bits) and depth (4bits)
110+
slide_pitch_init::
96111
push bc
97112
push de
98113

99-
;; init semitone position, fixed point representation
100-
ld SLIDE_POS16+1(ix), e
101-
ld a, #0
102-
ld SLIDE_POS16(ix), a
103-
104-
;; d: depth, negative if slide goes down
105-
ld d, SLIDE_DEPTH(ix)
114+
;; b: slide direction (from a)
115+
ld b, a
106116

107-
;; c: note adjust. slide up: 4, slide down: -4
108-
ld c, #4
109-
bit 7, d
110-
jr z, _post_inc_adjust
111-
ld c, #-4
112-
_post_inc_adjust:
117+
;; enable slide FX
118+
set BIT_FX_SLIDE, FX(ix)
113119

114-
;; b: current octave
115-
ld a, SLIDE_POS16+1(ix)
116-
and #0xf0
117-
ld b, a
120+
;; a: speed
121+
ld a, (hl)
118122

119-
;; e: target octave
120-
ld a, SLIDE_POS16+1(ix)
121-
add d
122-
and #0xf0
123+
;; de: inc16 = speed / 32
124+
ld d, a
125+
ld e, #0
126+
srl d
127+
rr e
128+
srl d
129+
rr e
130+
srl d
131+
rr e
132+
srl d
133+
rr e
134+
srl d
135+
rr e
136+
;; down: negate inc16
137+
bit 0, b
138+
jr z, _post_inc16_negate2
139+
ld a, #0
140+
sub e
123141
ld e, a
124-
125-
;; if current and target octave differ, skip missing steps in the depth
126-
ld a, b
127-
cp e
128-
jr z, _post_depth_adjust
129-
ld a, d
130-
add c ; slide up: 4, slide down: -4
142+
ld a, #0
143+
sbc d
131144
ld d, a
132-
_post_depth_adjust:
145+
_post_inc16_negate2:
146+
ld SLIDE_INC16(ix), e
147+
ld SLIDE_INC16+1(ix), d
133148

134-
;; a: current octave/note
135-
ld a, SLIDE_POS16+1(ix)
149+
;; depth
150+
ld a, #127
151+
;; down: negate depth
152+
;; we also need to go one seminote below, to account for the
153+
;; fractional parts of the slide.
154+
bit 0, b
155+
jr z, _post_depth_negate2
156+
neg
157+
dec a
158+
_post_depth_negate2:
159+
ld SLIDE_DEPTH(ix), a
136160

137-
;; d: target octave/note
138-
add d
139-
ld d, a
161+
inc hl
140162

141-
;; when target note is a missing step, adjust to the next note
142-
and #0xf
143-
cp #12
144-
ld a, d
145-
jr c, _post_target_note
146-
add c ; slide up: 4, slide down: -4
147-
_post_target_note:
148-
;; save target octave/note
163+
;; init semitone position, fixed point representation
164+
ld a, #0
165+
ld SLIDE_POS16(ix), a
166+
ld SLIDE_POS16+1(ix), a
167+
168+
;; save target depth
169+
ld a, SLIDE_DEPTH(ix)
149170
ld SLIDE_END(ix), a
150171

151172
pop de
@@ -211,20 +232,17 @@ _post_sign_chk:
211232
ret
212233

213234

214-
;;; Increment current fixed point position in the semitone table and
215-
;;; stop effects when the target position is reached
235+
;;; Increment current fixed point displacement and
236+
;;; stop effects when the target displacement is reached
216237
;;; ------
217238
;;; IN:
218239
;;; ix : state for channel
219240
;;; c : slide direction: 0 == up, 1 == down
220241
;;; OUT:
221242
;;; a : whether effect is finished (0: finished, 1: still running)
222-
;;; d : when effect is finished, target semitone
243+
;;; d : when effect is finished, target displacement
244+
;;; de modified
223245
eval_slide_step:
224-
;; ix: state for the current channel
225-
push hl
226-
pop ix
227-
228246
;; c: 0 slide up, 1 slide down
229247
ld a, SLIDE_INC16+1(ix)
230248
rlc a
@@ -234,7 +252,7 @@ eval_slide_step:
234252
;; INC16 increment is 1/8 semitone (0x0020) * depth
235253
;; negative for slide down
236254

237-
;; add/sub increment to the current semitone POS16
255+
;; add/sub increment to the current semitone displacement POS16
238256
;; e: fractional part
239257
ld a, SLIDE_INC16(ix)
240258
add SLIDE_POS16(ix)
@@ -243,23 +261,8 @@ eval_slide_step:
243261
;; d: integer part
244262
ld a, SLIDE_INC16+1(ix)
245263
adc SLIDE_POS16+1(ix)
264+
ld SLIDE_POS16+1(ix), a
246265
ld d, a
247-
;; do we need to skip missing steps in the note table
248-
and #0xf
249-
cp #0xc
250-
jr c, _post_skip
251-
ld a, d
252-
;; slide direction
253-
bit 0, c
254-
jr z, _slide_dist_up
255-
add #-4
256-
ld d, a
257-
jr _post_skip
258-
_slide_dist_up:
259-
add #4
260-
ld d, a
261-
_post_skip:
262-
ld SLIDE_POS16+1(ix), d
263266

264267
;; have we reached the end of the slide?
265268
;; slide up: continue if cur < end
@@ -276,31 +279,18 @@ _slide_cp:
276279
jr c, _slide_intermediate
277280

278281
;; slide is finished, stop effect
279-
ld (ix), #0
282+
res BIT_FX_SLIDE, FX(ix)
280283

281-
;; d: clamp the last slide pos to the target semitone
284+
;; d: clamp the last slide pos to the target displacement
282285
ld d, SLIDE_END(ix)
283286

284287
;; for slide down, we finish one note below the real target to play
285-
;; all ticks with fractional parts. Adjust the end note back if needed
288+
;; all ticks with fractional parts. Adjust the end displacement back if needed
286289
bit 0, c
287290
jr z, _post_adjust
288-
ld a, d
289-
and #0xf
290-
cp #11
291-
jr c, _neg_inc_adjust
292-
;; adjust to next note (after the missing steps in the note table)
293-
ld a, d
294-
add #5
295-
ld d, a
296-
jr _post_adjust
297-
_neg_inc_adjust:
298-
;; adjust to next note
299-
ld a, d
300-
inc a
301-
ld d, a
291+
inc d
302292
_post_adjust:
303-
;; effect is finished, new semitone in d
293+
;; effect is finished, new displacement in d
304294
ld a, #0
305295
ret
306296

0 commit comments

Comments
 (0)