Skip to content

Commit 617a93b

Browse files
committed
nullsound massive refactoring of FX processing
- slides and vibrato FX have ben updated to work on both note and volume with a single codebase. - semantics of all FX hae been updated to match Furnace while changing note/volume/FX while an FX is ongoing - general cleanup to avoid duplicating NSS bytecodes for each channel
1 parent 318408b commit 617a93b

File tree

17 files changed

+1132
-1533
lines changed

17 files changed

+1132
-1533
lines changed

nullsound/Makefile.in

Lines changed: 1 addition & 1 deletion
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 memory bios-commands adpcm ym2610 stream timer utils nss-fm nss-ssg nss-adpcm-a nss-adpcm-b fx-vibrato fx-slide fx-vol-slide fx-trigger fx-arpeggio fx-legato volume
22+
OBJS=entrypoint memory bios-commands adpcm ym2610 stream timer utils nss-fm nss-ssg nss-adpcm-a nss-adpcm-b fx-vibrato fx-slide fx-trigger fx-arpeggio fx-legato volume
2323
LIB=nullsound.lib
2424

2525
VERSION=@version@

nullsound/align.inc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,6 @@
2727
;; to tune the constants below to achieve our desired alignment.
2828

2929
.lclequ ALIGN_OFFSET_FM, 0xbc
30-
.lclequ ALIGN_OFFSET_SSG, 0x50
30+
.lclequ ALIGN_OFFSET_SSG, 0x4b
3131
.lclequ ALIGN_OFFSET_ADPCM_A, 0x52
32-
.lclequ ALIGN_OFFSET_ADPCM_B, 0x1a
32+
.lclequ ALIGN_OFFSET_ADPCM_B, 0x10

nullsound/doc/nss.md

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,12 @@ This document details the current level of support for Furnace features in NSS.
2222
- Only the `sequence` macro type can used to configure SSG properties. Macro types `ADSR` and `LFO` are not supported and there is no plan to support them.
2323

2424
- Within a sequence macro, each step is 1 tick long. That is, each time the YM2610 triggers an IRQ during music playback, a step of the macro is being evaluated. Unlike in Furnace, there is no native support in NSS for step length or step delay.
25+
2526
- Macro looping is currently different from what Furnace allows. Currently, NSS groups property updates by steps. When the loop is reached, it starts again from the configured step, which means all properties are re-evaluated from this step. This means you can't have loops for two different properties. This is going to improve in the future to match Furnace's semantics.
2627

2728
- SSG Auto-envelope feature is currently broken, SSG instruments using that feature can be processed by `nsstool`, but the resulting playback is invalid. Do not use it.
2829

29-
* If you use SSG in your Furnace module, and SSG instruments use the SSG noise channel, be aware that this will prevent you from fading out your module while it's playing. This is because the YM2610 has no support in hardware to change the volume of the noise channel.
30+
* If you use SSG in your Furnace module, and SSG instruments uses the volume envelope bit for the channel, be aware that this will prevent you from fading out your module while it's playing. This is because the YM2610 has no support in hardware to change the volume of the envelope generator.
3031

3132

3233
## Currently supported Furnace FX
@@ -39,15 +40,15 @@ This document details the current level of support for Furnace features in NSS.
3940

4041
## Volume
4142

42-
| FX | Description | Status | Note |
43-
|------|-------------------------------|--------|--------------------------------|
44-
| `0A` | Volume slide | | Only volume down. No ADPCM yet |
45-
| `FA` | Fast volume slide | 💜 | |
46-
| `F3` | Fine volume slide up | 💜 | |
47-
| `F4` | Fine volume slide down | 💜 | |
48-
| `F8` | Single tick volume slide up | 💜 | |
49-
| `F9` | Single tick volume slide down | 💜 | |
50-
| `07` | Tremolo | 💜 | |
43+
| FX | Description | Status | Note |
44+
|------|-------------------------------|--------|------|
45+
| `0A` | Volume slide | 💚| |
46+
| `FA` | Fast volume slide | 💜 | |
47+
| `F3` | Fine volume slide up | 💜 | |
48+
| `F4` | Fine volume slide down | 💜 | |
49+
| `F8` | Single tick volume slide up | 💜 | |
50+
| `F9` | Single tick volume slide down | 💜 | |
51+
| `07` | Tremolo | 💜 | |
5152

5253

