Skip to content

Commit

Permalink
nullsound: big refactor and new pipeline processing
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
dciabrin committed Nov 21, 2024
1 parent dad1c17 commit 6a21bd1
Show file tree
Hide file tree
Showing 12 changed files with 1,528 additions and 1,804 deletions.
2 changes: 1 addition & 1 deletion nullsound/Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ all: nullsound.lib linkcheck.map
-include ../Makefile.config

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

VERSION=@version@
Expand Down
35 changes: 28 additions & 7 deletions nullsound/buffers.s
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,33 @@ ssg_semitone_distance::
.db 0x07, 0x07, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x04, 0, 0, 0
.db 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0, 0, 0

;;; Sine precalc
;;; Convert note flat representation to <octave,semitone> representation
;;; ------
;;; a 64 bytes 2*Pi sign precalc encoded as 3-bit magnitude + 1-bit sign
;;; This is used by the vibrato effect
;;; Precalc for 8 octaves
.bndry 128
note_to_octave_semitone::
.db 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b
.db 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b
.db 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b
.db 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b
.db 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b
.db 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b
.db 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b
.db 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b

;;; fixed-point sine precalc
;;; ------
;;; a 64 entries (128bytes) signed fixed point precalc of sin(x) for x in [0..2*pi],
;;; encoded as [-1.0..1.0] as [s..iffffffff....]. This serves as a base increment
;;; for vibrato displacement from 1..16, which yields a 9bits fixed point for
;;; displacement of the current NSS note
.bndry 128
sine::
.db 0, 0, 9, 10, 11, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 15
.db 15, 15, 15, 15, 15, 15, 14, 14, 13, 13, 12, 11, 11, 10, 9, 0
.db 0, 0, 1, 2, 3, 3, 4, 5, 5, 6, 6, 7, 7, 7, 7, 7
.db 7, 7, 7, 7, 7, 7, 6, 6, 5, 5, 4, 3, 3, 2, 1, 0
.dw 0x0000, 0x0190, 0x0310, 0x04a0, 0x0610, 0x0780, 0x08e0, 0x0a20
.dw 0x0b50, 0x0c50, 0x0d40, 0x0e10, 0x0ec0, 0x0f40, 0x0fb0, 0x0fe0
.dw 0x1000, 0x0fe0, 0x0fb0, 0x0f40, 0x0ec0, 0x0e10, 0x0d40, 0x0c50
.dw 0x0b50, 0x0a20, 0x08e0, 0x0780, 0x0610, 0x04a0, 0x0310, 0x0190
.dw 0x8000, 0x8190, 0x8310, 0x84a0, 0x8610, 0x8780, 0x88e0, 0x8a20
.dw 0x8b50, 0x8c50, 0x8d40, 0x8e10, 0x8ec0, 0x8f40, 0x8fb0, 0x8fe0
.dw 0x9000, 0x8fe0, 0x8fb0, 0x8f40, 0x8ec0, 0x8e10, 0x8d40, 0x8c50
.dw 0x8b50, 0x8a20, 0x88e0, 0x8780, 0x8610, 0x84a0, 0x8310, 0x8190
178 changes: 84 additions & 94 deletions nullsound/fx-slide.s
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,20 @@
.area CODE


;;; Enable slide effect for the current SSG channel
;;; Enable slide effect for the current channel
;;; ------
;;; ix : FM state for channel
;;; ix : state for channel
;;; a : slide direction: 0 == up, 1 == down
;;; [ hl ]: speed (4bits) and depth (4bits)
slide_init::
push bc
push de

;; b: slide direction (from a)
ld b, a

;; slide fx on
ld a, FX(ix)
set 1, a
ld FX(ix), a
;; enable slide FX
set BIT_FX_SLIDE, FX(ix)

;; a: speed
ld a, (hl)
Expand All @@ -48,6 +49,7 @@ slide_init::
rra
rra
and #0xf

;; de: inc16 = speed / 8
ld d, a
ld e, #0
Expand Down Expand Up @@ -85,67 +87,86 @@ _post_depth_negate:

inc hl

;; init semitone position, fixed point representation
ld a, #0
ld SLIDE_POS16(ix), a
ld SLIDE_POS16+1(ix), a

;; save target depth
ld a, SLIDE_DEPTH(ix)
ld SLIDE_END(ix), a

pop de
pop bc

ret


;;; Setup the end semitone for the currently configured slide
;;; Enable slide effect for the current channel
;;; ------
;;; ix : state for channel
;;; e : semitone to configure increments from
slide_setup_increments::
;;; ix : state for channel
;;; a : slide direction: 0 == up, 1 == down
;;; [ hl ]: speed (4bits) and depth (4bits)
slide_pitch_init::
push bc
push de

;; init semitone position, fixed point representation
ld SLIDE_POS16+1(ix), e
ld a, #0
ld SLIDE_POS16(ix), a

