@effetune/dsp 0.1.0 → 0.5.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/README.md CHANGED
@@ -3,8 +3,8 @@
3
3
  <!-- BEGIN DSP-LIBRARY-JAVASCRIPT-SUMMARY -->
4
4
  EffeTune DSP provides the same MIT-licensed C++ audio kernels used by EffeTune
5
5
  as a self-contained WebAssembly package for Node.js and evergreen browsers.
6
- Version 0.1.0 exposes all 76 catalog types through the generic Chain and
7
- `createEffect` APIs and 76 generated named convenience classes,
6
+ Version 0.5.0 exposes all 90 catalog types through the generic Chain and
7
+ `createEffect` APIs and 90 generated named convenience classes,
8
8
  decoded analyzer telemetry, versioned semantic presets, deterministic seeds, and an AudioWorklet wrapper.
9
9
  <!-- END DSP-LIBRARY-JAVASCRIPT-SUMMARY -->
10
10
 
@@ -39,6 +39,44 @@ const output = await chain.process(input, { sampleRate: 48000 });
39
39
  console.log(output.length, output[0].length, output[0][0]);
40
40
  chain.close();
41
41
  ```
42
+
43
+ ### Graph v1 quickstart
44
+
45
+ Graph v1 is opt-in routing for branching and merging:
46
+
47
+ ```js
48
+ import { Graph, createGraph, createVolume } from '@effetune/dsp';
49
+
50
+ const input = [
51
+ new Float32Array(128).fill(0.25),
52
+ new Float32Array(128).fill(0.25)
53
+ ];
54
+ const graphDocument = Graph.wetDry(
55
+ createVolume({ id: 'wet', volume: -6 }),
56
+ { dry: 0.5, wet: 0.5 }
57
+ );
58
+ const graph = await createGraph(graphDocument);
59
+ let stream;
60
+
61
+ try {
62
+ const offline = await graph.process(input, { sampleRate: 48000 });
63
+ stream = await graph.stream({
64
+ sampleRate: 48000,
65
+ channels: 2,
66
+ blockSize: 128
67
+ });
68
+ const continuous = await stream.process(input);
69
+ console.log(
70
+ offline[0][0],
71
+ continuous[0][0],
72
+ stream.latencySamples,
73
+ stream.compileSnapshot.effectiveSchedule
74
+ );
75
+ } finally {
76
+ stream?.close();
77
+ graph.close();
78
+ }
79
+ ```
42
80
  <!-- END DSP-LIBRARY-JAVASCRIPT-START -->
43
81
 
44
82
  The package is ESM-only. Save the example as `start.mjs` and run
@@ -51,10 +89,14 @@ Public package entry points are:
51
89
  - `@effetune/dsp/worklet` for `EffeTuneNode`
52
90
  - `@effetune/dsp/processor` for the side-effect AudioWorklet processor
53
91
  - `@effetune/dsp/schemas/chain-v1.json` for the Chain v1 JSON Schema
92
+ - `@effetune/dsp/schemas/graph-v1.json` for the Graph v1 JSON Schema
54
93
  - `@effetune/dsp/schemas/bundle-v1.json` for the Bundle v1 JSON Schema
55
94
  - `@effetune/dsp/catalog` for ESM catalog exports
56
95
  - `@effetune/dsp/catalog.json` for the machine-readable catalog JSON
57
96
 
97
+ Graph v1 is opt-in. Its current capacities and delay-storage accounting are
98
+ published in the [Graph v1 guide](https://effetune.frieve.com/dsp/reference/graph-v1/#capacity).
99
+
58
100
  Every offline `process()` call starts from fresh DSP state and returns newly
59
101
  owned `Float32Array` channels. Input arrays are never mutated. Effects run in
60
102
  array order; a disabled effect and an empty chain are identity operations.
@@ -134,15 +176,73 @@ verify exact byte length and SHA-256 before accepting an ETA1 payload. The
134
176
  complete payload and convolution footprint must fit the 32 MiB kernel cap.
135
177
 
136
178
  `EFFECT_CATALOG` and `getEffectCatalog()` expose the machine-readable semantic
137
- catalog for all 76 root classes and their `create<Type>()` factories. The
179
+ catalog for all 90 root classes and their `create<Type>()` factories. The
138
180
  catalog contains channel choices, parameters, required assets, telemetry, and
139
181
  latency declarations, but no private implementation mapping.
140
182
 
183
+ ### Modulation Style recipes
184
+
185
+ The application-only **Style** selector is not a DSP parameter or a second
186
+ preset API. The following JSON-compatible objects are the equivalent public
187
+ parameter dictionaries. Copy one into a named constructor, for example
188
+ `new Chorus(MODULATION_STYLES.Chorus.Flanger)`, or into a Chain effect's
189
+ `parameters` object.
190
+
191
+ ```js
192
+ const MODULATION_STYLES = {
193
+ AutoFilter: {
194
+ "Auto Filter Sweep": { mode: "LFO", filterType: "Low-pass", minimumFrequency: 200, maximumFrequency: 4000, resonance: 1.5, mix: 80, rate: 0.5, waveform: "Sine", stereoPhase: 0, sensitivity: 24, attack: 20, release: 250, direction: "Up" },
195
+ "Stereo Filter Sweep": { mode: "LFO", filterType: "Low-pass", minimumFrequency: 160, maximumFrequency: 6000, resonance: 2, mix: 85, rate: 0.35, waveform: "Sine", stereoPhase: 120, sensitivity: 24, attack: 20, release: 250, direction: "Up" },
196
+ "Envelope Filter": { mode: "Envelope", filterType: "Low-pass", minimumFrequency: 100, maximumFrequency: 5000, resonance: 1.2, mix: 85, rate: 0.5, waveform: "Sine", stereoPhase: 0, sensitivity: 24, attack: 18, release: 300, direction: "Up" },
197
+ "Auto Wah": { mode: "Envelope", filterType: "Band-pass", minimumFrequency: 180, maximumFrequency: 2400, resonance: 5, mix: 100, rate: 0.5, waveform: "Sine", stereoPhase: 0, sensitivity: 30, attack: 8, release: 180, direction: "Up" },
198
+ "Reverse Auto Wah": { mode: "Envelope", filterType: "Band-pass", minimumFrequency: 180, maximumFrequency: 2800, resonance: 4, mix: 100, rate: 0.5, waveform: "Sine", stereoPhase: 0, sensitivity: 30, attack: 12, release: 350, direction: "Down" }
199
+ },
200
+ AutoPan: {
201
+ "Gentle Auto Pan": { rate: 0.35, depth: 45, center: 0, width: 70, waveform: "Sine", phase: 0 },
202
+ "Wide Auto Pan": { rate: 0.7, depth: 100, center: 0, width: 100, waveform: "Sine", phase: 0 },
203
+ "Fast Auto Pan": { rate: 4, depth: 85, center: 0, width: 100, waveform: "Triangle", phase: 0 }
204
+ },
205
+ Chorus: {
206
+ "Classic Chorus": { mode: "Chorus", rate: 0.8, delay: 12, depth: 3, voices: 3, stereoSpread: 60, feedback: 0, mix: 45 },
207
+ "Stereo Chorus": { mode: "Stereo Chorus", rate: 0.65, delay: 15, depth: 4, voices: 2, stereoSpread: 80, feedback: 0, mix: 50 },
208
+ Ensemble: { mode: "Ensemble", rate: 0.45, delay: 20, depth: 6, voices: 6, stereoSpread: 100, feedback: 0, mix: 60 },
209
+ Flanger: { mode: "Flanger", rate: 0.35, delay: 2.5, depth: 2, voices: 1, stereoSpread: 35, feedback: 45, mix: 50 },
210
+ "Jet Flanger": { mode: "Flanger", rate: 0.18, delay: 1.5, depth: 1.4, voices: 1, stereoSpread: 70, feedback: -75, mix: 55 },
211
+ Vibrato: { mode: "Vibrato", rate: 4.5, delay: 8, depth: 5, voices: 1, stereoSpread: 50, feedback: 0, mix: 100 }
212
+ },
213
+ FrequencyShifter: {
214
+ "Shift Up": { mode: "Shift", shift: 8, carrierFrequency: 440, minimumShift: 20, maximumShift: 800, rate: 0.15, direction: "Up", stereoPhase: 0, mix: 100 },
215
+ "Shift Down": { mode: "Shift", shift: -8, carrierFrequency: 440, minimumShift: 20, maximumShift: 800, rate: 0.15, direction: "Down", stereoPhase: 0, mix: 100 },
216
+ "Fine Detune": { mode: "Shift", shift: 2, carrierFrequency: 440, minimumShift: 20, maximumShift: 800, rate: 0.15, direction: "Up", stereoPhase: 90, mix: 55 },
217
+ "Ring Modulator": { mode: "Ring Mod", shift: 8, carrierFrequency: 440, minimumShift: 20, maximumShift: 800, rate: 0.15, direction: "Up", stereoPhase: 0, mix: 100 },
218
+ "Barber-pole Up": { mode: "Barber-pole", shift: 8, carrierFrequency: 440, minimumShift: 20, maximumShift: 900, rate: 0.12, direction: "Up", stereoPhase: 90, mix: 85 },
219
+ "Barber-pole Down": { mode: "Barber-pole", shift: -8, carrierFrequency: 440, minimumShift: 20, maximumShift: 900, rate: 0.12, direction: "Down", stereoPhase: 90, mix: 85 }
220
+ },
221
+ Phaser: {
222
+ "Classic Phaser": { mode: "Classic", rate: 0.5, centerFrequency: 1000, range: 3, stages: 6, feedback: 20, stereoPhase: 90, direction: "Up", mix: 50 },
223
+ "Deep Phaser": { mode: "Classic", rate: 0.25, centerFrequency: 700, range: 4.5, stages: 12, feedback: 55, stereoPhase: 30, direction: "Up", mix: 55 },
224
+ "Stereo Phaser": { mode: "Classic", rate: 0.65, centerFrequency: 1200, range: 3.5, stages: 8, feedback: 25, stereoPhase: 120, direction: "Up", mix: 50 },
225
+ "Barber-pole Up": { mode: "Barber-pole", rate: 0.35, centerFrequency: 1000, range: 5, stages: 8, feedback: 30, stereoPhase: 60, direction: "Up", mix: 55 },
226
+ "Barber-pole Down": { mode: "Barber-pole", rate: 0.35, centerFrequency: 1000, range: 5, stages: 8, feedback: 30, stereoPhase: 60, direction: "Down", mix: 55 }
227
+ },
228
+ RotarySpeaker: {
229
+ "Rotary Slow": { speedState: "Slow", speed: 100, acceleration: 2.2, crossover: 800, rotorBalance: 0, stereoWidth: 75, dopplerDepth: 45, amplitudeDepth: 55, mix: 70 },
230
+ "Rotary Fast": { speedState: "Fast", speed: 100, acceleration: 1.4, crossover: 800, rotorBalance: 0, stereoWidth: 85, dopplerDepth: 65, amplitudeDepth: 70, mix: 78 },
231
+ "Gentle Rotary": { speedState: "Slow", speed: 75, acceleration: 3, crossover: 900, rotorBalance: 0, stereoWidth: 45, dopplerDepth: 25, amplitudeDepth: 30, mix: 55 },
232
+ "Leslie Slow": { speedState: "Slow", speed: 100, acceleration: 2.8, crossover: 800, rotorBalance: -5, stereoWidth: 80, dopplerDepth: 50, amplitudeDepth: 60, mix: 75 },
233
+ "Leslie Fast": { speedState: "Fast", speed: 100, acceleration: 1.8, crossover: 800, rotorBalance: -5, stereoWidth: 90, dopplerDepth: 70, amplitudeDepth: 75, mix: 82 }
234
+ }
235
+ };
236
+ ```
237
+
141
238
  For stateful processing, `ChainStream.latencySamples` reports aggregate runtime
142
239
  latency and matches Python `Stream.latency_samples` for the same chain and
143
240
  sample rate. `chain.latencySamples({ sampleRate })` reports the same value
144
- without opening a stream, which aligns offline `process()` output.
145
- `EffeTuneNode` does not expose a latency getter.
241
+ without opening a stream. `EffeTuneNode.latencySamples` exposes the cached
242
+ aggregate for real-time processing; initialization and awaited `setParam()` or
243
+ `reset()` calls update it before returning. These APIs report latency without
244
+ trimming or padding offline output, so the host decides how to place rendered
245
+ audio.
146
246
 
147
247
  For real-time processing:
148
248
 
@@ -156,6 +256,7 @@ const node = await EffeTuneNode.create(context, preset, {
156
256
  });
157
257
  source.connect(node).connect(context.destination);
158
258
  await node.setParam('voice', 'threshold', -20);
259
+ console.log(node.latencySamples);
159
260
  await node.reset();
160
261
  node.close();
161
262
  ```