5354
## Pitch
@@ -61,29 +62,29 @@ This document details the current level of support for Furnace features in NSS.
6162
| F2 | Single tick pitch slide down | 💜 | |
6263
| 03 | Portamento | 💚 | |
6364
| E1 | Note slide up | 💚 | |
64-
| E2 | Note slide down | 💚 | |
6565
| EA | Toggle legato | 💜 | |
66+
| E2 | Note slide down | 💚 | |
6667
| E6 | Quick legato (compatibility) | 🚫 | |
67-
| E8 | Quick legato up | 🚫 | |
68-
| E9 | Quick legato down | 🚫 | |
69-
| 00 | Arpeggio | 💜 | |
70-
| E0 | Set arpeggio speed | 💜 | |
68+
| E8 | Quick legato up | 💚 | |
69+
| E9 | Quick legato down | 💚 | |
70+
| 00 | Arpeggio | 💚 | |
71+
| E0 | Set arpeggio speed | 💚 | |
7172
| 04 | Vibrato | 💚 | |
7273
| E3 | Set vibrato direction | 🚫 | |
7374
| E4 | Set vibrato rang | 🚫 | |
7475

7576

7677
## Panning
7778

78-
| FX | Description | Status | Note |
79-
|----|---------------------------------|--------|------|
80-
| 08 | Set panning | 💚 | |
81-
| 88 | Set rear panning | 🚫 | |
82-
| 81 | Set volume of left channe | 🚫 | |
83-
| 82 | Set volume of right channe | 🚫 | |
84-
| 89 | Set volume of rear left channe | 🚫 | |
85-
| 8A | Set volume of rear right channe | 🚫 | |
86-
| 80 | Set panning (linear) | 💚 | |
79+
| FX | Description | Status | Note |
80+
|----|----------------------------------|--------|------|
81+
| 08 | Set panning | 💚 | |
82+
| 88 | Set rear panning | 🚫 | |
83+
| 81 | Set volume of left channel | 🚫 | |
84+
| 82 | Set volume of right channel | 🚫 | |
85+
| 89 | Set volume of rear left channel | 🚫 | |
86+
| 8A | Set volume of rear right channel | 🚫 | |
87+
| 80 | Set panning (linear) | 💚 | |
8788

8889

8990
## Time

nullsound/fx-arpeggio.s

Lines changed: 58 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
;;; You should have received a copy of the GNU Lesser General Public License
1717
;;; along with ngdevkit. If not, see <http://www.gnu.org/licenses/>.
1818

19-
;;; Trigger effect (delay, cut...), common functions for FM and SSG
19+
;;; Arpeggio effect for FM, SSG and ADPCM-B
2020
;;;
2121

2222
.module nullsound
@@ -29,26 +29,58 @@
2929
.area CODE
3030

3131

32+
;;; Update the arpeggio state for the current channel
33+
;;; ------
34+
;;; ix: mirrored state of the current channel
35+
eval_arpeggio_step::
36+
;; assert: speed is always >=1, so count is never 0 here
37+
dec ARPEGGIO_COUNT(ix)
38+
ld a, ARPEGGIO_COUNT(ix)
39+
cp #0
40+
jr z, _arpeggio_update_pos
41+
ret
42+
_arpeggio_update_pos:
43+
;; rearm countdown
44+
ld a, ARPEGGIO_SPEED(ix)
45+
ld ARPEGGIO_COUNT(ix), a
46+
47+
;; update position in the arpeggio
48+
ld a, ARPEGGIO_POS(ix)
49+
dec a
50+
jp p, _arpeggio_post_pos
51+
add #3
52+
_arpeggio_post_pos:
53+
ld ARPEGGIO_POS(ix), a
54+
55+
;; set semitone offset according to position
56+
cp #2
57+
jr nz, _arpeggio_not2
58+
;; pos == 2: 2nd note in chord
59+
ld a, ARPEGGIO_2ND(ix)
60+
ld ARPEGGIO_POS8(ix), a
61+
jr _arpeggio_eval_end
62+
_arpeggio_not2:
63+
cp #1
64+
jr nz, _arpeggio_not1
65+
;; pos == 2: 3rd note in chord
66+
ld a, ARPEGGIO_3RD(ix)
67+
ld ARPEGGIO_POS8(ix), a
68+
jr _arpeggio_eval_end
69+
_arpeggio_not1:
70+
;; 1st note in chord (0 displacement)
71+
ld ARPEGGIO_POS8(ix), #0
72+
73+
_arpeggio_eval_end:
74+
ret
75+
76+
3277
;;; ARPEGGIO
3378
;;; Enable arpeggio chord for note playback
3479
;;; ------
3580
;;; ix : state for channel
3681
;;; [ hl ]: semitone:4 - semitone:4
3782
;;; hl modified
3883
arpeggio::
39-
;; check whether this disables FX
40-
ld a, (hl)
41-
cp #0
42-
jr nz, _arpeggio_init
43-
inc hl
44-
res BIT_FX_ARPEGGIO, FX(ix)
45-
;; To fully clear the state after the FX is disabled, we must remember
46-
;; to recompute the note and tune values without shift, so force it here
47-
ld ARPEGGIO_POS8(ix), a
48-
set BIT_LOAD_NOTE, PIPELINE(ix)
49-
ld a, #1
50-
ret
51-
_arpeggio_init:
5284
;; 2nd note in chord
5385
ld a, (hl)
5486
rra
@@ -66,15 +98,15 @@ _arpeggio_init:
6698
inc hl
6799