;; d: depth, negative if slide goes down
ld d, SLIDE_DEPTH(ix)
;; b: slide direction (from a)
ld b, a

;; c: note adjust. slide up: 4, slide down: -4
ld c, #4
bit 7, d
jr z, _post_inc_adjust
ld c, #-4
_post_inc_adjust:
;; enable slide FX
set BIT_FX_SLIDE, FX(ix)

;; b: current octave
ld a, SLIDE_POS16+1(ix)
and #0xf0
ld b, a
;; a: speed
ld a, (hl)

;; e: target octave
ld a, SLIDE_POS16+1(ix)
add d
and #0xf0
;; de: inc16 = speed / 32
ld d, a
ld e, #0
srl d
rr e
srl d
rr e
srl d
rr e
srl d
rr e
srl d
rr e
;; down: negate inc16
bit 0, b
jr z, _post_inc16_negate2
ld a, #0
sub e
ld e, a

;; if current and target octave differ, skip missing steps in the depth
ld a, b
cp e
jr z, _post_depth_adjust
ld a, d
add c ; slide up: 4, slide down: -4
ld a, #0
sbc d
ld d, a
_post_depth_adjust:
_post_inc16_negate2:
ld SLIDE_INC16(ix), e
ld SLIDE_INC16+1(ix), d

;; a: current octave/note
ld a, SLIDE_POS16+1(ix)
;; depth
ld a, #127
;; down: negate depth
;; we also need to go one seminote below, to account for the
;; fractional parts of the slide.
bit 0, b
jr z, _post_depth_negate2
neg
dec a
_post_depth_negate2:
ld SLIDE_DEPTH(ix), a

;; d: target octave/note
add d
ld d, a
inc hl

;; when target note is a missing step, adjust to the next note
and #0xf
cp #12
ld a, d
jr c, _post_target_note
add c ; slide up: 4, slide down: -4
_post_target_note:
;; save target octave/note
;; init semitone position, fixed point representation
ld a, #0
ld SLIDE_POS16(ix), a
ld SLIDE_POS16+1(ix), a

;; save target depth
ld a, SLIDE_DEPTH(ix)
ld SLIDE_END(ix), a

pop de
Expand Down Expand Up @@ -211,20 +232,17 @@ _post_sign_chk:
ret


;;; Increment current fixed point position in the semitone table and
;;; stop effects when the target position is reached
;;; Increment current fixed point displacement and
;;; stop effects when the target displacement is reached
;;; ------
;;; IN:
;;; ix : state for channel
;;; c : slide direction: 0 == up, 1 == down
;;; OUT:
;;; a : whether effect is finished (0: finished, 1: still running)
;;; d : when effect is finished, target semitone
;;; d : when effect is finished, target displacement
;;; de modified
eval_slide_step:
;; ix: state for the current channel
push hl
pop ix

;; c: 0 slide up, 1 slide down
ld a, SLIDE_INC16+1(ix)
rlc a
Expand All @@ -234,7 +252,7 @@ eval_slide_step:
;; INC16 increment is 1/8 semitone (0x0020) * depth
;; negative for slide down

;; add/sub increment to the current semitone POS16
;; add/sub increment to the current semitone displacement POS16
;; e: fractional part
ld a, SLIDE_INC16(ix)
add SLIDE_POS16(ix)
Expand All @@ -243,23 +261,8 @@ eval_slide_step:
;; d: integer part
ld a, SLIDE_INC16+1(ix)
adc SLIDE_POS16+1(ix)
ld SLIDE_POS16+1(ix), a
ld d, a
;; do we need to skip missing steps in the note table
and #0xf
cp #0xc
jr c, _post_skip
ld a, d
;; slide direction
bit 0, c
jr z, _slide_dist_up
add #-4
ld d, a
jr _post_skip
_slide_dist_up:
add #4
ld d, a
_post_skip:
ld SLIDE_POS16+1(ix), d

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

;; slide is finished, stop effect
ld (ix), #0
res BIT_FX_SLIDE, FX(ix)

;; d: clamp the last slide pos to the target semitone
;; d: clamp the last slide pos to the target displacement
ld d, SLIDE_END(ix)

;; for slide down, we finish one note below the real target to play
;; all ticks with fractional parts. Adjust the end note back if needed
;; all ticks with fractional parts. Adjust the end displacement back if needed
bit 0, c
jr z, _post_adjust
ld a, d
and #0xf
cp #11
jr c, _neg_inc_adjust
;; adjust to next note (after the missing steps in the note table)
ld a, d
add #5
ld d, a
jr _post_adjust
_neg_inc_adjust:
;; adjust to next note
ld a, d
inc a
ld d, a
inc d
_post_adjust:
;; effect is finished, new semitone in d
;; effect is finished, new displacement in d
ld a, #0
ret

Expand Down
Loading

0 comments on commit 6a21bd1

Please sign in to comment.