@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.
Files changed (88) hide show
  1. package/README.md +1 -1
  2. package/lib/dist/console-codes.d.ts +13 -13
  3. package/lib/dist/console-codes.js +16 -16
  4. package/lib/dist/core/classes/AudioClip.d.ts +62 -66
  5. package/lib/dist/core/classes/AudioClip.d.ts.map +1 -1
  6. package/lib/dist/core/classes/AudioClip.js +386 -410
  7. package/lib/dist/core/classes/AudioDevice.d.ts +12 -12
  8. package/lib/dist/core/classes/AudioDevice.js +30 -30
  9. package/lib/dist/core/classes/Channel.d.ts +29 -29
  10. package/lib/dist/core/classes/Channel.js +144 -144
  11. package/lib/dist/core/classes/DpsPipeline.d.ts +59 -59
  12. package/lib/dist/core/classes/DpsPipeline.js +115 -115
  13. package/lib/dist/core/classes/Effector.d.ts +11 -7
  14. package/lib/dist/core/classes/Effector.d.ts.map +1 -1
  15. package/lib/dist/core/classes/Effector.js +20 -7
  16. package/lib/dist/core/classes/Master.d.ts +11 -11
  17. package/lib/dist/core/classes/Master.js +35 -35
  18. package/lib/dist/core/exports.d.ts +6 -6
  19. package/lib/dist/core/exports.js +6 -6
  20. package/lib/dist/effects/classes/Chorus.d.ts +2 -18
  21. package/lib/dist/effects/classes/Chorus.d.ts.map +1 -1
  22. package/lib/dist/effects/classes/Chorus.js +2 -83
  23. package/lib/dist/effects/classes/Distortion.d.ts +2 -2
  24. package/lib/dist/effects/classes/Distortion.js +2 -2
  25. package/lib/dist/effects/classes/Equalizer.d.ts +2 -2
  26. package/lib/dist/effects/classes/Equalizer.js +2 -2
  27. package/lib/dist/effects/classes/Filter.d.ts +2 -2
  28. package/lib/dist/effects/classes/Filter.js +2 -2
  29. package/lib/dist/effects/classes/Limiter.d.ts +2 -2
  30. package/lib/dist/effects/classes/Limiter.js +2 -2
  31. package/lib/dist/effects/classes/Saturation.d.ts +2 -2
  32. package/lib/dist/effects/classes/Saturation.js +2 -2
  33. package/lib/dist/effects/classes/SoftClip.d.ts +7 -7
  34. package/lib/dist/effects/classes/SoftClip.d.ts.map +1 -1
  35. package/lib/dist/effects/classes/SoftClip.js +38 -37
  36. package/lib/dist/effects/classes/StereoPanner.d.ts +2 -2
  37. package/lib/dist/effects/classes/StereoPanner.js +2 -2
  38. package/lib/dist/effects/classes/compressors/Compressor.d.ts +2 -2
  39. package/lib/dist/effects/classes/compressors/Compressor.js +2 -2
  40. package/lib/dist/effects/classes/compressors/MultibandCompressor.d.ts +2 -2
  41. package/lib/dist/effects/classes/compressors/MultibandCompressor.js +2 -2
  42. package/lib/dist/effects/classes/delays/AdvancedDelay.d.ts +2 -2
  43. package/lib/dist/effects/classes/delays/AdvancedDelay.js +2 -2
  44. package/lib/dist/effects/classes/delays/MonoDelay.d.ts +2 -2
  45. package/lib/dist/effects/classes/delays/MonoDelay.js +2 -2
  46. package/lib/dist/effects/classes/delays/PingPongDelay.d.ts +2 -2
  47. package/lib/dist/effects/classes/delays/PingPongDelay.js +2 -2
  48. package/lib/dist/effects/classes/delays/StereoDelay.d.ts +2 -2
  49. package/lib/dist/effects/classes/delays/StereoDelay.js +2 -2
  50. package/lib/dist/effects/classes/reverbs/ChamberReverb.d.ts +2 -2
  51. package/lib/dist/effects/classes/reverbs/ChamberReverb.js +2 -2
  52. package/lib/dist/effects/classes/reverbs/ConvolverReverb.d.ts +2 -2
  53. package/lib/dist/effects/classes/reverbs/ConvolverReverb.js +2 -2
  54. package/lib/dist/effects/classes/reverbs/GenericReverb.d.ts +2 -2
  55. package/lib/dist/effects/classes/reverbs/GenericReverb.js +2 -2
  56. package/lib/dist/effects/classes/reverbs/HallReverb.d.ts +2 -2
  57. package/lib/dist/effects/classes/reverbs/HallReverb.js +2 -2
  58. package/lib/dist/effects/classes/reverbs/RoomReverb.d.ts +2 -2
  59. package/lib/dist/effects/classes/reverbs/RoomReverb.js +2 -2
  60. package/lib/dist/effects/exports.d.ts +19 -19
  61. package/lib/dist/effects/exports.js +19 -19
  62. package/lib/dist/index.d.ts +12 -12
  63. package/lib/dist/index.d.ts.map +1 -1
  64. package/lib/dist/index.js +28 -28
  65. package/lib/dist/typings.d.ts +59 -66
  66. package/lib/dist/typings.d.ts.map +1 -1
  67. package/lib/dist/typings.js +1 -1
  68. package/lib/dist/utilities/constants.d.ts +1 -1
  69. package/lib/dist/utilities/constants.js +9 -9
  70. package/lib/dist/utilities/debugger.d.ts +7 -7
  71. package/lib/dist/utilities/debugger.js +49 -49
  72. package/lib/dist/utilities/helpers.d.ts +40 -40
  73. package/lib/dist/utilities/helpers.d.ts.map +1 -1
  74. package/lib/dist/utilities/helpers.js +143 -148
  75. package/lib/dist/utilities/web-assembly.d.ts +3 -3
  76. package/lib/dist/utilities/web-assembly.js +12 -12
  77. package/lib/src/core/classes/AudioClip.ts +2 -7
  78. package/lib/src/core/classes/Channel.ts +94 -4
  79. package/lib/src/core/classes/Effector.ts +2 -0
  80. package/lib/src/effects/classes/Chorus.ts +3 -0
  81. package/lib/src/effects/classes/Distortion.ts +14 -1
  82. package/lib/src/effects/classes/Saturation.ts +3 -1
  83. package/lib/src/effects/classes/SoftClip.ts +3 -0
  84. package/lib/src/effects/classes/StereoPanner.ts +3 -1
  85. package/lib/src/index.ts +1 -0
  86. package/lib/src/utilities/helpers.ts +28 -6
  87. package/lib/src/utilities/web-assembly.ts +4 -5
  88. 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
