@denaudio/den 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +63 -0
- package/LICENSE-APACHE +202 -0
- package/LICENSE-MIT +21 -0
- package/README.md +107 -2
- package/dist/biquad-eq.d.ts +11 -0
- package/dist/biquad-eq.js +35 -0
- package/dist/catalog-filter-math.d.ts +4 -0
- package/dist/catalog-filter-math.js +30 -0
- package/dist/character-filter.d.ts +13 -0
- package/dist/character-filter.js +53 -0
- package/dist/convolution-spectrum.d.ts +25 -0
- package/dist/convolution-spectrum.js +82 -0
- package/dist/convolution.d.ts +17 -0
- package/dist/convolution.js +87 -0
- package/dist/crossover.d.ts +11 -0
- package/dist/crossover.js +17 -0
- package/dist/curve-shaper.d.ts +26 -0
- package/dist/curve-shaper.js +73 -0
- package/dist/delay-fx.d.ts +37 -0
- package/dist/delay-fx.js +84 -0
- package/dist/delay-readhead.d.ts +19 -0
- package/dist/delay-readhead.js +54 -0
- package/dist/delay-settings.d.ts +55 -0
- package/dist/delay-settings.js +20 -0
- package/dist/drive.d.ts +24 -0
- package/dist/drive.js +116 -0
- package/dist/dual-head-delay.d.ts +28 -0
- package/dist/dual-head-delay.js +77 -0
- package/dist/dynamics.d.ts +61 -0
- package/dist/dynamics.js +130 -0
- package/dist/envelope.d.ts +34 -0
- package/dist/envelope.js +62 -0
- package/dist/filter.d.ts +9 -0
- package/dist/filter.js +34 -0
- package/dist/filterbank-vocoder.d.ts +35 -0
- package/dist/filterbank-vocoder.js +52 -0
- package/dist/formant-bank.d.ts +15 -0
- package/dist/formant-bank.js +28 -0
- package/dist/freeze-reverb.d.ts +35 -0
- package/dist/freeze-reverb.js +61 -0
- package/dist/frequency-shifter.d.ts +24 -0
- package/dist/frequency-shifter.js +57 -0
- package/dist/gate.d.ts +2 -0
- package/dist/gate.js +12 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +12 -0
- package/dist/instrument-example.d.ts +12 -0
- package/dist/instrument-example.js +29 -0
- package/dist/instrument-settings.d.ts +95 -0
- package/dist/instrument-settings.js +36 -0
- package/dist/instrument.d.ts +42 -0
- package/dist/instrument.js +166 -0
- package/dist/lfo.d.ts +19 -0
- package/dist/lfo.js +55 -0
- package/dist/live-buffer.d.ts +39 -0
- package/dist/live-buffer.js +52 -0
- package/dist/live-granular.d.ts +41 -0
- package/dist/live-granular.js +64 -0
- package/dist/lookahead-limiter.d.ts +31 -0
- package/dist/lookahead-limiter.js +67 -0
- package/dist/loop-crossfade.d.ts +28 -0
- package/dist/loop-crossfade.js +72 -0
- package/dist/modulation-fx.d.ts +47 -0
- package/dist/modulation-fx.js +58 -0
- package/dist/modulation.d.ts +132 -0
- package/dist/modulation.js +228 -0
- package/dist/mpe-expression.d.ts +36 -0
- package/dist/mpe-expression.js +73 -0
- package/dist/multiband-dynamics.d.ts +50 -0
- package/dist/multiband-dynamics.js +60 -0
- package/dist/musical-controls.d.ts +76 -0
- package/dist/musical-controls.js +125 -0
- package/dist/musical-examples.d.ts +21 -0
- package/dist/musical-examples.js +142 -0
- package/dist/musical-materials.d.ts +110 -0
- package/dist/musical-materials.js +56 -0
- package/dist/oscillator.d.ts +10 -0
- package/dist/oscillator.js +35 -0
- package/dist/oversampled-drive.d.ts +19 -0
- package/dist/oversampled-drive.js +99 -0
- package/dist/performance.d.ts +61 -0
- package/dist/performance.js +241 -0
- package/dist/pitch-quantizer.d.ts +26 -0
- package/dist/pitch-quantizer.js +88 -0
- package/dist/prepared-convolution.d.ts +26 -0
- package/dist/prepared-convolution.js +104 -0
- package/dist/resident-recorder.d.ts +28 -0
- package/dist/resident-recorder.js +68 -0
- package/dist/resident-time-stretch.d.ts +46 -0
- package/dist/resident-time-stretch.js +136 -0
- package/dist/resonator.d.ts +32 -0
- package/dist/resonator.js +63 -0
- package/dist/reverb.d.ts +27 -0
- package/dist/reverb.js +52 -0
- package/dist/sample.d.ts +113 -0
- package/dist/sample.js +212 -0
- package/dist/source.d.ts +58 -0
- package/dist/source.js +113 -0
- package/dist/spatial-chains.d.ts +50 -0
- package/dist/spatial-chains.js +76 -0
- package/dist/spectral-fft.d.ts +27 -0
- package/dist/spectral-fft.js +84 -0
- package/dist/spectral-freeze.d.ts +24 -0
- package/dist/spectral-freeze.js +74 -0
- package/dist/spectral-gate.d.ts +23 -0
- package/dist/spectral-gate.js +58 -0
- package/dist/spectral-stft.d.ts +14 -0
- package/dist/spectral-stft.js +70 -0
- package/dist/spectral-texture.d.ts +46 -0
- package/dist/spectral-texture.js +141 -0
- package/dist/spectral.d.ts +18 -0
- package/dist/spectral.js +10 -0
- package/dist/state-variable-filter.d.ts +17 -0
- package/dist/state-variable-filter.js +25 -0
- package/dist/stereo-delay.d.ts +45 -0
- package/dist/stereo-delay.js +70 -0
- package/dist/virtual-analog.d.ts +26 -0
- package/dist/virtual-analog.js +66 -0
- package/dist/voice-policy.d.ts +37 -0
- package/dist/voice-policy.js +245 -0
- package/dist/wavetable-bands.d.ts +37 -0
- package/dist/wavetable-bands.js +145 -0
- package/dist/wavetable-read.d.ts +6 -0
- package/dist/wavetable-read.js +11 -0
- package/dist/wavetable.d.ts +29 -0
- package/dist/wavetable.js +49 -0
- package/dist/windowed-pitch-shift.d.ts +34 -0
- package/dist/windowed-pitch-shift.js +51 -0
- package/docs/catalog-audition.md +76 -0
- package/docs/catalog-filters.md +125 -0
- package/docs/catalog-modulation-fx.md +220 -0
- package/docs/catalog-status.md +433 -0
- package/docs/character-filter.md +139 -0
- package/docs/contracts.md +141 -0
- package/docs/control-modulation.md +194 -0
- package/docs/convolution.md +50 -0
- package/docs/curve-shaper.md +117 -0
- package/docs/delay-fx-capture-findings.json +134 -0
- package/docs/delay-fx.md +202 -0
- package/docs/delay-readhead.md +121 -0
- package/docs/delay-settings-candidate.json +333 -0
- package/docs/delay-settings.md +111 -0
- package/docs/dependency-findings.md +58 -0
- package/docs/deployment-status.md +37 -0
- package/docs/drive.md +152 -0
- package/docs/dual-head-delay.md +131 -0
- package/docs/dynamics.md +180 -0
- package/docs/envelope-integer-staging.md +64 -0
- package/docs/filter-materialization-results.json +71 -0
- package/docs/filter-materialization.md +135 -0
- package/docs/filter-oscillator.md +126 -0
- package/docs/filterbank-vocoder-entry.md +58 -0
- package/docs/freeze-reverb.md +179 -0
- package/docs/frequency-shifter.md +133 -0
- package/docs/frontend-audition.md +22 -0
- package/docs/gain-schedule-verification.md +53 -0
- package/docs/initial-acceptance.md +79 -0
- package/docs/instrument-performance.md +191 -0
- package/docs/instrument-settings.md +130 -0
- package/docs/instrument.md +204 -0
- package/docs/integration-candidate.md +114 -0
- package/docs/live-buffer.md +163 -0
- package/docs/live-granular.md +179 -0
- package/docs/lookahead-multiband.md +183 -0
- package/docs/loop-crossfade.md +99 -0
- package/docs/mpe-expression.md +65 -0
- package/docs/musical-clock-seek-boundary.md +31 -0
- package/docs/musical-controls-contract.md +144 -0
- package/docs/musical-examples.md +255 -0
- package/docs/oversampled-drive.md +153 -0
- package/docs/performance.md +53 -0
- package/docs/pitch-quantizer.md +55 -0
- package/docs/prepared-convolution.md +197 -0
- package/docs/realtime-audition.md +63 -0
- package/docs/resident-recorder.md +151 -0
- package/docs/resident-time-stretch.md +196 -0
- package/docs/sample.md +191 -0
- package/docs/sound-audition-headroom.md +103 -0
- package/docs/sources.md +81 -0
- package/docs/spatial-chains-entry.md +251 -0
- package/docs/spectral-freeze-entry.md +132 -0
- package/docs/spectral-gate-entry.md +134 -0
- package/docs/spectral-large-candidate.md +81 -0
- package/docs/spectral-texture-entry.md +178 -0
- package/docs/spectral.md +127 -0
- package/docs/virtual-analog.md +77 -0
- package/docs/voice-policy.md +38 -0
- package/docs/wavetable-bands.md +138 -0
- package/docs/wavetable.md +101 -0
- package/docs/windowed-pitch-shift.md +112 -0
- package/package.json +269 -4
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# Modulation, stereo delay and algorithmic reverb candidates
|
|
2
|
+
|
|
3
|
+
Status: **CANDIDATE**. These are composable DSP modules, not human-approved sounds,
|
|
4
|
+
finished room/plate emulations, or a browser real-time performance guarantee.
|
|
5
|
+
The catalog source is [sections 8 and 10](https://www.notion.so/3ef449b4e81d817db1acf1fff48779b3).
|
|
6
|
+
|
|
7
|
+
Public entries:
|
|
8
|
+
|
|
9
|
+
- `@denaudio/den/modulation-fx`: `flanger`, `phaser` and their config/control types
|
|
10
|
+
- `@denaudio/den/stereo-delay`: `pingPongDelay`, `multiTapDelay`, `StereoDelayConfig`,
|
|
11
|
+
`PingPongControls`, `DelayMixControls`, `DelayTap`, `MultiTapDelayConfig`
|
|
12
|
+
- `@denaudio/den/reverb`: `algorithmicReverb`, `AlgorithmicReverbConfig`, `ReverbControls`
|
|
13
|
+
|
|
14
|
+
All use existing `defineSubgraph` / `instantiate` and state/snapshot mechanisms.
|
|
15
|
+
No loader, routing, serialization, parameter, or test framework is added.
|
|
16
|
+
Use the tested unworklet 0.6.0 dependency. The root entry does not re-export these candidate modules.
|
|
17
|
+
|
|
18
|
+
## Shared entry contract
|
|
19
|
+
|
|
20
|
+
Instantiate during graph construction with `sampleRate: ctx.sampleRate`; rates are
|
|
21
|
+
integer Hz in [8000, 192000]. Call each instance's `tick` exactly once per sample.
|
|
22
|
+
Audio and continuous controls are `Node<'f32'>`, reset/bypass are `Node<'bool'>`.
|
|
23
|
+
Inputs and controls must be finite. Numerical tests use nominal audio within
|
|
24
|
+
[-1, 1]; extreme near-overflow f32 input is not a supported operating level.
|
|
25
|
+
There is no output limiter and wet/feedback paths can exceed unity.
|
|
26
|
+
|
|
27
|
+
`mix` is linear dry/wet in [0, 1], clamped at the endpoints. A zero mix continues
|
|
28
|
+
feeding/advancing the effect. Bypass emits unity dry, stops new input to the wet
|
|
29
|
+
network, and continues its existing tail. Re-enabling it reveals that continuing
|
|
30
|
+
tail. Bypass does not save CPU. Reset clears effective history **before** the
|
|
31
|
+
current input is processed. Holding reset continually clears history. Reset and
|
|
32
|
+
bypass together suppress new wet input; reset alone accepts the current input.
|
|
33
|
+
|
|
34
|
+
No implicit parameter smoothing or click-free bypass is claimed. Abrupt controls
|
|
35
|
+
can create discontinuities. The caller owns musical modulation and smoothing.
|
|
36
|
+
Persistent histories use the existing snapshot path; tests cover exact same-rate,
|
|
37
|
+
same-schema continuation. Cross-rate snapshots and changed construction schemas
|
|
38
|
+
are not asserted compatible. unworklet scalar writes flush values below 1e-30;
|
|
39
|
+
very small tails therefore differ from ideal infinite-precision equations.
|
|
40
|
+
|
|
41
|
+
## Flanger
|
|
42
|
+
|
|
43
|
+
`flanger(config).tick(left, right, controls)` is stereo-in/stereo-out and returns
|
|
44
|
+
`left`, `right`, `timingRejected`, `modulationClipped`.
|
|
45
|
+
|
|
46
|
+
Construction controls:
|
|
47
|
+
|
|
48
|
+
- `maxDelaySeconds`: fixed per-channel capacity, one sample through 0.02 seconds;
|
|
49
|
+
default 0.02
|
|
50
|
+
- `stereoPhaseCycles`: finite relative right LFO phase; default 0.5
|
|
51
|
+
|
|
52
|
+
Sample controls: `delaySeconds`, `depthSeconds`, `rateHz`, `feedback`, `mix`,
|
|
53
|
+
`bypass`, `reset`. Base time must lie in [one sample, capacity]. Invalid time emits
|
|
54
|
+
dry, stops new wet input, and preserves the prior valid internal time (or minimum
|
|
55
|
+
time on reset), reporting `timingRejected`. Depth and rate inherit existing delay
|
|
56
|
+
bounds: depth [0, 0.05] seconds, rate [0, 20] Hz; the resulting moving head is clipped
|
|
57
|
+
to the declared short capacity and reports `modulationClipped`.
|
|
58
|
+
Feedback is positive, clamped to [0, 0.95].
|
|
59
|
+
|
|
60
|
+
This intentionally reuses `delayFx`, `delayReadhead` and the existing LFO. Flat
|
|
61
|
+
feedback and short delay create the comb response: with a static integer delay D,
|
|
62
|
+
wet transfer is z^-D / (1 - feedback*z^-D). At zero feedback and 50% mix, the first
|
|
63
|
+
notch is at sampleRate/(2D). Tests check complex frequency response, not merely a
|
|
64
|
+
renamed chorus preset. Wet latency is the selected delay; dry has no added delay.
|
|
65
|
+
Linear interpolation attenuates high frequencies and moving delay produces
|
|
66
|
+
Doppler pitch changes. There is no through-zero or negative-feedback mode.
|
|
67
|
+
|
|
68
|
+
## Phaser
|
|
69
|
+
|
|
70
|
+
`phaser(config).tick(input, controls)` returns one mono sample. Compose independent
|
|
71
|
+
instances, or use different modulation trajectories, for stereo.
|
|
72
|
+
|
|
73
|
+
- `stages`: fixed 2, 4, 6 or 8 first-order allpasses; default 4
|
|
74
|
+
- `frequencyHz`: common per-stage -90 degree frequency, clamped to
|
|
75
|
+
[20, 0.45*sampleRate]
|
|
76
|
+
- `feedback`: signed previous-sample wet feedback, clamped to [-0.95, 0.95]
|
|
77
|
+
- `mix`, `bypass`, `reset`: shared behavior above
|
|
78
|
+
|
|
79
|
+
With a = (tan(pi*f/fs)-1)/(tan(pi*f/fs)+1), a static stage has transfer
|
|
80
|
+
(a + z^-1)/(1 + a*z^-1). Stages are normalized lattice sections:
|
|
81
|
+
y = a*x + b*s; next_s = b*x - a*s; b = sqrt(1-a*a). The scattering matrix is
|
|
82
|
+
orthogonal, so even changing a every sample cannot create energy in that isolated
|
|
83
|
+
section. The bounded sine/cosine polynomial uses f64 arithmetic, followed by f64
|
|
84
|
+
coefficient, signal, history and feedback staging. This does not promise absence
|
|
85
|
+
of modulation sidebands, perceptual artifacts, or numerical error.
|
|
86
|
+
|
|
87
|
+
Static wet magnitude is unity; dry/wet cancellation produces the phaser notches.
|
|
88
|
+
At 100% wet it is an allpass phase effect, not an EQ notch bank. There is direct
|
|
89
|
+
feedthrough, no lookahead, and exactly one sample in the explicit feedback path.
|
|
90
|
+
A normalized realization is deliberate: a time-varying direct-form allpass does
|
|
91
|
+
not inherit the same per-sample energy argument automatically.
|
|
92
|
+
|
|
93
|
+
## Ping-pong delay
|
|
94
|
+
|
|
95
|
+
`pingPongDelay(config).tick(left, right, controls)` returns stereo samples and
|
|
96
|
+
`timingRejected`. `maxDelaySeconds` is fixed, one sample through 8 seconds;
|
|
97
|
+
default 2. `timeSeconds` sets both channel delays and has the same invalid-request
|
|
98
|
+
policy as the flanger base time. It is a moving, linearly interpolated head;
|
|
99
|
+
there is no dual-head transition or internal tempo conversion.
|
|
100
|
+
|
|
101
|
+
Feedback is signed and clamped to [-0.95, 0.95]. Both channels are read before
|
|
102
|
+
either channel is written. The left wet output feeds the right input and vice
|
|
103
|
+
versa. A left-only impulse appears on the left after D samples, right after 2D,
|
|
104
|
+
left after 3D, with amplitudes 1, g, g². No extra sample enters this circulation.
|
|
105
|
+
A duplicated mono input stays symmetric. A feedback filter is not part of this
|
|
106
|
+
candidate; the existing `delayFx` provides filtered independent-channel repeats.
|
|
107
|
+
|
|
108
|
+
## Multitap delay
|
|
109
|
+
|
|
110
|
+
`multiTapDelay(config).tick(monoInput, controls)` returns `left`, `right`.
|
|
111
|
+
Construction fixes 1–8 taps and the common `maxDelaySeconds` capacity (default 2,
|
|
112
|
+
up to 8 seconds). Each tap has `delaySeconds`, `gainLeft`, `gainRight`. Times must
|
|
113
|
+
fit [one sample, capacity]; signed gains must be finite and in [-1e6, 1e6].
|
|
114
|
+
|
|
115
|
+
All gains share divisor max(1, sum(abs(left gains)), sum(abs(right gains))). This
|
|
116
|
+
preserves signs, each channel's relative tap levels, and stereo ratios; it reduces
|
|
117
|
+
absolute level when either sum exceeds unity. There is no per-tap auto gain or
|
|
118
|
+
energy-based normalization. The post-normalization L1 sum in either channel is
|
|
119
|
+
at most one, giving the mixed-tap feedback path a clear amplitude bound.
|
|
120
|
+
|
|
121
|
+
Each tap reuses one independent `delayReadhead`, read once and written once per
|
|
122
|
+
sample. This deliberately spends N fixed-capacity buffers instead of changing the
|
|
123
|
+
existing readhead's single-read contract. Feedback is the average of the two wet
|
|
124
|
+
channels, multiplied by signed gain [-0.95, 0.95], then added to mono input before
|
|
125
|
+
all tap writes. Opposite-polarity stereo taps can cancel in this feedback sum.
|
|
126
|
+
Dry mono input is copied to both channels. There is no runtime tap insertion,
|
|
127
|
+
reordering or time control; rebuild for a different rhythmic pattern.
|
|
128
|
+
|
|
129
|
+
## Small algorithmic reverb
|
|
130
|
+
|
|
131
|
+
`algorithmicReverb(config).tick(left, right, { mix, bypass, reset })` returns
|
|
132
|
+
stereo samples. The network has four fixed delays and a Hadamard/2 orthogonal
|
|
133
|
+
feedback matrix. Reference delays are 29.7, 37.1, 41.1 and 43.7 ms, scaled and
|
|
134
|
+
rounded to sample counts at construction.
|
|
135
|
+
|
|
136
|
+
- `roomScale`: fixed [0.5, 2], default 1
|
|
137
|
+
- `decaySeconds`: fixed low-frequency target RT60 [0.1, 10], default 1.5
|
|
138
|
+
- `dampingHz`: fixed matched-z one-pole corner [20, 0.45*sampleRate], default
|
|
139
|
+
min(6000, 0.45*sampleRate)
|
|
140
|
+
|
|
141
|
+
Each delay's loop gain is 10^(-3*delaySamples/(sampleRate*decaySeconds)). The damping
|
|
142
|
+
pole exp(-2*pi*dampingHz/sampleRate) makes a convex one-pole lowpass, so high-band
|
|
143
|
+
decay is shorter than the low-frequency target. Room, decay and damping are
|
|
144
|
+
construction settings, **not runtime modulation controls**. Compute rate-relative
|
|
145
|
+
settings from `ctx.sampleRate`, including during unworklet's eager 48 kHz capture.
|
|
146
|
+
|
|
147
|
+
Input stereo is injected through two orthonormal Hadamard columns and wet stereo
|
|
148
|
+
uses two other orthonormal projections. Hadamard diffusion occurs at every return;
|
|
149
|
+
there are no extra input diffusers or hand-tuned early-reflection paths. Sparse
|
|
150
|
+
initial reflections and metallic modes are possible. Increasing echo density and
|
|
151
|
+
correct low-band decay do not establish a pleasant room/hall/plate sound.
|
|
152
|
+
|
|
153
|
+
There is no predelay or processing lookahead. The first wet arrival is approximately
|
|
154
|
+
29.7 ms*roomScale; dry is immediate. This is an acoustic network delay, not a host
|
|
155
|
+
latency-compensation value. Four buffers use the existing readhead capacity rule,
|
|
156
|
+
ceil(sampleRate*maxDelaySeconds)+2; floating-point ceiling can add a guard slot.
|
|
157
|
+
Passing their times through the existing f32 seconds API introduces at most a small
|
|
158
|
+
fractional-sample interpolation difference; the independent reference includes it.
|
|
159
|
+
This implementation is damped, not a lossless network or freeze effect.
|
|
160
|
+
|
|
161
|
+
No convolution, IR handling, FFT, shimmer, frequency shifter or preset engine is
|
|
162
|
+
included. There is no claim of matching a commercial reverb or a physical room.
|
|
163
|
+
|
|
164
|
+
## Verification and reproducibility
|
|
165
|
+
|
|
166
|
+
Focused suites are `tests/catalog-modulation-fx.spec.ts` and
|
|
167
|
+
`tests/catalog-reverb.spec.ts`, at 44.1, 48 and 96 kHz. They check independent
|
|
168
|
+
complex comb/allpass responses, DC/Nyquist and cutoff extremes, lattice
|
|
169
|
+
fast-modulation energy, signed ping-pong timing against a non-ring timeline,
|
|
170
|
+
normalization/polarity/steady-state tap levels, reset/bypass/mix, fresh silence,
|
|
171
|
+
exact same-schema continuation, stereo and mono behavior, FDN impulse/matrix
|
|
172
|
+
references, bounded energy, echo-density growth and band-decay fits.
|
|
173
|
+
|
|
174
|
+
The FDN 0.6 s decay fixture requires a low-band fitted RT60 between 0.45 and 0.75 s
|
|
175
|
+
and high-band RT60 below 65% of low-band RT60. This explicitly allows finite-window
|
|
176
|
+
and modal estimation differences; no test threshold is adjusted from an observed
|
|
177
|
+
result. A separate 43.7-second offline fixture exercises maximum 10-second decay,
|
|
178
|
+
sustained stereo excitation and a long tail. Every render requires finite outputs
|
|
179
|
+
and zero reported scrubbed samples.
|
|
180
|
+
|
|
181
|
+
`tests/catalog-modulation-packed.test.mjs` installs the actual tarball into a fresh
|
|
182
|
+
consumer, checks public-entry types, renders WASM at all three rates, builds a Vite
|
|
183
|
+
worklet bundle, and records CANDIDATE WAV files plus package/source hashes under
|
|
184
|
+
`artifacts/catalog-modulation`. Building a worklet bundle is not browser execution.
|
|
185
|
+
Exact-head CI/browser verification belongs to the integration gate. These tests do
|
|
186
|
+
not measure hardware audio, scheduler deadlines, maximum voice count, or universal
|
|
187
|
+
runtime performance. Listen to candidate material before musical approval.
|
|
188
|
+
|
|
189
|
+
## Algorithm sources
|
|
190
|
+
|
|
191
|
+
- Julius O. Smith, [delay-line interpolation](https://www.dsprelated.com/freebooks/pasp/Delay_Line_Signal_Interpolation.html)
|
|
192
|
+
and [allpass sections](https://www.dsprelated.com/freebooks/filters/Allpass_Filter_Sections.html):
|
|
193
|
+
background for the interpolation and static allpass transfer properties.
|
|
194
|
+
- Sebastian J. Schlecht and Emanuel A. P. Habets,
|
|
195
|
+
[On Lossless Feedback Delay Networks](https://arxiv.org/abs/1606.07729): matrix
|
|
196
|
+
losslessness background. This candidate adds fixed losses and independent tests;
|
|
197
|
+
the paper is not evidence of this implementation's musical or runtime quality.
|
|
198
|
+
|
|
199
|
+
Implementation is original TypeScript composition of den/unworklet primitives;
|
|
200
|
+
no external DSP source code or audio assets were copied.
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
## Review clarifications and boundary correction
|
|
204
|
+
|
|
205
|
+
`decaySeconds` sets each FDN line's nominal loop-gain loss, not an exact measured
|
|
206
|
+
RT60 or a hard 10-second tail ceiling. Damping suppresses high frequencies, but
|
|
207
|
+
very low damping also adds loop-filter group delay and can lengthen low-band
|
|
208
|
+
decay. Independent review at 48 kHz, roomScale 0.5, decaySeconds 10 and damping 20 Hz
|
|
209
|
+
measured asymptotic stereo-energy RT60 of 14.8826 seconds (fit 5–15 seconds of a
|
|
210
|
+
43.69-second impulse render, zero scrubs/nonfinite values). Independent
|
|
211
|
+
matrix-pole analysis predicted 14.9275 seconds. This stable setting is retained
|
|
212
|
+
with the correct interpretation, not described as a measured 10-second maximum.
|
|
213
|
+
|
|
214
|
+
The catalog integration also corrects the shared read-head's one-sample
|
|
215
|
+
construction boundary. At rates such as 8001 Hz, `sampleRate*(1/sampleRate)` can
|
|
216
|
+
round below 1. Construction now checks the seconds value against the exact
|
|
217
|
+
computed reciprocal first, then floors the already-valid product at one sample.
|
|
218
|
+
The immediately smaller representable seconds value still rejects. Regression
|
|
219
|
+
coverage checks new wrappers plus old/new audio, complete state and WASM parity
|
|
220
|
+
for the original 44.1/48/96 kHz paths. No broader capacity rounding is introduced.
|