@effetune/dsp 0.4.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/dist/index.d.ts CHANGED
@@ -16,12 +16,15 @@ export type {
16
16
  DelayOptions,
17
17
  TimeAlignmentOptions,
18
18
  AMRadioSimulatorOptions,
19
+ AutoFilterOptions,
19
20
  AutoLevelerOptions,
21
+ AutoPanOptions,
20
22
  BandPassFilterOptions,
21
23
  BitCrusherOptions,
22
24
  BluetoothSBCSimulatorOptions,
23
25
  BrickwallLimiterOptions,
24
26
  CassetteArtifactsOptions,
27
+ ChorusOptions,
25
28
  CombFilterOptions,
26
29
  CommonEffectOptions,
27
30
  CompressorOptions,
@@ -40,6 +43,7 @@ export type {
40
43
  ExpanderOptions,
41
44
  FDNReverbOptions,
42
45
  FMRadioSimulatorOptions,
46
+ FrequencyShifterOptions,
43
47
  FifteenBandGEQOptions,
44
48
  FifteenBandPEQOptions,
45
49
  FiveBandDynamicEQOptions,
@@ -70,8 +74,11 @@ export type {
70
74
  NarrowRangeOptions,
71
75
  NoiseBlenderOptions,
72
76
  OscillatorOptions,
77
+ PhaserOptions,
78
+ PhaseSelectEQOptions,
73
79
  PitchShifterOptions,
74
80
  PowerAmpSagOptions,
81
+ RotarySpeakerOptions,
75
82
  RSReverbOptions,
76
83
  RoomEQOptions,
77
84
  SaturationOptions,
@@ -107,12 +114,15 @@ export {
107
114
  Delay,
108
115
  TimeAlignment,
109
116
  AMRadioSimulator,
117
+ AutoFilter,
110
118
  AutoLeveler,
119
+ AutoPan,
111
120
  BandPassFilter,
112
121
  BitCrusher,
113
122
  BluetoothSBCSimulator,
114
123
  BrickwallLimiter,
115
124
  CassetteArtifacts,
125
+ Chorus,
116
126
  CombFilter,
117
127
  Compressor,
118
128
  CrossfeedFilter,
@@ -129,6 +139,7 @@ export {
129
139
  Expander,
130
140
  FDNReverb,
131
141
  FMRadioSimulator,
142
+ FrequencyShifter,
132
143
  FifteenBandGEQ,
133
144
  FifteenBandPEQ,
134
145
  FiveBandDynamicEQ,
@@ -158,8 +169,11 @@ export {
158
169
  NarrowRange,
159
170
  NoiseBlender,
160
171
  Oscillator,
172
+ Phaser,
173
+ PhaseSelectEQ,
161
174
  PitchShifter,
162
175
  PowerAmpSag,
176
+ RotarySpeaker,
163
177
  RSReverb,
164
178
  RoomEQ,
165
179
  Saturation,
@@ -193,12 +207,15 @@ export {
193
207
  createDelay,
194
208
  createTimeAlignment,
195
209
  createAMRadioSimulator,
210
+ createAutoFilter,
196
211
  createAutoLeveler,
212
+ createAutoPan,
197
213
  createBandPassFilter,
198
214
  createBitCrusher,
199
215
  createBluetoothSBCSimulator,
200
216
  createBrickwallLimiter,
201
217
  createCassetteArtifacts,
218
+ createChorus,
202
219
  createCombFilter,
203
220
  createCompressor,
204
221
  createCrossfeedFilter,
@@ -213,6 +230,7 @@ export {
213
230
  createExpander,
214
231
  createFDNReverb,
215
232
  createFMRadioSimulator,
233
+ createFrequencyShifter,
216
234
  createFifteenBandGEQ,
217
235
  createFifteenBandPEQ,
218
236
  createFiveBandDynamicEQ,
@@ -242,8 +260,11 @@ export {
242
260
  createNarrowRange,
243
261
  createNoiseBlender,
244
262
  createOscillator,
263
+ createPhaser,
264
+ createPhaseSelectEQ,
245
265
  createPitchShifter,
246
266
  createPowerAmpSag,
267
+ createRotarySpeaker,
247
268
  createRSReverb,
248
269
  createRoomEQ,
249
270
  createSaturation,
@@ -267,7 +288,12 @@ export type { EffectDefinition } from './effect.js';
267
288
  import type { Effect } from './effect.js';
268
289
  import type { EffectChannel, EffectType } from './generated-effects.js';
269
290
 
270
- export declare class EffeTuneError extends Error {}
291
+ export declare class EffeTuneError extends Error {
292
+ readonly code?: string;
293
+ readonly path?: string;
294
+ readonly nodeId?: string;
295
+ readonly edgeId?: string;
296
+ }
271
297
  export declare class ValidationError extends EffeTuneError {}
272
298
  export declare class EffectError extends EffeTuneError {}
273
299
  export declare class AssetError extends EffeTuneError {}
@@ -519,6 +545,226 @@ export declare function createChain(
519
545
  options?: CreateChainOptions
520
546
  ): Promise<Chain>;
521
547
 
548
+ export interface GraphEndpoint {
549
+ readonly id: string;
550
+ }
551
+
552
+ export interface GraphNode extends ChainEffect {}
553
+
554
+ export interface GraphNodeInput extends ChainEffectInput {
555
+ readonly id: string;
556
+ }
557
+
558
+ export interface GraphEdge {
559
+ readonly id: string;
560
+ readonly source: string;
561
+ readonly destination: string;
562
+ readonly gain: number;
563
+ readonly mute: boolean;
564
+ readonly pan?: number;
565
+ readonly mixGroup: string;
566
+ readonly solo: boolean;
567
+ }
568
+
569
+ export interface GraphEdgeInput {
570
+ readonly id: string;
571
+ readonly source: string;
572
+ readonly destination: string;
573
+ readonly gain?: number;
574
+ readonly mute?: boolean;
575
+ readonly pan?: number;
576
+ readonly mixGroup?: string;
577
+ readonly solo?: boolean;
578
+ }
579
+
580
+ export interface GraphDocument {
581
+ readonly version: 1;
582
+ readonly input: GraphEndpoint;
583
+ readonly output: GraphEndpoint;
584
+ readonly nodes: readonly GraphNode[];
585
+ readonly edges: readonly GraphEdge[];
586
+ }
587
+
588
+ export interface GraphDocumentInput {
589
+ readonly version: 1;
590
+ readonly input: GraphEndpoint;
591
+ readonly output: GraphEndpoint;
592
+ readonly nodes: readonly GraphNodeInput[];
593
+ readonly edges: readonly GraphEdgeInput[];
594
+ }
595
+
596
+ export interface GraphCompileSnapshot {
597
+ readonly version: 1;
598
+ readonly identity: boolean;
599
+ readonly silence: boolean;
600
+ readonly effectiveSchedule: readonly string[];
601
+ readonly nodes: readonly GraphCompileNodeSnapshot[];
602
+ readonly edges: readonly GraphCompileEdgeSnapshot[];
603
+ readonly outputLatency: readonly number[];
604
+ readonly outputCompensation: readonly number[];
605
+ readonly latencySamples: number;
606
+ readonly capacity: Readonly<{ bufferSlots: number; workspaceBytes: number }>;
607
+ }
608
+
609
+ export interface GraphCompileNodeSnapshot {
610
+ readonly id: string;
611
+ readonly effective: boolean;
612
+ readonly dormant: boolean;
613
+ readonly enabled: boolean;
614
+ readonly disabledBypass: boolean;
615
+ readonly scheduleIndex: number | null;
616
+ readonly bufferSlot: number | null;
617
+ readonly processingGroup: Readonly<{ firstChannel: number; channelCount: number }>;
618
+ readonly kernelLatency: number;
619
+ readonly inputLatency: readonly number[];
620
+ readonly outputLatency: readonly number[];
621
+ readonly preNodeCompensation: readonly number[];
622
+ }
623
+
624
+ export interface GraphCompileEdgeSnapshot {
625
+ readonly id: string;
626
+ readonly active: boolean;
627
+ readonly suppressed: boolean;
628
+ readonly dormant: boolean;
629
+ readonly fanInCompensation: readonly number[];
630
+ }
631
+
632
+ export type GraphVisualizationState =
633
+ | 'structural'
634
+ | 'effective'
635
+ | 'dormant'
636
+ | 'disabled-bypass'
637
+ | 'suppressed';
638
+
639
+ export interface GraphVisualizationEndpoint {
640
+ readonly id: string;
641
+ readonly kind: 'input' | 'output';
642
+ }
643
+
644
+ export interface GraphVisualizationEffectNode {
645
+ readonly id: string;
646
+ readonly kind: 'effect';
647
+ readonly effectType: EffectType;
648
+ readonly enabled: boolean;
649
+ readonly effective?: boolean;
650
+ readonly dormant?: boolean;
651
+ readonly disabledBypass?: boolean;
652
+ readonly state: GraphVisualizationState;
653
+ }
654
+
655
+ export interface GraphVisualizationEdge {
656
+ readonly id: string;
657
+ readonly source: string;
658
+ readonly destination: string;
659
+ readonly active?: boolean;
660
+ readonly suppressed?: boolean;
661
+ readonly dormant?: boolean;
662
+ readonly state: GraphVisualizationState;
663
+ }
664
+
665
+ export interface GraphVisualizationSnapshot {
666
+ readonly version: 1;
667
+ readonly nodes: readonly (GraphVisualizationEndpoint | GraphVisualizationEffectNode)[];
668
+ readonly edges: readonly GraphVisualizationEdge[];
669
+ }
670
+
671
+ export interface GraphStructuralSnapshot {
672
+ readonly document: GraphDocument;
673
+ readonly topologicalOrder: readonly string[];
674
+ readonly incoming: Readonly<Record<string, readonly string[]>>;
675
+ readonly outgoing: Readonly<Record<string, readonly string[]>>;
676
+ }
677
+
678
+ export interface CreateGraphOptions extends ArtifactOptions {
679
+ readonly assetResolver?: AssetResolver | { resolve: AssetResolver };
680
+ }
681
+
682
+ export interface GraphProcessOptions {
683
+ readonly sampleRate: number;
684
+ readonly seed?: number;
685
+ readonly blockSize?: number;
686
+ }
687
+
688
+ export interface GraphStreamOptions extends GraphProcessOptions {
689
+ readonly channels?: number;
690
+ }
691
+
692
+ export interface GraphRecipeOptions {
693
+ readonly nodeId?: string;
694
+ readonly inputId?: string;
695
+ readonly outputId?: string;
696
+ }
697
+
698
+ export interface WetDryGraphOptions extends GraphRecipeOptions {
699
+ readonly wet?: number;
700
+ readonly dry?: number;
701
+ }
702
+
703
+ export interface SendReturnGraphOptions extends GraphRecipeOptions {
704
+ readonly send?: number;
705
+ readonly returnGain?: number;
706
+ }
707
+
708
+ export declare class Graph {
709
+ private constructor();
710
+ static load(input: string | GraphDocumentInput, options?: CreateGraphOptions): Promise<Graph>;
711
+ static fromChain(
712
+ chain: Chain | ChainDocumentInput | readonly (Effect | ChainEffectInput)[],
713
+ options?: CreateGraphOptions
714
+ ): Promise<Graph>;
715
+ static wetDry(effect: Effect | ChainEffectInput, options?: WetDryGraphOptions): GraphDocument;
716
+ static sendReturn(effect: Effect | ChainEffectInput, options?: SendReturnGraphOptions): GraphDocument;
717
+ readonly nodes: readonly GraphNode[];
718
+ readonly edges: readonly GraphEdge[];
719
+ toJSON(): GraphDocument;
720
+ toChain(): ChainDocument;
721
+ serialize(space?: number): string;
722
+ getNode(id: string): GraphNode | null;
723
+ getEdge(id: string): GraphEdge | null;
724
+ incoming(id: string): readonly GraphEdge[];
725
+ outgoing(id: string): readonly GraphEdge[];
726
+ structuralSnapshot(): GraphStructuralSnapshot;
727
+ visualizationSnapshot(): GraphVisualizationSnapshot;
728
+ stream(options: GraphStreamOptions): Promise<GraphStream>;
729
+ latencySamples(options: LatencyOptions): Promise<number>;
730
+ process(audio: readonly Float32Array[], options: GraphProcessOptions): Promise<Float32Array[]>;
731
+ close(): void;
732
+ }
733
+
734
+ export declare class GraphStream {
735
+ readonly graph: GraphDocument;
736
+ readonly latencySamples: number;
737
+ readonly compileSnapshot: GraphCompileSnapshot;
738
+ visualizationSnapshot(): GraphVisualizationSnapshot;
739
+ setParam(nodeId: string, parameterName: string, value: unknown): this;
740
+ reset(): this;
741
+ process(audio: readonly Float32Array[]): Promise<Float32Array[]>;
742
+ close(): void;
743
+ }
744
+
745
+ export declare function createGraph(
746
+ input: string | GraphDocumentInput,
747
+ options?: CreateGraphOptions
748
+ ): Promise<Graph>;
749
+
750
+ export declare function normalizeGraphDocument(
751
+ input: string | GraphDocumentInput
752
+ ): GraphDocument;
753
+ export declare function graphDocumentFromChain(
754
+ input: ChainDocumentInput | readonly (Effect | ChainEffectInput)[]
755
+ ): GraphDocument;
756
+ export declare function chainDocumentFromGraph(
757
+ input: GraphDocumentInput
758
+ ): ChainDocument;
759
+ export declare function createWetDryGraphDocument(
760
+ effect: Effect | ChainEffectInput,
761
+ options?: WetDryGraphOptions
762
+ ): GraphDocument;
763
+ export declare function createSendReturnGraphDocument(
764
+ effect: Effect | ChainEffectInput,
765
+ options?: SendReturnGraphOptions
766
+ ): GraphDocument;
767
+
522
768
  export declare function parsePreset(
523
769
  input: string | ChainDocumentInput | readonly (Effect | ChainEffectInput)[]
524
770
  ): ChainDocument;
package/dist/index.js CHANGED
@@ -25,12 +25,15 @@ export {
25
25
  Delay,
26
26
  TimeAlignment,
27
27
  AMRadioSimulator,
28
+ AutoFilter,
28
29
  AutoLeveler,
30
+ AutoPan,
29
31
  BitCrusher,
30
32
  BluetoothSBCSimulator,
31
33
  BrickwallLimiter,
32
34
  BandPassFilter,
33
35
  CassetteArtifacts,
36
+ Chorus,
34
37
  CombFilter,
35
38
  Compressor,
36
39
  CrossfeedFilter,
@@ -47,6 +50,7 @@ export {
47
50
  Expander,
48
51
  FDNReverb,
49
52
  FMRadioSimulator,
53
+ FrequencyShifter,
50
54
  FifteenBandGEQ,
51
55
  FifteenBandPEQ,
52
56
  FiveBandDynamicEQ,
@@ -76,8 +80,11 @@ export {
76
80
  NarrowRange,
77
81
  NoiseBlender,
78
82
  Oscillator,
83
+ Phaser,
84
+ PhaseSelectEQ,
79
85
  PitchShifter,
80
86
  PowerAmpSag,
87
+ RotarySpeaker,
81
88
  RSReverb,
82
89
  RoomEQ,
83
90
  Saturation,
@@ -111,12 +118,15 @@ export {
111
118
  createDelay,
112
119
  createTimeAlignment,
113
120
  createAMRadioSimulator,
121
+ createAutoFilter,
114
122
  createAutoLeveler,
123
+ createAutoPan,
115
124
  createBandPassFilter,
116
125
  createBitCrusher,
117
126
  createBluetoothSBCSimulator,
118
127
  createBrickwallLimiter,
119
128
  createCassetteArtifacts,
129
+ createChorus,
120
130
  createCombFilter,
121
131
  createCompressor,
122
132
  createCrossfeedFilter,
@@ -131,6 +141,7 @@ export {
131
141
  createExpander,
132
142
  createFDNReverb,
133
143
  createFMRadioSimulator,
144
+ createFrequencyShifter,
134
145
  createFifteenBandGEQ,
135
146
  createFifteenBandPEQ,
136
147
  createFiveBandDynamicEQ,
@@ -160,8 +171,11 @@ export {
160
171
  createNarrowRange,
161
172
  createNoiseBlender,
162
173
  createOscillator,
174
+ createPhaser,
175
+ createPhaseSelectEQ,
163
176
  createPitchShifter,
164
177
  createPowerAmpSag,
178
+ createRotarySpeaker,
165
179
  createRSReverb,
166
180
  createRoomEQ,
167
181
  createSaturation,
@@ -182,6 +196,14 @@ export {
182
196
  export { getEffectCatalog } from './catalog.js';
183
197
  export { encodeEta1 } from './assets.js';
184
198
  export { Chain, createChain, isBundleDocument } from './runtime.js';
199
+ export { Graph, GraphStream, createGraph } from './graph.js';
200
+ export {
201
+ chainDocumentFromGraph,
202
+ createSendReturnGraphDocument,
203
+ createWetDryGraphDocument,
204
+ graphDocumentFromChain,
205
+ normalizeGraphDocument
206
+ } from './graph-document.js';
185
207
  export { importLegacyPreset, parsePreset } from './preset.js';
186
208
 
187
209
  import { getEffectCatalog } from './catalog.js';
@@ -36,6 +36,7 @@ const REQUIRED_FUNCTION_EXPORTS = [
36
36
  'et_telemetry_capacity',
37
37
  'et_telemetry_read',
38
38
  'et_pipeline_configure',
39
+ 'et_pipeline_latency',
39
40
  'et_pipeline_process'
40
41
  ];
41
42
 
@@ -811,7 +812,21 @@ export class DspEngineBinding {
811
812
  this._refreshViews();
812
813
  this._assertRange(ptr, bytes.byteLength, 'Pipeline descriptor');
813
814
  this.u8.set(bytes, ptr);
814
- return this.exports.et_pipeline_configure(this.engine, ptr, bytes.byteLength);
815
+ this._preparing = true;
816
+ let status = ET_ERR_STATE;
817
+ try {
818
+ status = this.exports.et_pipeline_configure(this.engine, ptr, bytes.byteLength);
819
+ } finally {
820
+ this._refreshViews();
821
+ this._preparing = false;
822
+ }
823
+ this.getArenaViews();
824
+ return status;
825
+ }
826
+
827
+ pipelineLatency() {
828
+ if (!this.engine) return 0;
829
+ return this.exports.et_pipeline_latency(this.engine) >>> 0;
815
830
  }
816
831
 
817
832
  pipelineProcess(channelCount, frameCount, timeSeconds, masterBypass = false) {
@@ -826,6 +841,132 @@ export class DspEngineBinding {
826
841
  );
827
842
  }
828
843
 
844
+ graphCapabilities() {
845
+ if (typeof this.exports.et_graph_capabilities !== 'function') return 0;
846
+ return this.exports.et_graph_capabilities() >>> 0;
847
+ }
848
+
849
+ get graphSupported() {
850
+ return Boolean(
851
+ (this.graphCapabilities() & 1) !== 0 &&
852
+ typeof this.exports.et_graph_configure === 'function' &&
853
+ typeof this.exports.et_graph_latency === 'function' &&
854
+ typeof this.exports.et_graph_process === 'function' &&
855
+ typeof this.exports.et_graph_snapshot_size === 'function' &&
856
+ typeof this.exports.et_graph_snapshot_copy === 'function' &&
857
+ typeof this.exports.et_graph_read_diagnostic === 'function' &&
858
+ typeof this.exports.et_graph_set_instance_params === 'function' &&
859
+ typeof this.exports.et_graph_reset === 'function'
860
+ );
861
+ }
862
+
863
+ graphConfigure(descriptor) {
864
+ if (!this.engine || !this.prepared || !this.graphSupported) return ET_ERR_STATE;
865
+ const bytes = toUint8View(descriptor, 'Graph descriptor');
866
+ if (bytes.byteLength === 0) return ET_ERR_STATE;
867
+ this._preparing = true;
868
+ let ptr = 0;
869
+ try {
870
+ ptr = this.exports.malloc(bytes.byteLength) >>> 0;
871
+ this._refreshViews();
872
+ if (!ptr) return ET_ERR_STATE;
873
+ this._assertRange(ptr, bytes.byteLength, 'Graph descriptor');
874
+ this.u8.set(bytes, ptr);
875
+ return this.exports.et_graph_configure(this.engine, ptr, bytes.byteLength);
876
+ } finally {
877
+ if (ptr) this.exports.free(ptr);
878
+ this._refreshViews();
879
+ this._preparing = false;
880
+ if (this.engine && this.prepared) this.getArenaViews();
881
+ }
882
+ }
883
+
884
+ graphLatency() {
885
+ if (!this.engine || !this.graphSupported) return 0;
886
+ return this.exports.et_graph_latency(this.engine) >>> 0;
887
+ }
888
+
889
+ graphProcess(channelCount, frameCount, timeSeconds) {
890
+ if (!this.engine || !this.graphSupported) return ET_ERR_STATE;
891
+ this._refreshViews();
892
+ return this.exports.et_graph_process(
893
+ this.engine,
894
+ channelCount >>> 0,
895
+ frameCount >>> 0,
896
+ timeSeconds
897
+ );
898
+ }
899
+
900
+ graphSetInstanceParams(instanceId, packed, paramsHash, changedIndex) {
901
+ if (!this.engine || !this.graphSupported) return ET_ERR_STATE;
902
+ const values = packed instanceof Float32Array ? packed : Float32Array.from(packed || []);
903
+ const byteLength = values.length * Float32Array.BYTES_PER_ELEMENT;
904
+ if (byteLength > SCRATCH_BYTES) {
905
+ throw new DspBindingError('Packed Graph parameters exceed the scratch-buffer capacity');
906
+ }
907
+ const ptr = this.exports.et_scratch_ptr(this.engine) >>> 0;
908
+ this._refreshViews();
909
+ this._assertRange(ptr, byteLength, 'Packed Graph parameter block');
910
+ new Float32Array(this._memoryBuffer, ptr, values.length).set(values);
911
+ return this.exports.et_graph_set_instance_params(
912
+ this.engine,
913
+ instanceId,
914
+ ptr,
915
+ values.length,
916
+ paramsHash >>> 0,
917
+ changedIndex >>> 0
918
+ );
919
+ }
920
+
921
+ graphReset() {
922
+ if (!this.engine || !this.graphSupported) return ET_ERR_STATE;
923
+ return this.exports.et_graph_reset(this.engine);
924
+ }
925
+
926
+ graphSnapshot() {
927
+ if (!this.engine || !this.graphSupported) return null;
928
+ const byteLength = this.exports.et_graph_snapshot_size(this.engine) >>> 0;
929
+ if (byteLength === 0) return new Uint8Array();
930
+ let ptr = 0;
931
+ this._preparing = true;
932
+ try {
933
+ ptr = this.exports.malloc(byteLength) >>> 0;
934
+ this._refreshViews();
935
+ if (!ptr) throw new DspBindingError('Unable to allocate the Graph snapshot buffer');
936
+ this._assertRange(ptr, byteLength, 'Graph snapshot');
937
+ const status = this.exports.et_graph_snapshot_copy(
938
+ this.engine,
939
+ ptr,
940
+ byteLength
941
+ );
942
+ if (status !== ET_OK) {
943
+ throw new DspBindingError('DSP Graph snapshot could not be read');
944
+ }
945
+ return new Uint8Array(this.u8.slice(ptr, ptr + byteLength));
946
+ } finally {
947
+ if (ptr) this.exports.free(ptr);
948
+ this._refreshViews();
949
+ this._preparing = false;
950
+ if (this.engine && this.prepared) this.getArenaViews();
951
+ }
952
+ }
953
+
954
+ graphDiagnostic() {
955
+ if (!this.engine || !this.graphSupported) return null;
956
+ const ptr = this.exports.et_scratch_ptr(this.engine) >>> 0;
957
+ this._refreshViews();
958
+ this._assertRange(ptr, 24, 'Graph diagnostic');
959
+ if (this.exports.et_graph_read_diagnostic(this.engine, ptr) !== ET_OK) return null;
960
+ return {
961
+ status: this.dataView.getInt32(ptr, true),
962
+ kind: this.dataView.getUint32(ptr + 4, true),
963
+ index: this.dataView.getUint32(ptr + 8, true),
964
+ path: this.dataView.getUint32(ptr + 12, true),
965
+ required: this.dataView.getUint32(ptr + 16, true),
966
+ capacity: this.dataView.getUint32(ptr + 20, true)
967
+ };
968
+ }
969
+
829
970
  markFailed() {
830
971
  this.failed = true;
831
972
  }