Skip to content

Commit 318408b

Browse files
committed
nullsound: refactor volume FX pipeline
1 parent d7b1266 commit 318408b

File tree

6 files changed

+340
-130
lines changed

6 files changed

+340
-130
lines changed

nullsound/fx-vol-slide.s

Lines changed: 230 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
;;;
22
;;; nullsound - modular sound driver
3-
;;; Copyright (c) 2024 Damien Ciabrini
3+
;;; Copyright (c) 2024-2025 Damien Ciabrini
44
;;; This file is part of ngdevkit
55
;;;
66
;;; ngdevkit is free software: you can redistribute it and/or modify
@@ -23,66 +23,252 @@
2323

2424
.include "ym2610.inc"
2525
.include "struct-fx.inc"
26+
.include "pipeline.inc"
2627

2728
.area CODE
2829

2930

30-
;;; Enable volume slide effect for the current channel
31-
;;; TODO: handle slide up
31+
;;; Setup the fixed-point increment for the slide
3232
;;; ------
33-
;;; ix : state for channel
34-
;;; a : slide direction: 0 == up, 1 == down
35-
;;; bc : volume increment
36-
;;; d : max volume
37-
;;; [ hl ]: speed (4bits)
38-
;;; [ hl modified ]
39-
vol_slide_init::
40-
;; a: speed
41-
ld a, (hl)
42-
inc hl
33+
;;; c : increment size (increment = 1/2^c)
34+
;;; e : speed (increments)
35+
;;; bc, de modified
36+
vol_slide_init_increment::
37+
38+
;; de: inc16 = speed / 2^c
39+
ld d, e
40+
ld e, #0
41+
__vol_slide_divide:
42+
srl d
43+
rr e
44+
dec c
45+
jr nz, __vol_slide_divide
46+
47+
;; store absolute speed (no direction)
48+
ld VOL_SLIDE_INC16(ix), e
49+
ld VOL_SLIDE_INC16+1(ix), d
4350

44-
;; 0 speed means 'disable FX'
45-
cp #0
46-
jr nz, _setup_vol_slide
47-
res BIT_FX_VOL_SLIDE, FX(ix)
4851
ret
49-
_setup_vol_slide:
50-
;; setup FX
51-
ld a, #0x40
52-
ld VOL_SLIDE_INC16(ix), c
53-
ld VOL_SLIDE_INC16+1(ix), b
54-
ld a, #0
55-
ld VOL_SLIDE_POS16(ix), a
56-
ld VOL_SLIDE_POS16+1(ix), a
57-
ld a, #15
58-
ld VOL_SLIDE_END(ix), d
5952

60-
;; enable FX
61-
set BIT_FX_VOL_SLIDE, FX(ix)
53+
54+
;;; Initialize the source volume for the slide
55+
;;; ------
56+
;;; ix : state for channel
57+
;;; b : current volume
58+
vol_slide_init_source::
59+
;; init slide position if no volume slide FX is ongoing
60+
bit BIT_FX_VOL_SLIDE, FX(ix)
61+
jr nz, _vol_post_init_slide
62+
ld VOL_SLIDE_POS16(ix), #0
63+
ld VOL_SLIDE_POS16+1(ix), b
64+
_vol_post_init_slide:
65+
ret
66+
67+
68+
;;; Initialize a target volume for the slide
69+
;;; ------
70+
;;; ix : state for channel
71+
;;; b : current volume
72+
;;; d : target offset (signed)
73+
vol_slide_init_target::
74+
;; init slide direction
75+
res BIT_SLIDE_DIRECTION, VOL_SLIDE_CFG(ix)
76+
77+
;; slide target is the current position + new displacement
78+
;; a: target note
79+
ld a, b
80+
add d
81+
;; down: we also need to go one seminote below, to account
82+
;; for the fractional parts of the slide.
83+
bit 7, d
84+
jr z, _post_neg_vol_slide
85+
set BIT_SLIDE_DIRECTION, VOL_SLIDE_CFG(ix)
86+
dec a
87+
_post_neg_vol_slide:
88+
ld VOL_SLIDE_END(ix), a
6289