68100
;; init arpeggio state if it is not running already
69-
bit BIT_FX_ARPEGGIO, FX(ix)
101+
bit BIT_FX_ARPEGGIO, NOTE_FX(ix)
70102
jr nz, _arpeggio_end
71103
ld a, ARPEGGIO_SPEED(ix)
72104
ld ARPEGGIO_COUNT(ix), a
73105
xor a
74106
ld ARPEGGIO_POS(ix), a
75107
ld ARPEGGIO_POS8(ix), a
76108

77-
set BIT_FX_ARPEGGIO, FX(ix)
109+
set BIT_FX_ARPEGGIO, NOTE_FX(ix)
78110

79111
_arpeggio_end:
80112
ld a, #1
@@ -90,55 +122,21 @@ _arpeggio_end:
90122
arpeggio_speed::
91123
ld a, (hl)
92124
inc hl
93-
94125
ld ARPEGGIO_SPEED(ix), a
95-
96126
ld a, #1
97-
98127
ret
99128

100129

101-
;;; Update the arpeggio state for the current channel
130+
;;; ARPEGGIO_OFF
131+
;;; Disable arpeggio chord for note playback
102132
;;; ------
103-
;;; ix: mirrored state of the current channel
104-
;;; [TODO modified]
105-
eval_arpeggio_step::
106-
;; assert: speed is always >=1, so count is never 0 here
107-
dec ARPEGGIO_COUNT(ix)
108-
ld a, ARPEGGIO_COUNT(ix)
109-
cp #0
110-
jr z, _arpeggio_update_pos
111-
ret
112-
_arpeggio_update_pos:
113-
;; rearm countdown
114-
ld a, ARPEGGIO_SPEED(ix)
115-
ld ARPEGGIO_COUNT(ix), a
116-
117-
;; update position in the arpeggio
118-
ld a, ARPEGGIO_POS(ix)
119-
dec a
120-
jp p, _arpeggio_post_pos
121-
add #3
122-
_arpeggio_post_pos:
123-
ld ARPEGGIO_POS(ix), a
124-
125-
;; set semitone offset according to position
126-
cp #2
127-
jr nz, _arpeggio_not2
128-
;; pos == 2: 2nd note in chord
129-
ld a, ARPEGGIO_2ND(ix)
130-
ld ARPEGGIO_POS8(ix), a
131-
jr _arpeggio_eval_end
132-
_arpeggio_not2:
133-
cp #1
134-
jr nz, _arpeggio_not1
135-
;; pos == 2: 3rd note in chord
136-
ld a, ARPEGGIO_3RD(ix)
137-
ld ARPEGGIO_POS8(ix), a
138-
jr _arpeggio_eval_end
139-
_arpeggio_not1:
140-
;; 1st note in chord (0 displacement)
133+
;;; ix : state for channel
134+
arpeggio_off::
135+
;; disable FX
136+
res BIT_FX_ARPEGGIO, NOTE_FX(ix)
141137
ld ARPEGGIO_POS8(ix), #0
142-
143-
_arpeggio_eval_end:
138+
;; since we disable the FX outside of the pipeline process
139+
;; make sure to load this new note at next pipeline run
140+
set BIT_LOAD_NOTE, PIPELINE(ix)
141+
ld a, #1
144142
ret

0 commit comments

Comments
 (0)