@fluex/fluexgl-dsp 0.4.6 → 0.4.8
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 +7 -7
- package/lib/dist/console-codes.d.ts +2 -1
- package/lib/dist/console-codes.d.ts.map +1 -1
- package/lib/dist/console-codes.js +1 -0
- package/lib/dist/core/classes/AudioClip.d.ts +27 -16
- package/lib/dist/core/classes/AudioClip.d.ts.map +1 -1
- package/lib/dist/core/classes/AudioClip.js +133 -48
- package/lib/dist/core/classes/AudioClipPlayer.d.ts +8 -8
- package/lib/dist/core/classes/AudioClipPlayer.d.ts.map +1 -1
- package/lib/dist/core/classes/AudioClipPlayer.js +22 -24
- package/lib/dist/core/classes/AudioDevice.d.ts +46 -5
- package/lib/dist/core/classes/AudioDevice.d.ts.map +1 -1
- package/lib/dist/core/classes/AudioDevice.js +47 -6
- package/lib/dist/core/classes/Channel.d.ts +20 -20
- package/lib/dist/core/classes/Channel.d.ts.map +1 -1
- package/lib/dist/core/classes/Channel.js +42 -42
- package/lib/dist/core/classes/DpsPipeline.d.ts +6 -6
- package/lib/dist/core/classes/DpsPipeline.d.ts.map +1 -1
- package/lib/dist/core/classes/DpsPipeline.js +18 -18
- package/lib/dist/core/classes/Effector.d.ts +5 -5
- package/lib/dist/core/classes/Effector.d.ts.map +1 -1
- package/lib/dist/core/classes/Effector.js +8 -8
- package/lib/dist/core/classes/Master.d.ts +6 -6
- package/lib/dist/core/classes/Master.d.ts.map +1 -1
- package/lib/dist/core/classes/Master.js +18 -18
- package/lib/dist/effects/classes/Analyser.d.ts +10 -6
- package/lib/dist/effects/classes/Analyser.d.ts.map +1 -1
- package/lib/dist/effects/classes/Analyser.js +29 -13
- package/lib/dist/effects/classes/Chorus.d.ts +7 -7
- package/lib/dist/effects/classes/Chorus.d.ts.map +1 -1
- package/lib/dist/effects/classes/Chorus.js +25 -25
- package/lib/dist/effects/classes/Distortion.d.ts +1 -1
- package/lib/dist/effects/classes/Distortion.d.ts.map +1 -1
- package/lib/dist/effects/classes/Distortion.js +1 -1
- package/lib/dist/effects/classes/Reverb.d.ts +32 -0
- package/lib/dist/effects/classes/Reverb.d.ts.map +1 -0
- package/lib/dist/effects/classes/Reverb.js +61 -0
- package/lib/dist/effects/classes/clips/HardClip.d.ts +5 -5
- package/lib/dist/effects/classes/clips/HardClip.d.ts.map +1 -1
- package/lib/dist/effects/classes/clips/HardClip.js +14 -14
- package/lib/dist/effects/classes/clips/SoftClip.d.ts +4 -4
- package/lib/dist/effects/classes/clips/SoftClip.d.ts.map +1 -1
- package/lib/dist/effects/classes/clips/SoftClip.js +13 -13
- package/lib/dist/effects/classes/filters/HighPassFilter.d.ts +18 -0
- package/lib/dist/effects/classes/filters/HighPassFilter.d.ts.map +1 -0
- package/lib/dist/effects/classes/filters/HighPassFilter.js +59 -0
- package/lib/dist/effects/classes/filters/LowPassFilter.d.ts +5 -5
- package/lib/dist/effects/classes/filters/LowPassFilter.d.ts.map +1 -1
- package/lib/dist/effects/classes/filters/LowPassFilter.js +17 -17
- package/lib/dist/effects/classes/filters/NotchFilter.d.ts +18 -0
- package/lib/dist/effects/classes/filters/NotchFilter.d.ts.map +1 -0
- package/lib/dist/effects/classes/filters/NotchFilter.js +59 -0
- package/lib/dist/effects/exports.d.ts +2 -5
- package/lib/dist/effects/exports.d.ts.map +1 -1
- package/lib/dist/effects/exports.js +2 -5
- package/lib/dist/index.d.ts +4 -4
- package/lib/dist/index.d.ts.map +1 -1
- package/lib/dist/index.js +3 -3
- package/lib/dist/typings.d.ts +33 -0
- package/lib/dist/typings.d.ts.map +1 -1
- package/lib/dist/typings.js +12 -0
- package/lib/dist/utilities/constants.d.ts +1 -0
- package/lib/dist/utilities/constants.d.ts.map +1 -1
- package/lib/dist/utilities/constants.js +1 -0
- package/lib/dist/utilities/debugger.d.ts +4 -4
- package/lib/dist/utilities/debugger.js +8 -8
- package/lib/dist/utilities/helpers.d.ts +13 -13
- package/lib/dist/utilities/helpers.d.ts.map +1 -1
- package/lib/dist/utilities/helpers.js +45 -59
- package/lib/dist/utilities/web-assembly.js +1 -1
- package/lib/src/console-codes.ts +2 -1
- package/lib/src/core/classes/AudioClip.ts +166 -55
- package/lib/src/core/classes/AudioClipPlayer.ts +22 -24
- package/lib/src/core/classes/AudioDevice.ts +49 -6
- package/lib/src/core/classes/Channel.ts +42 -42
- package/lib/src/core/classes/DpsPipeline.ts +19 -19
- package/lib/src/core/classes/Effector.ts +9 -9
- package/lib/src/core/classes/Master.ts +18 -18
- package/lib/src/effects/classes/Analyser.ts +33 -13
- package/lib/src/effects/classes/Chorus.ts +25 -25
- package/lib/src/effects/classes/Distortion.ts +1 -1
- package/lib/src/effects/classes/Reverb.ts +81 -0
- package/lib/src/effects/classes/clips/HardClip.ts +14 -14
- package/lib/src/effects/classes/clips/SoftClip.ts +13 -13
- package/lib/src/effects/classes/filters/HighPassFilter.ts +81 -0
- package/lib/src/effects/classes/filters/LowPassFilter.ts +17 -17
- package/lib/src/effects/classes/filters/NotchFilter.ts +81 -0
- package/lib/src/effects/exports.ts +2 -6
- package/lib/src/index.ts +15 -17
- package/lib/src/typings.ts +39 -1
- package/lib/src/utilities/constants.ts +3 -1
- package/lib/src/utilities/debugger.ts +4 -4
- package/lib/src/utilities/helpers.ts +47 -60
- package/lib/src/utilities/web-assembly.ts +1 -1
- package/package.json +3 -2
- package/lib/src/effects/classes/reverbs/ChamberReverb.ts +0 -1
- package/lib/src/effects/classes/reverbs/ConvolverReverb.ts +0 -1
- package/lib/src/effects/classes/reverbs/GenericReverb.ts +0 -1
- package/lib/src/effects/classes/reverbs/HallReverb.ts +0 -1
- package/lib/src/effects/classes/reverbs/RoomReverb.ts +0 -1
|
@@ -19,8 +19,8 @@ import { LoadAudioSourceOptions, AudioSourceData, DspPipelineInitializationOptio
|
|
|
19
19
|
* FluexGL DSP cannot be used without calling this function first.
|
|
20
20
|
* @returns
|
|
21
21
|
*/
|
|
22
|
-
export async function
|
|
23
|
-
Debug.
|
|
22
|
+
export async function initializeDspPipeline(options: DspPipelineInitializationOptions): Promise<DspPipelineInitializationState | null> {
|
|
23
|
+
Debug.log("Attempting to initialize DSP pipeline...");
|
|
24
24
|
|
|
25
25
|
const start: number = Date.now();
|
|
26
26
|
let initialized: boolean = true;
|
|
@@ -29,7 +29,7 @@ export async function InitializeDspPipeline(options: DspPipelineInitializationOp
|
|
|
29
29
|
|
|
30
30
|
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
31
31
|
|
|
32
|
-
Debug.
|
|
32
|
+
Debug.log(`Found ${stream.getTracks().length} media stream tracks.`);
|
|
33
33
|
|
|
34
34
|
stream.getTracks().forEach(function (track: MediaStreamTrack) {
|
|
35
35
|
track.stop();
|
|
@@ -38,7 +38,7 @@ export async function InitializeDspPipeline(options: DspPipelineInitializationOp
|
|
|
38
38
|
|
|
39
39
|
initialized = false;
|
|
40
40
|
|
|
41
|
-
Debug.
|
|
41
|
+
Debug.error("Permission to access media devices has not been granted.", [
|
|
42
42
|
"Make sure the user has granted FluentGL permission to access media devices."
|
|
43
43
|
], ErrorCodes.NO_CONTEXT_PERMISSION)
|
|
44
44
|
}
|
|
@@ -48,12 +48,12 @@ export async function InitializeDspPipeline(options: DspPipelineInitializationOp
|
|
|
48
48
|
const workletFileRequest = await fetch(options.pathToWorklet);
|
|
49
49
|
const textContent: string = await workletFileRequest.text();
|
|
50
50
|
|
|
51
|
-
const blobUrl: string =
|
|
51
|
+
const blobUrl: string = constructProcessorWorklet(textContent);
|
|
52
52
|
|
|
53
53
|
const end: number = Date.now(),
|
|
54
54
|
difference: number = end - start;
|
|
55
55
|
|
|
56
|
-
Debug.
|
|
56
|
+
Debug.success(`Succesfully initialized DSP pipeline within ${difference}ms.`);
|
|
57
57
|
|
|
58
58
|
return {
|
|
59
59
|
success: true,
|
|
@@ -65,7 +65,7 @@ export async function InitializeDspPipeline(options: DspPipelineInitializationOp
|
|
|
65
65
|
* Resolves a list of available audio output devices.
|
|
66
66
|
* @returns
|
|
67
67
|
*/
|
|
68
|
-
export async function
|
|
68
|
+
export async function resolveAudioOutputDevices(): Promise<AudioDevice[]> {
|
|
69
69
|
|
|
70
70
|
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
71
71
|
|
|
@@ -81,7 +81,7 @@ export async function ResolveAudioOutputDevices(): Promise<AudioDevice[]> {
|
|
|
81
81
|
* Resolves a list of available audio input devices.
|
|
82
82
|
* @returns
|
|
83
83
|
*/
|
|
84
|
-
export async function
|
|
84
|
+
export async function resolveAudioInputDevices(): Promise<AudioDevice[]> {
|
|
85
85
|
|
|
86
86
|
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
87
87
|
|
|
@@ -97,8 +97,8 @@ export async function ResolveAudioInputDevices(): Promise<AudioDevice[]> {
|
|
|
97
97
|
* Resolves the default audio output device.
|
|
98
98
|
* @returns
|
|
99
99
|
*/
|
|
100
|
-
export async function
|
|
101
|
-
Debug.
|
|
100
|
+
export async function resolveDefaultAudioOutputDevice(init: DspPipelineInitializationState): Promise<AudioDevice | null> {
|
|
101
|
+
Debug.log("Attempting to resolve default audio output device...");
|
|
102
102
|
|
|
103
103
|
const audioDeviceInfos: MediaDeviceInfo[] = [];
|
|
104
104
|
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
@@ -107,13 +107,13 @@ export async function ResolveDefaultAudioOutputDevice(init: DspPipelineInitializ
|
|
|
107
107
|
(device.kind === "audiooutput" && device.deviceId == "default")
|
|
108
108
|
&& audioDeviceInfos.push(device);
|
|
109
109
|
|
|
110
|
-
devices.length === 0 && Debug.
|
|
110
|
+
devices.length === 0 && Debug.warn("No default audio device found.", [], WarningCodes.NO_DEFAULT_AUDIO_DEVICE_FOUND);
|
|
111
111
|
|
|
112
112
|
const defaultAudioDevice = devices.length === 0 ? null : new AudioDevice(audioDeviceInfos[0]);
|
|
113
113
|
|
|
114
114
|
if (!defaultAudioDevice) return null;
|
|
115
115
|
|
|
116
|
-
await
|
|
116
|
+
await loadWorkletOnAudioDevice(defaultAudioDevice, init.workletBlobUrl);
|
|
117
117
|
|
|
118
118
|
return defaultAudioDevice;
|
|
119
119
|
}
|
|
@@ -122,8 +122,8 @@ export async function ResolveDefaultAudioOutputDevice(init: DspPipelineInitializ
|
|
|
122
122
|
* Resolves the default audio input device.
|
|
123
123
|
* @returns
|
|
124
124
|
*/
|
|
125
|
-
export async function
|
|
126
|
-
Debug.
|
|
125
|
+
export async function resolveDefaultAudioInputDevice(init: DspPipelineInitializationState): Promise<AudioDevice | null> {
|
|
126
|
+
Debug.log("Attempting to resolve default audio output device...");
|
|
127
127
|
|
|
128
128
|
const audioDeviceInfos: MediaDeviceInfo[] = [];
|
|
129
129
|
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
@@ -132,13 +132,13 @@ export async function ResolveDefaultAudioInputDevice(init: DspPipelineInitializa
|
|
|
132
132
|
(device.kind === "audioinput" && device.deviceId == "default")
|
|
133
133
|
&& audioDeviceInfos.push(device);
|
|
134
134
|
|
|
135
|
-
devices.length === 0 && Debug.
|
|
135
|
+
devices.length === 0 && Debug.warn("No default audio device found.", [], WarningCodes.NO_DEFAULT_AUDIO_DEVICE_FOUND);
|
|
136
136
|
|
|
137
137
|
const defaultAudioDevice = devices.length === 0 ? null : new AudioDevice(audioDeviceInfos[0]);
|
|
138
138
|
|
|
139
139
|
if (!defaultAudioDevice) return null;
|
|
140
140
|
|
|
141
|
-
await
|
|
141
|
+
await loadWorkletOnAudioDevice(defaultAudioDevice, init.workletBlobUrl);
|
|
142
142
|
|
|
143
143
|
return defaultAudioDevice;
|
|
144
144
|
}
|
|
@@ -149,25 +149,25 @@ export async function ResolveDefaultAudioInputDevice(init: DspPipelineInitializa
|
|
|
149
149
|
* @param options
|
|
150
150
|
* @returns
|
|
151
151
|
*/
|
|
152
|
-
export async function
|
|
152
|
+
export async function loadAudioSource(path: string, options: Partial<LoadAudioSourceOptions> = { allowForeignFileTypes: false }): Promise<AudioSourceData | null> {
|
|
153
153
|
|
|
154
154
|
const extension: string | null = mime.getType(path);
|
|
155
155
|
|
|
156
156
|
if (!extension && !options.allowForeignFileTypes) {
|
|
157
157
|
|
|
158
|
-
Debug.
|
|
158
|
+
Debug.error("The file type of the specified file could not be identified.", [
|
|
159
159
|
`Set allowForeignFileTypes to true in the properties to allow foreign or unknown file types.`
|
|
160
160
|
], ErrorCodes.NO_FILE_TYPE_FOUND);
|
|
161
161
|
return null;
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
if (!SUPPORTED_FILE_TYPES.includes(extension as string)) Debug.
|
|
164
|
+
if (!SUPPORTED_FILE_TYPES.includes(extension as string)) Debug.warn("The file type of the specified file is unknown and possibly unknown, but will be used anyways.");
|
|
165
165
|
|
|
166
166
|
const file = await fetch(path, { method: "get" });
|
|
167
167
|
|
|
168
168
|
if (file.status !== 200) {
|
|
169
169
|
|
|
170
|
-
Debug.
|
|
170
|
+
Debug.error("The specified file could not be loaded.", [
|
|
171
171
|
`Received status code: ${file.status}.`
|
|
172
172
|
], ErrorCodes.PATH_TO_FILE_NOT_FOUND);
|
|
173
173
|
return null;
|
|
@@ -190,7 +190,7 @@ export async function LoadAudioSource(path: string, options: Partial<LoadAudioSo
|
|
|
190
190
|
/**
|
|
191
191
|
* Loads an audio file from a blob.
|
|
192
192
|
*/
|
|
193
|
-
export async function
|
|
193
|
+
export async function loadAudioSourceFromBlob(blob: Blob): Promise<AudioSourceData | null> {
|
|
194
194
|
|
|
195
195
|
const tempContext: AudioContext = new AudioContext(),
|
|
196
196
|
arrayBuffer: ArrayBuffer = await blob.arrayBuffer();
|
|
@@ -204,7 +204,7 @@ export async function LoadAudioSourceFromBlob(blob: Blob): Promise<AudioSourceDa
|
|
|
204
204
|
};
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
-
export function
|
|
207
|
+
export function constructProcessorWorklet(code: string): string {
|
|
208
208
|
|
|
209
209
|
const blob = new Blob([code], {
|
|
210
210
|
type: "application/javascript"
|
|
@@ -213,8 +213,8 @@ export function ConstructProcessorWorklet(code: string): string {
|
|
|
213
213
|
return URL.createObjectURL(blob);
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
-
export async function
|
|
217
|
-
Debug.
|
|
216
|
+
export async function loadWorkletOnAudioDevice(audioDevice: AudioDevice, workletBlobUrl: string) {
|
|
217
|
+
Debug.log("Loading worklet modules on master channel...", [`Channel ID: ${audioDevice.id}`]);
|
|
218
218
|
|
|
219
219
|
const context: AudioContext = audioDevice.context,
|
|
220
220
|
start: number = Date.now();
|
|
@@ -224,19 +224,19 @@ export async function LoadWorkletOnAudioDevice(audioDevice: AudioDevice, worklet
|
|
|
224
224
|
const end: number = Date.now(),
|
|
225
225
|
difference: number = end - start;
|
|
226
226
|
|
|
227
|
-
Debug.
|
|
227
|
+
Debug.success("Succesfully loaded audio processor worklets into master channel.", [
|
|
228
228
|
`Executed in ${difference}ms.`,
|
|
229
229
|
]);
|
|
230
230
|
|
|
231
231
|
return true;
|
|
232
232
|
}
|
|
233
233
|
|
|
234
|
-
export function
|
|
234
|
+
export function sendMessageToWorklet<T, K = any>(node: AudioWorkletNode | null, commandId: T, data: K) {
|
|
235
235
|
|
|
236
236
|
if (!node) return false;
|
|
237
237
|
|
|
238
238
|
if (typeof data === "number" && !Number.isFinite(data)) {
|
|
239
|
-
Debug.
|
|
239
|
+
Debug.warn("Refusing to send non-finite numeric value to AudioWorkletNode.", [
|
|
240
240
|
`Command: ${String(commandId)}`,
|
|
241
241
|
`Value: ${String(data)}`
|
|
242
242
|
]);
|
|
@@ -248,42 +248,29 @@ export function SendMessageToWorklet<T, K = any>(node: AudioWorkletNode | null,
|
|
|
248
248
|
return true;
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
-
export function
|
|
251
|
+
export function isFiniteNumber(value: unknown): value is number {
|
|
252
252
|
return typeof value === "number" && Number.isFinite(value);
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
-
export function
|
|
256
|
-
return
|
|
255
|
+
export function coerceFiniteNumber(value: unknown, fallback: number): number {
|
|
256
|
+
return isFiniteNumber(value) ? value : fallback;
|
|
257
257
|
}
|
|
258
258
|
|
|
259
|
-
export function
|
|
260
|
-
|
|
261
|
-
if (!compiledWebAssemblyModule)
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
},
|
|
277
|
-
processorOptions: {
|
|
278
|
-
module: compiledWebAssemblyModule
|
|
279
|
-
}
|
|
280
|
-
});
|
|
281
|
-
} catch (err) {
|
|
282
|
-
Debug.Error("Failed to create audio worklet node.", [
|
|
283
|
-
`Request audio worklet node: ${name}.`,
|
|
284
|
-
"Make sure you called InitializeDspPipeline/InitializeDpsPipeline and loaded the worklet module on the same AudioContext.",
|
|
285
|
-
String(err)
|
|
286
|
-
]);
|
|
287
|
-
return null;
|
|
288
|
-
}
|
|
259
|
+
export function createAudioWorkletNode<T = any>(context: AudioContext, name: AudioWorkletProcessorNames | string, data: T): AudioWorkletNode {
|
|
260
|
+
|
|
261
|
+
if (!compiledWebAssemblyModule)
|
|
262
|
+
throw new Error("Coult not create audio worklet node. WebAssembly has not been compiled yet.")
|
|
263
|
+
|
|
264
|
+
return new AudioWorkletNode(context, name, {
|
|
265
|
+
numberOfInputs: 1,
|
|
266
|
+
numberOfOutputs: 1,
|
|
267
|
+
outputChannelCount: [2],
|
|
268
|
+
parameterData: {
|
|
269
|
+
...data,
|
|
270
|
+
sampleRate: context.sampleRate
|
|
271
|
+
},
|
|
272
|
+
processorOptions: {
|
|
273
|
+
module: compiledWebAssemblyModule
|
|
274
|
+
}
|
|
275
|
+
});
|
|
289
276
|
}
|
|
@@ -11,7 +11,7 @@ export async function LoadWebAssemblyModule(path: string): Promise<WebAssembly.M
|
|
|
11
11
|
resolve(module);
|
|
12
12
|
}).catch(function (error: Error) {
|
|
13
13
|
|
|
14
|
-
Debug.
|
|
14
|
+
Debug.error("Failed to load WebAssembly module from path: " + path, [
|
|
15
15
|
"Make sure the path is correct and the server is serving the .wasm file with the correct MIME type (application/wasm).",
|
|
16
16
|
"Error details: " + error.message
|
|
17
17
|
], ErrorCodes.WASM_COMPILATION_ERROR);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluex/fluexgl-dsp",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.8",
|
|
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",
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"mime": "^4.1.0",
|
|
32
32
|
"terser": "^5.44.0",
|
|
33
33
|
"truncate": "^3.0.0",
|
|
34
|
+
"typescript": "^7.0.2",
|
|
34
35
|
"uuid": "^13.0.0"
|
|
35
36
|
},
|
|
36
37
|
"devDependencies": {
|
|
@@ -49,4 +50,4 @@
|
|
|
49
50
|
"url": "https://github.com/rohankanhaisingh/FluexGL-DSP/issues"
|
|
50
51
|
},
|
|
51
52
|
"homepage": "https://github.com/rohankanhaisingh/FluexGL-DSP#readme"
|
|
52
|
-
}
|
|
53
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export class ChamberReverb {}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export class ConvolverReverb {}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export class GenericReverb {}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export class HallReverb {}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export class RoomReverb {}
|