6390
ret
6491

6592

66-
;;; Update the volume slide for the current channel by one increment
93+
;;; Increment current fixed point displacement and
94+
;;; stop effects when the target displacement is reached
6795
;;; ------
6896
;;; IN:
69-
;;; ix: state for the current channel
70-
eval_vol_slide_step::
71-
push hl
72-
push bc
73-
ld l, VOL_SLIDE_POS16(ix)
74-
ld h, VOL_SLIDE_POS16+1(ix)
97+
;;; ix : state for channel
98+
;;; bc, de, hl modified
99+
eval_vol_slide_step:
100+
;; bc: increment
75101
ld c, VOL_SLIDE_INC16(ix)
76102
ld b, VOL_SLIDE_INC16+1(ix)
103+
;; hl: decimal note (FX copy)
104+
ld l, VOL_SLIDE_POS16(ix)
105+
ld h, VOL_SLIDE_POS16+1(ix)
106+
107+
;; c: 0 slide up, 1 slide down
108+
bit BIT_SLIDE_DIRECTION, VOL_SLIDE_CFG(ix)
109+
jr nz, _vol_slide_sub_inc
110+
111+
_vol_slide_add_inc:
112+
;; de: pos16+inc16
77113
add hl, bc
78-
ld a, h
79-
cp VOL_SLIDE_END(ix)
80-
jr c, _post_vol_slide_clamp
81-
;; the slide FX reached past its end, clamp it
114+
ex de, hl
115+
;; bc: 00xx (end vol)
116+
ld c, VOL_SLIDE_END(ix)
117+
ld b, VOL_SLIDE_END+1(ix)
118+
;; lh: new pos16 MSB
119+
ld l, d
120+
ld h, #0
121+
jr _vol_slide_cp
122+
_vol_slide_sub_inc:
123+
;; de: pos16-inc16
124+
or a
125+
sbc hl, bc
126+
ex de, hl
127+
;; bc: new pos16 MSB
128+
ld c, d
129+
ld b, #0
130+
;; lh: 00xx (end vol) or ffff (-1)
131+
ld l, VOL_SLIDE_END(ix)
132+
ld h, VOL_SLIDE_END+1(ix)
133+
134+
;; have we reached the end of the slide?
135+
;; slide up: continue if cur < end
136+
;; slide down: continue if end < cur
137+
;; note: we don't check for equality because the increment
138+
;; can go past the target note
139+
_vol_slide_cp:
140+
or a
141+
sbc hl, bc
142+
jp m, _vol_slide_intermediate
143+
144+
;; slide has reached its target
145+
146+
;; hl: clamp the last slide pos to the target displacement
82147
ld h, VOL_SLIDE_END(ix)
83-
_post_vol_slide_clamp:
84-
ld VOL_SLIDE_POS16(ix), l
85-
ld VOL_SLIDE_POS16+1(ix), h
86-
pop bc
148+
ld l, #0
149+
150+
;; for slide down, we finish one note below the real target to play
151+
;; all ticks with fractional parts. Adjust the end displacement back if needed
152+
bit BIT_SLIDE_DIRECTION, VOL_SLIDE_CFG(ix)
153+
jr z, _vol_slide_post_sub_clamp
154+
inc h
155+
_vol_slide_post_sub_clamp:
156+
;; slide is finished, but only stop the effect if requested
157+
bit BIT_SLIDE_KEEP_RUNNING, VOL_SLIDE_CFG(ix)
158+
jr nz, _vol_slide_intermediate
159+
res BIT_FX_VOL_SLIDE, FX(ix)
160+
161+
_vol_slide_intermediate:
162+
;; effect is still running
163+
;; CHECK: when we stop the slide midway, we can only keep the
164+
;; integer part of the slide, which may not match Furnace's semantics
165+
ld VOL_SLIDE_POS16(ix), e
166+
ld VOL_SLIDE_POS16+1(ix), d
167+
ld VOL(ix), d
168+
169+
ret
170+
171+
172+
;;; Enable volume slide effect for the current channel
173+
;;; ------
174+
;;; ix : state for channel
175+
;;; a : slide direction: 0 == up, 1 == down
176+
;;; [ hl ]: increment
177+
vol_slide_init::
178+
;; FX configuration
179+
ld VOL_SLIDE_CFG(ix), a
180+
181+
push bc
182+
push de
183+
184+
;; e: increment
185+
ld e, (hl)
186+
inc hl
187+
push hl
188+
189+
;; c: increment size: 1/4 volume
190+
ld c, #2
191+
call vol_slide_init_increment
192+
193+
;; b: current volume
194+
ld b, VOL(ix)
195+
196+
;; init volume slide source (absolute value)
197+
call vol_slide_init_source
198+
199+
;; set up a default target bound, as per definition, vol slides
200+
;; do not have one (they rely on the stop FX in the music)
201+
ld bc, #-1
202+
bit BIT_SLIDE_DIRECTION, VOL_SLIDE_CFG(ix)
203+
jr nz, _vol_slide_init_direction
204+
ld b, #0
205+
ld c, VOL_SLIDE_MAX(ix)
206+
_vol_slide_init_direction:
207+
ld VOL_SLIDE_END(ix), c
208+
ld VOL_SLIDE_END+1(ix), b
209+
set BIT_FX_VOL_SLIDE, FX(ix)
210+
87211
pop hl
212+
pop de
213+
pop bc
214+
215+
ld a, #1
88216
ret
217+
218+
219+
;;; Update an ongoing volume slide effect with a new volume
220+
;;; ------
221+
;;; ix : state for channel
222+
;;; a : new volume for channel
223+
vol_slide_update::
224+
bit BIT_SLIDE_PORTAMENTO, VOL_SLIDE_CFG(ix)
225+
jr nz, _vol_slide_update_target
226+
227+
_vol_slide_update_src:
228+
ld VOL_SLIDE_POS16(ix), #0
229+
ld VOL_SLIDE_POS16+1(ix), a
230+
ret
231+
232+
_vol_slide_update_target:
233+
;; b: current volume
234+
ld b, a
235+
;; d: displacement (new vol - current vol)
236+
sub VOL(ix)
237+
ld d, a
238+
call vol_slide_init_target
239+
ret
240+
241+
242+
;;; VOL_SLIDE_OFF
243+
;;; Stop the volume slide effect in progress for the current channel
244+
;;; ------
245+
vol_slide_off::
246+
;; set the new volume from current slide position
247+
ld a, VOL_SLIDE_POS16+1(ix)
248+
ld VOL(ix), a
249+
;; since we disable the FX outside of the pipeline process
250+
;; make sure to load this new volume at next pipeline run
251+
res BIT_FX_VOL_SLIDE, FX(ix)
252+
set BIT_LOAD_VOL, PIPELINE(ix)
253+
ld a, #1
254+
ret
255+
256+
257+
;;; VOL_SLIDE_UP
258+
;;; Enable volume slide up effect for the current channel
259+
;;; ------
260+
;;; [ hl ]: increment
261+
vol_slide_up::
262+
ld a, #0
263+
set BIT_SLIDE_KEEP_RUNNING, a
264+
jp vol_slide_init
265+
266+
267+
;;; VOL_SLIDE_DOWN
268+
;;; Enable volume slide down effect for the current channel
269+
;;; ------
270+
;;; [ hl ]: increment
271+
vol_slide_down::
272+
ld a, #1
273+
set BIT_SLIDE_KEEP_RUNNING, a
274+
jp vol_slide_init

0 commit comments

Comments
 (0)