- constructor(public options: Partial<ChannelOptions> = { maxAudioNodes: 8, maxEffects: 8 }) {
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 /* && e.enabled !== false */);
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.parentialMasterChannel.gainNode);
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
- export class Distortion {}
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
+ }
@@ -1 +1,3 @@
1
- export class Saturation {}
1
+ export class Saturation {
2
+
3
+ }
@@ -4,6 +4,9 @@ import { Debug } from "../../utilities/debugger";
4
4
 
5
5
  export class SoftClip extends Effector {
6
6
 
7
+ public label: string | null = "SoftClip";
8
+ static name: string = "SoftClip";
9
+
7
10
  constructor(public drive: number = 1) {
8
11
  super();
9
12
  }
@@ -1 +1,3 @@
1
- export class StereoPanner {}
1
+ export class StereoPanner {
2
+ static name: string = "StereoPanner";
3
+ }
package/lib/src/index.ts CHANGED
@@ -63,6 +63,7 @@ export {
63
63
  ResolveDefaultAudioInputDevice,
64
64
  ResolveDefaultAudioOutputDevice,
65
65
  LoadAudioSource,
66
+ LoadAudioSourceFromBlob,
66
67
  LoadWorkletOnMasterChannel,
67
68
  } from "./utilities/helpers";
68
69
 
@@ -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...", [ `Channel ID: ${master.id}` ]);
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
- return new Promise(function(resolve, reject) {
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.2",
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",