@fluex/fluexgl-dsp 0.1.2 → 0.1.3
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 +1 -1
- package/lib/dist/console-codes.d.ts +13 -13
- package/lib/dist/console-codes.js +16 -16
- package/lib/dist/core/classes/AudioClip.d.ts +62 -66
- package/lib/dist/core/classes/AudioClip.d.ts.map +1 -1
- package/lib/dist/core/classes/AudioClip.js +386 -410
- package/lib/dist/core/classes/AudioDevice.d.ts +12 -12
- package/lib/dist/core/classes/AudioDevice.js +30 -30
- package/lib/dist/core/classes/Channel.d.ts +29 -29
- package/lib/dist/core/classes/Channel.js +144 -144
- package/lib/dist/core/classes/DpsPipeline.d.ts +59 -59
- package/lib/dist/core/classes/DpsPipeline.js +115 -115
- package/lib/dist/core/classes/Effector.d.ts +11 -7
- package/lib/dist/core/classes/Effector.d.ts.map +1 -1
- package/lib/dist/core/classes/Effector.js +20 -7
- package/lib/dist/core/classes/Master.d.ts +11 -11
- package/lib/dist/core/classes/Master.js +35 -35
- package/lib/dist/core/exports.d.ts +6 -6
- package/lib/dist/core/exports.js +6 -6
- package/lib/dist/effects/classes/Chorus.d.ts +2 -18
- package/lib/dist/effects/classes/Chorus.d.ts.map +1 -1
- package/lib/dist/effects/classes/Chorus.js +2 -83
- package/lib/dist/effects/classes/Distortion.d.ts +2 -2
- package/lib/dist/effects/classes/Distortion.js +2 -2
- package/lib/dist/effects/classes/Equalizer.d.ts +2 -2
- package/lib/dist/effects/classes/Equalizer.js +2 -2
- package/lib/dist/effects/classes/Filter.d.ts +2 -2
- package/lib/dist/effects/classes/Filter.js +2 -2
- package/lib/dist/effects/classes/Limiter.d.ts +2 -2
- package/lib/dist/effects/classes/Limiter.js +2 -2
- package/lib/dist/effects/classes/Saturation.d.ts +2 -2
- package/lib/dist/effects/classes/Saturation.js +2 -2
- package/lib/dist/effects/classes/SoftClip.d.ts +7 -7
- package/lib/dist/effects/classes/SoftClip.d.ts.map +1 -1
- package/lib/dist/effects/classes/SoftClip.js +38 -37
- package/lib/dist/effects/classes/StereoPanner.d.ts +2 -2
- package/lib/dist/effects/classes/StereoPanner.js +2 -2
- package/lib/dist/effects/classes/compressors/Compressor.d.ts +2 -2
- package/lib/dist/effects/classes/compressors/Compressor.js +2 -2
- package/lib/dist/effects/classes/compressors/MultibandCompressor.d.ts +2 -2
- package/lib/dist/effects/classes/compressors/MultibandCompressor.js +2 -2
- package/lib/dist/effects/classes/delays/AdvancedDelay.d.ts +2 -2
- package/lib/dist/effects/classes/delays/AdvancedDelay.js +2 -2
- package/lib/dist/effects/classes/delays/MonoDelay.d.ts +2 -2
- package/lib/dist/effects/classes/delays/MonoDelay.js +2 -2
- package/lib/dist/effects/classes/delays/PingPongDelay.d.ts +2 -2
- package/lib/dist/effects/classes/delays/PingPongDelay.js +2 -2
- package/lib/dist/effects/classes/delays/StereoDelay.d.ts +2 -2
- package/lib/dist/effects/classes/delays/StereoDelay.js +2 -2
- package/lib/dist/effects/classes/reverbs/ChamberReverb.d.ts +2 -2
- package/lib/dist/effects/classes/reverbs/ChamberReverb.js +2 -2
- package/lib/dist/effects/classes/reverbs/ConvolverReverb.d.ts +2 -2
- package/lib/dist/effects/classes/reverbs/ConvolverReverb.js +2 -2
- package/lib/dist/effects/classes/reverbs/GenericReverb.d.ts +2 -2
- package/lib/dist/effects/classes/reverbs/GenericReverb.js +2 -2
- package/lib/dist/effects/classes/reverbs/HallReverb.d.ts +2 -2
- package/lib/dist/effects/classes/reverbs/HallReverb.js +2 -2
- package/lib/dist/effects/classes/reverbs/RoomReverb.d.ts +2 -2
- package/lib/dist/effects/classes/reverbs/RoomReverb.js +2 -2
- package/lib/dist/effects/exports.d.ts +19 -19
- package/lib/dist/effects/exports.js +19 -19
- package/lib/dist/index.d.ts +12 -12
- package/lib/dist/index.d.ts.map +1 -1
- package/lib/dist/index.js +28 -28
- package/lib/dist/typings.d.ts +59 -66
- package/lib/dist/typings.d.ts.map +1 -1
- package/lib/dist/typings.js +1 -1
- package/lib/dist/utilities/constants.d.ts +1 -1
- package/lib/dist/utilities/constants.js +9 -9
- package/lib/dist/utilities/debugger.d.ts +7 -7
- package/lib/dist/utilities/debugger.js +49 -49
- package/lib/dist/utilities/helpers.d.ts +40 -40
- package/lib/dist/utilities/helpers.d.ts.map +1 -1
- package/lib/dist/utilities/helpers.js +143 -148
- package/lib/dist/utilities/web-assembly.d.ts +3 -3
- package/lib/dist/utilities/web-assembly.js +12 -12
- package/lib/src/core/classes/AudioClip.ts +2 -7
- package/lib/src/core/classes/Channel.ts +94 -4
- package/lib/src/core/classes/Effector.ts +2 -0
- package/lib/src/effects/classes/Chorus.ts +3 -0
- package/lib/src/effects/classes/Distortion.ts +14 -1
- package/lib/src/effects/classes/Saturation.ts +3 -1
- package/lib/src/effects/classes/SoftClip.ts +3 -0
- package/lib/src/effects/classes/StereoPanner.ts +3 -1
- package/lib/src/index.ts +1 -0
- package/lib/src/utilities/helpers.ts +28 -6
- package/lib/src/utilities/web-assembly.ts +4 -5
- package/package.json +1 -1
|
@@ -20,11 +20,17 @@ export class Channel {
|
|
|
20
20
|
|
|
21
21
|
public gainNode: GainNode | null = null;
|
|
22
22
|
public stereoPannerNode: StereoPannerNode | null = null;
|
|
23
|
+
public analyserNode: AnalyserNode | null = null;
|
|
24
|
+
public channelSplitterNode: ChannelSplitterNode | null = null;
|
|
25
|
+
|
|
26
|
+
public analyserFloatArrayBuffer = new Float32Array();
|
|
27
|
+
public analyserByteArrayBuffer = new Uint8Array();
|
|
23
28
|
|
|
24
29
|
public audioClipsInputGainNode: GainNode | null = null;
|
|
25
30
|
|
|
26
|
-
|
|
31
|
+
public analyserOptions: AnalyserOptions = { fftSize: 32 };
|
|
27
32
|
|
|
33
|
+
constructor(public options: Partial<ChannelOptions> = { maxAudioNodes: 8, maxEffects: 8 }) {
|
|
28
34
|
this.label = options.label ?? null;
|
|
29
35
|
}
|
|
30
36
|
|
|
@@ -42,7 +48,7 @@ export class Channel {
|
|
|
42
48
|
effect.audioWorkletNode?.disconnect();
|
|
43
49
|
}
|
|
44
50
|
|
|
45
|
-
const activeEffects = this.effects.filter(e => !!e.audioWorkletNode
|
|
51
|
+
const activeEffects = this.effects.filter(e => !!e.audioWorkletNode);
|
|
46
52
|
|
|
47
53
|
if (activeEffects.length === 0) {
|
|
48
54
|
|
|
@@ -53,7 +59,7 @@ export class Channel {
|
|
|
53
59
|
this.audioClipsInputGainNode.connect(firstEffectGain);
|
|
54
60
|
|
|
55
61
|
for (let i = 0; i < activeEffects.length - 1; i++) {
|
|
56
|
-
|
|
62
|
+
|
|
57
63
|
const current = activeEffects[i].audioWorkletNode!;
|
|
58
64
|
const next = activeEffects[i + 1].audioWorkletNode!;
|
|
59
65
|
|
|
@@ -78,12 +84,17 @@ export class Channel {
|
|
|
78
84
|
|
|
79
85
|
this.gainNode = new GainNode(this.parentialContext);
|
|
80
86
|
this.stereoPannerNode = new StereoPannerNode(this.parentialContext);
|
|
87
|
+
this.analyserNode = new AnalyserNode(this.parentialContext, this.analyserOptions);
|
|
88
|
+
|
|
89
|
+
this.analyserFloatArrayBuffer = new Float32Array(this.analyserNode.fftSize);
|
|
90
|
+
this.analyserByteArrayBuffer = new Uint8Array(this.analyserNode.fftSize);
|
|
81
91
|
|
|
82
92
|
this.audioClipsInputGainNode = new GainNode(this.parentialContext);
|
|
83
93
|
|
|
84
94
|
this.audioClipsInputGainNode.connect(this.stereoPannerNode);
|
|
85
95
|
this.stereoPannerNode.connect(this.gainNode);
|
|
86
|
-
this.gainNode.connect(this.
|
|
96
|
+
this.gainNode.connect(this.analyserNode);
|
|
97
|
+
this.analyserNode.connect(this.parentialMasterChannel.gainNode);
|
|
87
98
|
}
|
|
88
99
|
|
|
89
100
|
public SetLabel(label: string): void {
|
|
@@ -131,6 +142,15 @@ export class Channel {
|
|
|
131
142
|
});
|
|
132
143
|
}
|
|
133
144
|
|
|
145
|
+
public HasAudioClip(clip: AudioClip): boolean {
|
|
146
|
+
|
|
147
|
+
for (let _clip of this.audioClips) {
|
|
148
|
+
if (_clip.id === clip.id) return true;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
|
|
134
154
|
public SetVolume(volume: number): void {
|
|
135
155
|
|
|
136
156
|
if (!this.gainNode) return Debug.Error("Could not set channel volume because the channel is not attached to a master channel.", [
|
|
@@ -167,6 +187,10 @@ export class Channel {
|
|
|
167
187
|
this.rebuildEffectChain();
|
|
168
188
|
}
|
|
169
189
|
|
|
190
|
+
public AttachEffect(effect: Effector): void {
|
|
191
|
+
return this.AddEffect(effect);
|
|
192
|
+
}
|
|
193
|
+
|
|
170
194
|
public RemoveEffect(effect: Effector): void {
|
|
171
195
|
|
|
172
196
|
if (!this.effects.includes(effect)) return Debug.Error("Could not remove effect, because it is not part of this channel.", [
|
|
@@ -183,6 +207,72 @@ export class Channel {
|
|
|
183
207
|
this.rebuildEffectChain();
|
|
184
208
|
}
|
|
185
209
|
|
|
210
|
+
public DetachEffect(effect: Effector): void {
|
|
211
|
+
return this.RemoveEffect(effect);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
public SetAnalyserFftSize(value: number): number | null {
|
|
215
|
+
|
|
216
|
+
if (!this.analyserNode) {
|
|
217
|
+
Debug.Error("Could not set FFT size on analyser because the analyser has not been defined.");
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
this.analyserNode.fftSize = value;
|
|
222
|
+
|
|
223
|
+
this.analyserFloatArrayBuffer = new Float32Array(this.analyserNode.fftSize);
|
|
224
|
+
this.analyserByteArrayBuffer = new Uint8Array(this.analyserNode.fftSize);
|
|
225
|
+
|
|
226
|
+
return this.analyserNode.fftSize;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
public GetWaveformFloatData(): Float32Array | null {
|
|
230
|
+
|
|
231
|
+
if (!this.analyserNode) {
|
|
232
|
+
Debug.Error("Could not get waveform float data, because the analyser has not been defined.");
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (this.analyserFloatArrayBuffer.length !== this.analyserNode.fftSize) {
|
|
237
|
+
this.analyserFloatArrayBuffer = new Float32Array(this.analyserNode.fftSize);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
this.analyserNode.getFloatTimeDomainData(this.analyserFloatArrayBuffer);
|
|
241
|
+
return this.analyserFloatArrayBuffer;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
public GetWaveformByteData(): Uint8Array | null {
|
|
245
|
+
|
|
246
|
+
if (!this.analyserNode) {
|
|
247
|
+
Debug.Error("Could not get waveform byte data, because the analyser has not been defined.");
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (this.analyserByteArrayBuffer.length !== this.analyserNode.fftSize) {
|
|
252
|
+
this.analyserByteArrayBuffer = new Uint8Array(this.analyserNode.fftSize);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
this.analyserNode.getByteTimeDomainData(this.analyserByteArrayBuffer);
|
|
256
|
+
return this.analyserByteArrayBuffer;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
public SetAnalyserOptions(options: AnalyserOptions): Channel | null {
|
|
260
|
+
|
|
261
|
+
this.analyserOptions = {...options};
|
|
262
|
+
|
|
263
|
+
if (!this.analyserNode) return null;
|
|
264
|
+
|
|
265
|
+
this.analyserNode.minDecibels = options.minDecibels ?? this.analyserNode.minDecibels;
|
|
266
|
+
this.analyserNode.maxDecibels = options.maxDecibels ?? this.analyserNode.maxDecibels;
|
|
267
|
+
this.analyserNode.fftSize = options.fftSize ?? 32;
|
|
268
|
+
this.analyserNode.smoothingTimeConstant = options.smoothingTimeConstant ?? this.analyserNode.smoothingTimeConstant;
|
|
269
|
+
|
|
270
|
+
this.analyserByteArrayBuffer = new Uint8Array(this.analyserNode.fftSize);
|
|
271
|
+
this.analyserFloatArrayBuffer = new Float32Array(this.analyserNode.fftSize);
|
|
272
|
+
|
|
273
|
+
return this;
|
|
274
|
+
}
|
|
275
|
+
|
|
186
276
|
// Public getters and setters
|
|
187
277
|
|
|
188
278
|
public get volume(): number | null {
|
|
@@ -7,5 +7,7 @@ export abstract class Effector {
|
|
|
7
7
|
public audioWorkletNode: AudioWorkletNode | null = null;
|
|
8
8
|
public parentialContext: AudioContext | null = null;
|
|
9
9
|
|
|
10
|
+
static name: string = "Effector";
|
|
11
|
+
|
|
10
12
|
public abstract InitializeOnAttachment(parentialContext: AudioContext): Promise<void>;
|
|
11
13
|
}
|
|
@@ -5,6 +5,9 @@ import { ChorusEffectOptions } from "../../typings";
|
|
|
5
5
|
|
|
6
6
|
export class Chorus extends Effector {
|
|
7
7
|
|
|
8
|
+
public label: string | null = "Chorus";
|
|
9
|
+
static name: string = "Chorus";
|
|
10
|
+
|
|
8
11
|
public baseDelayMs: number = 15;
|
|
9
12
|
public depthMs: number = 8;
|
|
10
13
|
public rateHz: number = 1.5;
|
|
@@ -1 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
import { Effector } from "../../core/classes/Effector";
|
|
2
|
+
|
|
3
|
+
export class Distortion extends Effector {
|
|
4
|
+
|
|
5
|
+
static name: string = "Distortion";
|
|
6
|
+
|
|
7
|
+
constructor() {
|
|
8
|
+
super();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public async InitializeOnAttachment(parentialContext: AudioContext): Promise<void> {
|
|
12
|
+
|
|
13
|
+
}
|
|
14
|
+
}
|
package/lib/src/index.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { v4 } from "uuid";
|
|
|
3
3
|
|
|
4
4
|
import { AudioDevice } from "../core/classes/AudioDevice";
|
|
5
5
|
import { Master } from "../core/classes/Master";
|
|
6
|
+
import { Effector } from "../core/classes/Effector";
|
|
6
7
|
|
|
7
8
|
import { Debug } from "./debugger";
|
|
8
9
|
import { SUPPORTED_FILE_TYPES } from "./constants";
|
|
@@ -10,6 +11,10 @@ import { SUPPORTED_FILE_TYPES } from "./constants";
|
|
|
10
11
|
import { LoadWebAssemblyModule } from "./web-assembly";
|
|
11
12
|
import { ErrorCodes, WarningCodes } from "../console-codes";
|
|
12
13
|
|
|
14
|
+
import { Chorus, SoftClip } from "../effects/exports";
|
|
15
|
+
|
|
16
|
+
import * as Effects from "../effects/exports";
|
|
17
|
+
|
|
13
18
|
import { LoadAudioSourceOptions, AudioSourceData, DspPipelineInitializationOptions, DspPipelineInitializationState } from "../typings";
|
|
14
19
|
|
|
15
20
|
/**
|
|
@@ -99,7 +104,7 @@ export async function ResolveAudioInputDevices(): Promise<AudioDevice[]> {
|
|
|
99
104
|
*/
|
|
100
105
|
export async function ResolveDefaultAudioOutputDevice(init: DspPipelineInitializationState): Promise<AudioDevice | null> {
|
|
101
106
|
Debug.Log("Attempting to resolve default audio output device...");
|
|
102
|
-
|
|
107
|
+
|
|
103
108
|
const audioDeviceInfos: MediaDeviceInfo[] = [];
|
|
104
109
|
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
105
110
|
|
|
@@ -111,7 +116,7 @@ export async function ResolveDefaultAudioOutputDevice(init: DspPipelineInitializ
|
|
|
111
116
|
|
|
112
117
|
const defaultAudioDevice = devices.length === 0 ? null : new AudioDevice(audioDeviceInfos[0]);
|
|
113
118
|
|
|
114
|
-
if(!defaultAudioDevice) return null;
|
|
119
|
+
if (!defaultAudioDevice) return null;
|
|
115
120
|
|
|
116
121
|
await LoadWorkletOnMasterChannel(defaultAudioDevice.masterChannel, init.workletBlobUrl);
|
|
117
122
|
|
|
@@ -124,7 +129,7 @@ export async function ResolveDefaultAudioOutputDevice(init: DspPipelineInitializ
|
|
|
124
129
|
*/
|
|
125
130
|
export async function ResolveDefaultAudioInputDevice(init: DspPipelineInitializationState): Promise<AudioDevice | null> {
|
|
126
131
|
Debug.Log("Attempting to resolve default audio output device...");
|
|
127
|
-
|
|
132
|
+
|
|
128
133
|
const audioDeviceInfos: MediaDeviceInfo[] = [];
|
|
129
134
|
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
130
135
|
|
|
@@ -136,7 +141,7 @@ export async function ResolveDefaultAudioInputDevice(init: DspPipelineInitializa
|
|
|
136
141
|
|
|
137
142
|
const defaultAudioDevice = devices.length === 0 ? null : new AudioDevice(audioDeviceInfos[0]);
|
|
138
143
|
|
|
139
|
-
if(!defaultAudioDevice) return null;
|
|
144
|
+
if (!defaultAudioDevice) return null;
|
|
140
145
|
|
|
141
146
|
await LoadWorkletOnMasterChannel(defaultAudioDevice.masterChannel, init.workletBlobUrl);
|
|
142
147
|
|
|
@@ -187,6 +192,23 @@ export async function LoadAudioSource(path: string, options: Partial<LoadAudioSo
|
|
|
187
192
|
}
|
|
188
193
|
}
|
|
189
194
|
|
|
195
|
+
/**
|
|
196
|
+
* Loads an audio file from a blob.
|
|
197
|
+
*/
|
|
198
|
+
export async function LoadAudioSourceFromBlob(blob: Blob): Promise<AudioSourceData | null> {
|
|
199
|
+
|
|
200
|
+
const tempContext: AudioContext = new AudioContext(),
|
|
201
|
+
arrayBuffer: ArrayBuffer = await blob.arrayBuffer();
|
|
202
|
+
|
|
203
|
+
const audioBuffer: AudioBuffer = await tempContext.decodeAudioData(arrayBuffer);
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
id: v4(),
|
|
207
|
+
timestamp: Date.now(),
|
|
208
|
+
audioBuffer, arrayBuffer
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
190
212
|
export function ConstructProcessorWorklet(code: string): string {
|
|
191
213
|
|
|
192
214
|
const blob = new Blob([code], {
|
|
@@ -197,7 +219,7 @@ export function ConstructProcessorWorklet(code: string): string {
|
|
|
197
219
|
}
|
|
198
220
|
|
|
199
221
|
export async function LoadWorkletOnMasterChannel(master: Master, workletBlobUrl: string) {
|
|
200
|
-
Debug.Log("Loading worklet modules on master channel...", [
|
|
222
|
+
Debug.Log("Loading worklet modules on master channel...", [`Channel ID: ${master.id}`]);
|
|
201
223
|
|
|
202
224
|
const context: AudioContext = master.context,
|
|
203
225
|
start: number = Date.now();
|
|
@@ -212,4 +234,4 @@ export async function LoadWorkletOnMasterChannel(master: Master, workletBlobUrl:
|
|
|
212
234
|
]);
|
|
213
235
|
|
|
214
236
|
return true;
|
|
215
|
-
}
|
|
237
|
+
}
|
|
@@ -2,13 +2,12 @@ export let hasInitializedWasm: boolean = false;
|
|
|
2
2
|
export let compiledWebAssemblyModule: WebAssembly.Module | null = null;
|
|
3
3
|
|
|
4
4
|
export async function LoadWebAssemblyModule(path: string): Promise<WebAssembly.Module> {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
WebAssembly.compileStreaming(fetch(path)).then(function(module: WebAssembly.Module) {
|
|
5
|
+
return new Promise(function (resolve, reject) {
|
|
6
|
+
WebAssembly.compileStreaming(fetch(path)).then(function (module: WebAssembly.Module) {
|
|
8
7
|
compiledWebAssemblyModule = module;
|
|
9
8
|
resolve(module);
|
|
10
|
-
}).catch(function(error: Error) {
|
|
9
|
+
}).catch(function (error: Error) {
|
|
11
10
|
reject(error);
|
|
12
11
|
});
|
|
13
|
-
})
|
|
12
|
+
});
|
|
14
13
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluex/fluexgl-dsp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "An open-source, web-based DSP library developed alongside FluexGL, designed for creating and manipulating sounds in various contexts.",
|
|
5
5
|
"main": "lib/dist/index.js",
|
|
6
6
|
"types": "lib/dist/index.d.ts",
|