@fluex/fluexgl-dsp 0.1.2

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 (138) hide show
  1. package/README.md +87 -0
  2. package/lib/dist/console-codes.d.ts +14 -0
  3. package/lib/dist/console-codes.d.ts.map +1 -0
  4. package/lib/dist/console-codes.js +16 -0
  5. package/lib/dist/core/classes/AudioClip.d.ts +67 -0
  6. package/lib/dist/core/classes/AudioClip.d.ts.map +1 -0
  7. package/lib/dist/core/classes/AudioClip.js +410 -0
  8. package/lib/dist/core/classes/AudioDevice.d.ts +13 -0
  9. package/lib/dist/core/classes/AudioDevice.d.ts.map +1 -0
  10. package/lib/dist/core/classes/AudioDevice.js +30 -0
  11. package/lib/dist/core/classes/Channel.d.ts +30 -0
  12. package/lib/dist/core/classes/Channel.d.ts.map +1 -0
  13. package/lib/dist/core/classes/Channel.js +144 -0
  14. package/lib/dist/core/classes/DpsPipeline.d.ts +60 -0
  15. package/lib/dist/core/classes/DpsPipeline.d.ts.map +1 -0
  16. package/lib/dist/core/classes/DpsPipeline.js +115 -0
  17. package/lib/dist/core/classes/Effector.d.ts +8 -0
  18. package/lib/dist/core/classes/Effector.d.ts.map +1 -0
  19. package/lib/dist/core/classes/Effector.js +7 -0
  20. package/lib/dist/core/classes/Master.d.ts +12 -0
  21. package/lib/dist/core/classes/Master.d.ts.map +1 -0
  22. package/lib/dist/core/classes/Master.js +35 -0
  23. package/lib/dist/core/exports.d.ts +7 -0
  24. package/lib/dist/core/exports.d.ts.map +1 -0
  25. package/lib/dist/core/exports.js +6 -0
  26. package/lib/dist/effects/classes/Chorus.d.ts +19 -0
  27. package/lib/dist/effects/classes/Chorus.d.ts.map +1 -0
  28. package/lib/dist/effects/classes/Chorus.js +83 -0
  29. package/lib/dist/effects/classes/Distortion.d.ts +3 -0
  30. package/lib/dist/effects/classes/Distortion.d.ts.map +1 -0
  31. package/lib/dist/effects/classes/Distortion.js +2 -0
  32. package/lib/dist/effects/classes/Equalizer.d.ts +3 -0
  33. package/lib/dist/effects/classes/Equalizer.d.ts.map +1 -0
  34. package/lib/dist/effects/classes/Equalizer.js +2 -0
  35. package/lib/dist/effects/classes/Filter.d.ts +3 -0
  36. package/lib/dist/effects/classes/Filter.d.ts.map +1 -0
  37. package/lib/dist/effects/classes/Filter.js +2 -0
  38. package/lib/dist/effects/classes/Limiter.d.ts +3 -0
  39. package/lib/dist/effects/classes/Limiter.d.ts.map +1 -0
  40. package/lib/dist/effects/classes/Limiter.js +2 -0
  41. package/lib/dist/effects/classes/Saturation.d.ts +3 -0
  42. package/lib/dist/effects/classes/Saturation.d.ts.map +1 -0
  43. package/lib/dist/effects/classes/Saturation.js +2 -0
  44. package/lib/dist/effects/classes/SoftClip.d.ts +8 -0
  45. package/lib/dist/effects/classes/SoftClip.d.ts.map +1 -0
  46. package/lib/dist/effects/classes/SoftClip.js +37 -0
  47. package/lib/dist/effects/classes/StereoPanner.d.ts +3 -0
  48. package/lib/dist/effects/classes/StereoPanner.d.ts.map +1 -0
  49. package/lib/dist/effects/classes/StereoPanner.js +2 -0
  50. package/lib/dist/effects/classes/compressors/Compressor.d.ts +3 -0
  51. package/lib/dist/effects/classes/compressors/Compressor.d.ts.map +1 -0
  52. package/lib/dist/effects/classes/compressors/Compressor.js +2 -0
  53. package/lib/dist/effects/classes/compressors/MultibandCompressor.d.ts +3 -0
  54. package/lib/dist/effects/classes/compressors/MultibandCompressor.d.ts.map +1 -0
  55. package/lib/dist/effects/classes/compressors/MultibandCompressor.js +2 -0
  56. package/lib/dist/effects/classes/delays/AdvancedDelay.d.ts +3 -0
  57. package/lib/dist/effects/classes/delays/AdvancedDelay.d.ts.map +1 -0
  58. package/lib/dist/effects/classes/delays/AdvancedDelay.js +2 -0
  59. package/lib/dist/effects/classes/delays/MonoDelay.d.ts +3 -0
  60. package/lib/dist/effects/classes/delays/MonoDelay.d.ts.map +1 -0
  61. package/lib/dist/effects/classes/delays/MonoDelay.js +2 -0
  62. package/lib/dist/effects/classes/delays/PingPongDelay.d.ts +3 -0
  63. package/lib/dist/effects/classes/delays/PingPongDelay.d.ts.map +1 -0
  64. package/lib/dist/effects/classes/delays/PingPongDelay.js +2 -0
  65. package/lib/dist/effects/classes/delays/StereoDelay.d.ts +3 -0
  66. package/lib/dist/effects/classes/delays/StereoDelay.d.ts.map +1 -0
  67. package/lib/dist/effects/classes/delays/StereoDelay.js +2 -0
  68. package/lib/dist/effects/classes/reverbs/ChamberReverb.d.ts +3 -0
  69. package/lib/dist/effects/classes/reverbs/ChamberReverb.d.ts.map +1 -0
  70. package/lib/dist/effects/classes/reverbs/ChamberReverb.js +2 -0
  71. package/lib/dist/effects/classes/reverbs/ConvolverReverb.d.ts +3 -0
  72. package/lib/dist/effects/classes/reverbs/ConvolverReverb.d.ts.map +1 -0
  73. package/lib/dist/effects/classes/reverbs/ConvolverReverb.js +2 -0
  74. package/lib/dist/effects/classes/reverbs/GenericReverb.d.ts +3 -0
  75. package/lib/dist/effects/classes/reverbs/GenericReverb.d.ts.map +1 -0
  76. package/lib/dist/effects/classes/reverbs/GenericReverb.js +2 -0
  77. package/lib/dist/effects/classes/reverbs/HallReverb.d.ts +3 -0
  78. package/lib/dist/effects/classes/reverbs/HallReverb.d.ts.map +1 -0
  79. package/lib/dist/effects/classes/reverbs/HallReverb.js +2 -0
  80. package/lib/dist/effects/classes/reverbs/RoomReverb.d.ts +3 -0
  81. package/lib/dist/effects/classes/reverbs/RoomReverb.d.ts.map +1 -0
  82. package/lib/dist/effects/classes/reverbs/RoomReverb.js +2 -0
  83. package/lib/dist/effects/exports.d.ts +20 -0
  84. package/lib/dist/effects/exports.d.ts.map +1 -0
  85. package/lib/dist/effects/exports.js +19 -0
  86. package/lib/dist/index.d.ts +13 -0
  87. package/lib/dist/index.d.ts.map +1 -0
  88. package/lib/dist/index.js +28 -0
  89. package/lib/dist/typings.d.ts +67 -0
  90. package/lib/dist/typings.d.ts.map +1 -0
  91. package/lib/dist/typings.js +1 -0
  92. package/lib/dist/utilities/constants.d.ts +2 -0
  93. package/lib/dist/utilities/constants.d.ts.map +1 -0
  94. package/lib/dist/utilities/constants.js +9 -0
  95. package/lib/dist/utilities/debugger.d.ts +8 -0
  96. package/lib/dist/utilities/debugger.d.ts.map +1 -0
  97. package/lib/dist/utilities/debugger.js +49 -0
  98. package/lib/dist/utilities/helpers.d.ts +41 -0
  99. package/lib/dist/utilities/helpers.d.ts.map +1 -0
  100. package/lib/dist/utilities/helpers.js +148 -0
  101. package/lib/dist/utilities/web-assembly.d.ts +4 -0
  102. package/lib/dist/utilities/web-assembly.d.ts.map +1 -0
  103. package/lib/dist/utilities/web-assembly.js +12 -0
  104. package/lib/src/console-codes.ts +16 -0
  105. package/lib/src/core/classes/AudioClip.ts +545 -0
  106. package/lib/src/core/classes/AudioDevice.ts +39 -0
  107. package/lib/src/core/classes/Channel.ts +199 -0
  108. package/lib/src/core/classes/DpsPipeline.ts +153 -0
  109. package/lib/src/core/classes/Effector.ts +11 -0
  110. package/lib/src/core/classes/Master.ts +50 -0
  111. package/lib/src/core/exports.ts +6 -0
  112. package/lib/src/effects/classes/Chorus.ts +109 -0
  113. package/lib/src/effects/classes/Distortion.ts +1 -0
  114. package/lib/src/effects/classes/Equalizer.ts +1 -0
  115. package/lib/src/effects/classes/Filter.ts +1 -0
  116. package/lib/src/effects/classes/Limiter.ts +1 -0
  117. package/lib/src/effects/classes/Saturation.ts +1 -0
  118. package/lib/src/effects/classes/SoftClip.ts +42 -0
  119. package/lib/src/effects/classes/StereoPanner.ts +1 -0
  120. package/lib/src/effects/classes/compressors/Compressor.ts +1 -0
  121. package/lib/src/effects/classes/compressors/MultibandCompressor.ts +1 -0
  122. package/lib/src/effects/classes/delays/AdvancedDelay.ts +1 -0
  123. package/lib/src/effects/classes/delays/MonoDelay.ts +1 -0
  124. package/lib/src/effects/classes/delays/PingPongDelay.ts +1 -0
  125. package/lib/src/effects/classes/delays/StereoDelay.ts +1 -0
  126. package/lib/src/effects/classes/reverbs/ChamberReverb.ts +1 -0
  127. package/lib/src/effects/classes/reverbs/ConvolverReverb.ts +1 -0
  128. package/lib/src/effects/classes/reverbs/GenericReverb.ts +1 -0
  129. package/lib/src/effects/classes/reverbs/HallReverb.ts +1 -0
  130. package/lib/src/effects/classes/reverbs/RoomReverb.ts +1 -0
  131. package/lib/src/effects/exports.ts +22 -0
  132. package/lib/src/index.ts +93 -0
  133. package/lib/src/typings.ts +79 -0
  134. package/lib/src/utilities/constants.ts +9 -0
  135. package/lib/src/utilities/debugger.ts +66 -0
  136. package/lib/src/utilities/helpers.ts +215 -0
  137. package/lib/src/utilities/web-assembly.ts +14 -0
  138. package/package.json +50 -0
@@ -0,0 +1,30 @@
1
+ import { Effector } from "./Effector";
2
+ import { AudioClip } from "./AudioClip";
3
+ import { Master } from "./Master";
4
+ import { ChannelOptions } from "../../typings";
5
+ export declare class Channel {
6
+ options: Partial<ChannelOptions>;
7
+ id: string;
8
+ effects: Effector[];
9
+ label: string | null;
10
+ parentialContext: AudioContext | null;
11
+ parentialMasterChannel: Master | null;
12
+ audioClips: AudioClip[];
13
+ gainNode: GainNode | null;
14
+ stereoPannerNode: StereoPannerNode | null;
15
+ audioClipsInputGainNode: GainNode | null;
16
+ constructor(options?: Partial<ChannelOptions>);
17
+ private rebuildEffectChain;
18
+ InitializeChannelOnMasterAttachment(master: Master): void;
19
+ SetLabel(label: string): void;
20
+ ClearLabel(): void;
21
+ AttachAudioClip(clip: AudioClip): void;
22
+ DetachAudioClip(clip: AudioClip): void;
23
+ SetVolume(volume: number): void;
24
+ SetPanLevel(pan: number): void;
25
+ AddEffect(effect: Effector): void;
26
+ RemoveEffect(effect: Effector): void;
27
+ get volume(): number | null;
28
+ get panLevel(): number | null;
29
+ }
30
+ //# sourceMappingURL=Channel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Channel.d.ts","sourceRoot":"","sources":["../../../src/core/classes/Channel.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAElC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAG/C,qBAAa,OAAO;IAgBG,OAAO,EAAE,OAAO,CAAC,cAAc,CAAC;IAd5C,EAAE,EAAE,MAAM,CAAQ;IAClB,OAAO,EAAE,QAAQ,EAAE,CAAM;IACzB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAErB,gBAAgB,EAAE,YAAY,GAAG,IAAI,CAAQ;IAC7C,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE7C,UAAU,EAAE,SAAS,EAAE,CAAM;IAE7B,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAQ;IACjC,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAQ;IAEjD,uBAAuB,EAAE,QAAQ,GAAG,IAAI,CAAQ;gBAEpC,OAAO,GAAE,OAAO,CAAC,cAAc,CAAuC;IAKzF,OAAO,CAAC,kBAAkB;IA2CnB,mCAAmC,CAAC,MAAM,EAAE,MAAM;IAelD,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAM7B,UAAU,IAAI,IAAI;IAMlB,eAAe,CAAC,IAAI,EAAE,SAAS;IAU/B,eAAe,CAAC,IAAI,EAAE,SAAS;IAuB/B,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAS/B,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAS9B,SAAS,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI;IAkBjC,YAAY,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI;IAkB3C,IAAW,MAAM,IAAI,MAAM,GAAG,IAAI,CAIjC;IAED,IAAW,QAAQ,IAAI,MAAM,GAAG,IAAI,CAInC;CACJ"}
@@ -0,0 +1,144 @@
1
+ import { v4 } from "uuid";
2
+ import { Debug } from "../../utilities/debugger";
3
+ export class Channel {
4
+ options;
5
+ id = v4();
6
+ effects = [];
7
+ label;
8
+ parentialContext = null;
9
+ parentialMasterChannel = null;
10
+ audioClips = [];
11
+ gainNode = null;
12
+ stereoPannerNode = null;
13
+ audioClipsInputGainNode = null;
14
+ constructor(options = { maxAudioNodes: 8, maxEffects: 8 }) {
15
+ this.options = options;
16
+ this.label = options.label ?? null;
17
+ }
18
+ rebuildEffectChain() {
19
+ Debug.Log("Attempting to rebuild effect chain.");
20
+ if (!this.audioClipsInputGainNode || !this.gainNode)
21
+ return Debug.Error("Could not rebuild effect chain, because one or more gain nodes on this channel are undefined.", [
22
+ `Channel id: ${this.id}.`,
23
+ `Current amount of effects: ${this.effects.length}.`
24
+ ]);
25
+ this.audioClipsInputGainNode.disconnect();
26
+ for (const effect of this.effects) {
27
+ effect.audioWorkletNode?.disconnect();
28
+ }
29
+ const activeEffects = this.effects.filter(e => !!e.audioWorkletNode /* && e.enabled !== false */);
30
+ if (activeEffects.length === 0) {
31
+ this.audioClipsInputGainNode.connect(this.gainNode);
32
+ }
33
+ else {
34
+ const firstEffectGain = activeEffects[0].audioWorkletNode;
35
+ this.audioClipsInputGainNode.connect(firstEffectGain);
36
+ for (let i = 0; i < activeEffects.length - 1; i++) {
37
+ const current = activeEffects[i].audioWorkletNode;
38
+ const next = activeEffects[i + 1].audioWorkletNode;
39
+ current.connect(next);
40
+ }
41
+ const lastEffectGain = activeEffects[activeEffects.length - 1].audioWorkletNode;
42
+ lastEffectGain.connect(this.gainNode);
43
+ }
44
+ Debug.Success("Successfully rebuilt effect chain.", [
45
+ `Channel id: ${this.id}.`,
46
+ `Current amount of effects: ${this.effects.length}`
47
+ ]);
48
+ }
49
+ InitializeChannelOnMasterAttachment(master) {
50
+ this.parentialMasterChannel = master;
51
+ this.parentialContext = master.context;
52
+ this.gainNode = new GainNode(this.parentialContext);
53
+ this.stereoPannerNode = new StereoPannerNode(this.parentialContext);
54
+ this.audioClipsInputGainNode = new GainNode(this.parentialContext);
55
+ this.audioClipsInputGainNode.connect(this.stereoPannerNode);
56
+ this.stereoPannerNode.connect(this.gainNode);
57
+ this.gainNode.connect(this.parentialMasterChannel.gainNode);
58
+ }
59
+ SetLabel(label) {
60
+ this.options.label = label;
61
+ this.label = label;
62
+ }
63
+ ClearLabel() {
64
+ this.options.label = "";
65
+ this.label = null;
66
+ }
67
+ AttachAudioClip(clip) {
68
+ if (this.audioClips.includes(clip))
69
+ return Debug.Error("Could not attach audio clip because it is already part of this channel", [
70
+ "Call .DetachAudioClip([clip AudioClip]) before attaching audio clip."
71
+ ]);
72
+ clip.InitializeAudioClipOnAttaching(this);
73
+ this.audioClips.push(clip);
74
+ }
75
+ DetachAudioClip(clip) {
76
+ if (!this.audioClips.includes(clip))
77
+ return Debug.Error("Could not detach audio clip, because it is not part of this channel.", [
78
+ "Call .AttachAudioClip([clip AudioClip]) before deattaching audio clip."
79
+ ]);
80
+ const self = this;
81
+ clip.parentialAudioContext = null;
82
+ clip.parentialChannel = null;
83
+ clip.hasAttachedToChannel = false;
84
+ clip.stereoPannerNode?.disconnect();
85
+ clip.gainNode?.disconnect();
86
+ clip.DisconnectAllAudioBufferSourceNodes();
87
+ this.audioClips.forEach(function (_clip, index) {
88
+ if (clip.id === _clip.id)
89
+ return self.audioClips.splice(index, 1);
90
+ });
91
+ }
92
+ SetVolume(volume) {
93
+ if (!this.gainNode)
94
+ return Debug.Error("Could not set channel volume because the channel is not attached to a master channel.", [
95
+ "Attach the channel to a master channel before setting the volume."
96
+ ]);
97
+ this.gainNode.gain.setValueAtTime(volume, this.parentialContext.currentTime);
98
+ }
99
+ SetPanLevel(pan) {
100
+ if (!this.stereoPannerNode)
101
+ return Debug.Error("Could not set channel pan level because the channel is not attached to a master channel.", [
102
+ "Attach the channel to a master channel before setting the pan level."
103
+ ]);
104
+ this.stereoPannerNode.pan.setValueAtTime(pan, this.parentialContext.currentTime);
105
+ }
106
+ AddEffect(effect) {
107
+ if (!this.parentialContext)
108
+ return Debug.Error("Could not add effect on channel, because the parential context is undefined.", [
109
+ `Channel ID: ${this.id}`,
110
+ `Effect ID: ${effect.id}`,
111
+ `Effect name: ${effect.constructor.name}`
112
+ ]);
113
+ if (this.effects.includes(effect))
114
+ return Debug.Error("Could not add effect because it is already part of this channel", [
115
+ "Call .RemoveEffect([effect Effector]) before adding effect."
116
+ ]);
117
+ effect.InitializeOnAttachment(this.parentialContext);
118
+ this.effects.push(effect);
119
+ this.rebuildEffectChain();
120
+ }
121
+ RemoveEffect(effect) {
122
+ if (!this.effects.includes(effect))
123
+ return Debug.Error("Could not remove effect, because it is not part of this channel.", [
124
+ "Call .AddEffect([effect Effector]) before removing effect."
125
+ ]);
126
+ const self = this;
127
+ this.effects.forEach(function (_effect, index) {
128
+ if (effect.id === _effect.id)
129
+ return self.effects.splice(index, 1);
130
+ });
131
+ this.rebuildEffectChain();
132
+ }
133
+ // Public getters and setters
134
+ get volume() {
135
+ if (!this.gainNode)
136
+ return null;
137
+ return this.gainNode.gain.value;
138
+ }
139
+ get panLevel() {
140
+ if (!this.stereoPannerNode)
141
+ return null;
142
+ return this.stereoPannerNode.pan.value;
143
+ }
144
+ }
@@ -0,0 +1,60 @@
1
+ import { AudioDevice } from "./AudioDevice";
2
+ import { DspPipelineInitializationOptions } from "../../typings";
3
+ /**
4
+ * Represents the digital signal processing (DSP) pipeline responsible for initializing
5
+ * WebAssembly modules, AudioWorklet processors, and resolving audio output devices.
6
+ */
7
+ export declare class DspPipeline {
8
+ /**
9
+ * The path to the WebAssembly module file.
10
+ */
11
+ pathToWasm: string | null;
12
+ /**
13
+ * The path to the AudioWorklet processor script.
14
+ */
15
+ pathToWorklet: string | null;
16
+ /**
17
+ * Unique identifier of this DSP pipeline instance.
18
+ */
19
+ id: string;
20
+ /**
21
+ * Indicates whether the DSP pipeline has been successfully initialized.
22
+ */
23
+ hasInitialized: boolean;
24
+ /**
25
+ * The generated blob URL containing the AudioWorklet processor code.
26
+ */
27
+ private blobUrl;
28
+ /**
29
+ * Creates a new instance of the {@link DspPipeline} class.
30
+ *
31
+ * @param options - Initialization options for the DSP pipeline.
32
+ * Must include valid paths to the WebAssembly and AudioWorklet files.
33
+ */
34
+ constructor(options: DspPipelineInitializationOptions);
35
+ /**
36
+ * Initializes the DSP pipeline.
37
+ * This is a convenience wrapper around {@link InitializeDpsPipeline}.
38
+ *
39
+ * @returns A promise resolving to `true` if the initialization succeeded, otherwise `false`.
40
+ */
41
+ Init(): Promise<boolean>;
42
+ /**
43
+ * Performs the full initialization of the DSP pipeline.
44
+ * Loads the WebAssembly module, constructs the AudioWorklet blob URL,
45
+ * and ensures audio access permissions are granted.
46
+ *
47
+ * @returns A promise resolving to `true` when initialization completes successfully, otherwise `false`.
48
+ */
49
+ InitializeDpsPipeline(): Promise<boolean>;
50
+ /**
51
+ * Resolves and initializes the system’s default audio output device.
52
+ * This method can only be called after the DSP pipeline has been initialized.
53
+ *
54
+ * @returns A promise that resolves with the default {@link AudioDevice} instance,
55
+ * or `null` if no default device was found or initialization failed.
56
+ */
57
+ ResolveDefaultAudioOutputDevice(): Promise<AudioDevice | null>;
58
+ TellMeWhatTheFuckThisWholeLibraryActuallyDoes(): string;
59
+ }
60
+ //# sourceMappingURL=DpsPipeline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DpsPipeline.d.ts","sourceRoot":"","sources":["../../../src/core/classes/DpsPipeline.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAM5C,OAAO,EAAE,gCAAgC,EAAE,MAAM,eAAe,CAAC;AAEjE;;;GAGG;AACH,qBAAa,WAAW;IAEpB;;OAEG;IACI,UAAU,EAAE,MAAM,GAAG,IAAI,CAAQ;IAExC;;OAEG;IACI,aAAa,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE3C;;OAEG;IACI,EAAE,EAAE,MAAM,CAAQ;IAEzB;;OAEG;IACI,cAAc,EAAE,OAAO,CAAS;IAEvC;;OAEG;IACH,OAAO,CAAC,OAAO,CAAuB;IAEtC;;;;;OAKG;gBACS,OAAO,EAAE,gCAAgC;IAKrD;;;;;OAKG;IACU,IAAI,IAAI,OAAO,CAAC,OAAO,CAAC;IAIrC;;;;;;OAMG;IACU,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC;IA0CtD;;;;;;OAMG;IACU,+BAA+B;IA+BrC,6CAA6C;CAGvD"}
@@ -0,0 +1,115 @@
1
+ import { v4 } from "uuid";
2
+ import { AudioDevice } from "./AudioDevice";
3
+ import { Debug } from "../../utilities/debugger";
4
+ import { LoadWebAssemblyModule } from "../../utilities/web-assembly";
5
+ import { ConstructProcessorWorklet, LoadWorkletOnMasterChannel } from "../../utilities/helpers";
6
+ import { ErrorCodes, WarningCodes } from "../../console-codes";
7
+ /**
8
+ * Represents the digital signal processing (DSP) pipeline responsible for initializing
9
+ * WebAssembly modules, AudioWorklet processors, and resolving audio output devices.
10
+ */
11
+ export class DspPipeline {
12
+ /**
13
+ * The path to the WebAssembly module file.
14
+ */
15
+ pathToWasm = null;
16
+ /**
17
+ * The path to the AudioWorklet processor script.
18
+ */
19
+ pathToWorklet = null;
20
+ /**
21
+ * Unique identifier of this DSP pipeline instance.
22
+ */
23
+ id = v4();
24
+ /**
25
+ * Indicates whether the DSP pipeline has been successfully initialized.
26
+ */
27
+ hasInitialized = false;
28
+ /**
29
+ * The generated blob URL containing the AudioWorklet processor code.
30
+ */
31
+ blobUrl = null;
32
+ /**
33
+ * Creates a new instance of the {@link DspPipeline} class.
34
+ *
35
+ * @param options - Initialization options for the DSP pipeline.
36
+ * Must include valid paths to the WebAssembly and AudioWorklet files.
37
+ */
38
+ constructor(options) {
39
+ this.pathToWasm = options.pathToWasm;
40
+ this.pathToWorklet = options.pathToWorklet;
41
+ }
42
+ /**
43
+ * Initializes the DSP pipeline.
44
+ * This is a convenience wrapper around {@link InitializeDpsPipeline}.
45
+ *
46
+ * @returns A promise resolving to `true` if the initialization succeeded, otherwise `false`.
47
+ */
48
+ async Init() {
49
+ return await this.InitializeDpsPipeline();
50
+ }
51
+ /**
52
+ * Performs the full initialization of the DSP pipeline.
53
+ * Loads the WebAssembly module, constructs the AudioWorklet blob URL,
54
+ * and ensures audio access permissions are granted.
55
+ *
56
+ * @returns A promise resolving to `true` when initialization completes successfully, otherwise `false`.
57
+ */
58
+ async InitializeDpsPipeline() {
59
+ Debug.Log("Attempting to initialize DSP pipeline...");
60
+ const start = Date.now();
61
+ if (!this.pathToWasm || !this.pathToWorklet) {
62
+ Debug.Error("Could not initialize DSP pipeline, because the path to the WASM, or the worklet file has not been defined.");
63
+ return false;
64
+ }
65
+ try {
66
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
67
+ Debug.Log(`Found ${stream.getTracks().length} media stream tracks.`);
68
+ // Stop all tracks immediately after verification
69
+ stream.getTracks().forEach((track) => {
70
+ track.stop();
71
+ });
72
+ }
73
+ catch (err) {
74
+ Debug.Error("Permission to access media devices has not been granted.", ["Make sure the user has granted FluentGL permission to access media devices."], ErrorCodes.NO_CONTEXT_PERMISSION);
75
+ return false;
76
+ }
77
+ await LoadWebAssemblyModule(this.pathToWasm);
78
+ const workletFileRequest = await fetch(this.pathToWorklet);
79
+ const textContent = await workletFileRequest.text();
80
+ this.blobUrl = ConstructProcessorWorklet(textContent);
81
+ const end = Date.now();
82
+ const difference = end - start;
83
+ Debug.Success(`Successfully initialized DSP pipeline within ${difference}ms.`);
84
+ return (this.hasInitialized = true);
85
+ }
86
+ /**
87
+ * Resolves and initializes the system’s default audio output device.
88
+ * This method can only be called after the DSP pipeline has been initialized.
89
+ *
90
+ * @returns A promise that resolves with the default {@link AudioDevice} instance,
91
+ * or `null` if no default device was found or initialization failed.
92
+ */
93
+ async ResolveDefaultAudioOutputDevice() {
94
+ Debug.Log("Attempting to resolve default audio output device...");
95
+ if (!this.hasInitialized || !this.blobUrl) {
96
+ Debug.Error("Could not resolve default audio output device, because the required blob URL has not been created.", ["Call await .InitializeDpsPipeline() before resolving default audio output device."]);
97
+ return null;
98
+ }
99
+ const audioDeviceInfos = [];
100
+ const devices = await navigator.mediaDevices.enumerateDevices();
101
+ for (let device of devices)
102
+ (device.kind === "audiooutput" && device.deviceId === "default") &&
103
+ audioDeviceInfos.push(device);
104
+ devices.length === 0 &&
105
+ Debug.Warn("No default audio device found.", [], WarningCodes.NO_DEFAULT_AUDIO_DEVICE_FOUND);
106
+ const defaultAudioDevice = devices.length === 0 ? null : new AudioDevice(audioDeviceInfos[0]);
107
+ if (!defaultAudioDevice)
108
+ return null;
109
+ await LoadWorkletOnMasterChannel(defaultAudioDevice.masterChannel, this.blobUrl);
110
+ return defaultAudioDevice;
111
+ }
112
+ TellMeWhatTheFuckThisWholeLibraryActuallyDoes() {
113
+ return `I wanted to create a web based game and implement advanced audio, but javascript is slow so that's why this library uses Web Assembly. You dont have to use it, unless you know what the fuck you're doing. If you do, god bless you.`;
114
+ }
115
+ }
@@ -0,0 +1,8 @@
1
+ export declare abstract class Effector {
2
+ id: string;
3
+ label: string | null;
4
+ audioWorkletNode: AudioWorkletNode | null;
5
+ parentialContext: AudioContext | null;
6
+ abstract InitializeOnAttachment(parentialContext: AudioContext): Promise<void>;
7
+ }
8
+ //# sourceMappingURL=Effector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Effector.d.ts","sourceRoot":"","sources":["../../../src/core/classes/Effector.ts"],"names":[],"mappings":"AAEA,8BAAsB,QAAQ;IAEnB,EAAE,EAAE,MAAM,CAAQ;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC5B,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAQ;IACjD,gBAAgB,EAAE,YAAY,GAAG,IAAI,CAAQ;aAEpC,sBAAsB,CAAC,gBAAgB,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;CACxF"}
@@ -0,0 +1,7 @@
1
+ import { v4 } from "uuid";
2
+ export class Effector {
3
+ id = v4();
4
+ label = null;
5
+ audioWorkletNode = null;
6
+ parentialContext = null;
7
+ }
@@ -0,0 +1,12 @@
1
+ import { Channel } from "./Channel";
2
+ export declare class Master {
3
+ id: string;
4
+ channels: Channel[];
5
+ context: AudioContext;
6
+ gainNode: GainNode;
7
+ analyserNode: AnalyserNode;
8
+ constructor();
9
+ AttachChannel(channel: Channel): void;
10
+ DetachChannel(channel: Channel): void;
11
+ }
12
+ //# sourceMappingURL=Master.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Master.d.ts","sourceRoot":"","sources":["../../../src/core/classes/Master.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAIpC,qBAAa,MAAM;IAER,EAAE,EAAE,MAAM,CAAQ;IAClB,QAAQ,EAAE,OAAO,EAAE,CAAM;IACzB,OAAO,EAAE,YAAY,CAAsB;IAE3C,QAAQ,EAAE,QAAQ,CAA6B;IAC/C,YAAY,EAAE,YAAY,CAAiC;;IAQ3D,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAYrC,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;CAgB/C"}
@@ -0,0 +1,35 @@
1
+ import { v4 } from "uuid";
2
+ import { Debug } from "../../utilities/debugger";
3
+ export class Master {
4
+ id = v4();
5
+ channels = [];
6
+ context = new AudioContext();
7
+ gainNode = this.context.createGain();
8
+ analyserNode = this.context.createAnalyser();
9
+ constructor() {
10
+ this.gainNode.connect(this.analyserNode);
11
+ this.analyserNode.connect(this.context.destination);
12
+ }
13
+ AttachChannel(channel) {
14
+ if (this.channels.includes(channel))
15
+ return Debug.Error("Could not attach the channel because it is already part of this master channel.", [
16
+ "Call .DetachChannel([channel Channel]) before attaching the channel."
17
+ ]);
18
+ channel.InitializeChannelOnMasterAttachment(this);
19
+ this.channels.push(channel);
20
+ return;
21
+ }
22
+ DetachChannel(channel) {
23
+ if (!this.channels.includes(channel))
24
+ return Debug.Error("Could not detach the channel because it is not part of this master channel.", [
25
+ "Call .AttachChannel([channel Channel]) before detaching the channel."
26
+ ]);
27
+ const self = this;
28
+ this.channels.forEach(function (_channel, index) {
29
+ if (channel.id === _channel.id) {
30
+ self.channels.splice(index, 1);
31
+ return;
32
+ }
33
+ });
34
+ }
35
+ }
@@ -0,0 +1,7 @@
1
+ export { AudioDevice } from "./classes/AudioDevice";
2
+ export { Channel } from "./classes/Channel";
3
+ export { Effector } from "./classes/Effector";
4
+ export { Master } from "./classes/Master";
5
+ export { AudioClip } from "./classes/AudioClip";
6
+ export { DspPipeline } from "./classes/DpsPipeline";
7
+ //# sourceMappingURL=exports.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exports.d.ts","sourceRoot":"","sources":["../../src/core/exports.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { AudioDevice } from "./classes/AudioDevice";
2
+ export { Channel } from "./classes/Channel";
3
+ export { Effector } from "./classes/Effector";
4
+ export { Master } from "./classes/Master";
5
+ export { AudioClip } from "./classes/AudioClip";
6
+ export { DspPipeline } from "./classes/DpsPipeline";
@@ -0,0 +1,19 @@
1
+ import { Effector } from "../../core/classes/Effector";
2
+ import { ChorusEffectOptions } from "../../typings";
3
+ export declare class Chorus extends Effector {
4
+ baseDelayMs: number;
5
+ depthMs: number;
6
+ rateHz: number;
7
+ mix: number;
8
+ feedback: number;
9
+ options: ChorusEffectOptions;
10
+ private sampleRate;
11
+ constructor(options?: ChorusEffectOptions);
12
+ InitializeOnAttachment(parentialContext: AudioContext): Promise<void>;
13
+ SetBaseDelayMs(value: number): void;
14
+ SetDepthMs(value: number): void;
15
+ SetRateHz(value: number): void;
16
+ SetMix(value: number): void;
17
+ SetFeedback(value: number): void;
18
+ }
19
+ //# sourceMappingURL=Chorus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Chorus.d.ts","sourceRoot":"","sources":["../../../src/effects/classes/Chorus.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAEvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAEpD,qBAAa,MAAO,SAAQ,QAAQ;IAEzB,WAAW,EAAE,MAAM,CAAM;IACzB,OAAO,EAAE,MAAM,CAAK;IACpB,MAAM,EAAE,MAAM,CAAO;IACrB,GAAG,EAAE,MAAM,CAAO;IAClB,QAAQ,EAAE,MAAM,CAAO;IAEvB,OAAO,EAAE,mBAAmB,CAAM;IAEzC,OAAO,CAAC,UAAU,CAAa;gBAEnB,OAAO,CAAC,EAAE,mBAAmB;IAa5B,sBAAsB,CAAC,gBAAgB,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAwB3E,cAAc,CAAC,KAAK,EAAE,MAAM;IAW5B,UAAU,CAAC,KAAK,EAAE,MAAM;IAWxB,SAAS,CAAC,KAAK,EAAE,MAAM;IAWvB,MAAM,CAAC,KAAK,EAAE,MAAM;IAWpB,WAAW,CAAC,KAAK,EAAE,MAAM;CAUnC"}
@@ -0,0 +1,83 @@
1
+ import { compiledWebAssemblyModule } from "../../utilities/web-assembly";
2
+ import { Effector } from "../../core/classes/Effector";
3
+ import { Debug } from "../../utilities/debugger";
4
+ export class Chorus extends Effector {
5
+ baseDelayMs = 15;
6
+ depthMs = 8;
7
+ rateHz = 1.5;
8
+ mix = 0.5;
9
+ feedback = 0.2;
10
+ options = {};
11
+ sampleRate = 0;
12
+ constructor(options) {
13
+ super();
14
+ this.options = {
15
+ baseDelayMs: this.baseDelayMs,
16
+ depthMs: this.depthMs,
17
+ rateHz: this.rateHz,
18
+ mix: this.mix,
19
+ feedback: this.mix,
20
+ ...options
21
+ };
22
+ }
23
+ async InitializeOnAttachment(parentialContext) {
24
+ if (!compiledWebAssemblyModule)
25
+ return Debug.Error("Could not initialize effector because the nessecary WASM file has not been specified.", [
26
+ `Effector type: Chorus`
27
+ ]);
28
+ this.sampleRate = parentialContext.sampleRate;
29
+ this.audioWorkletNode = new AudioWorkletNode(parentialContext, "ChorusProcessor", {
30
+ numberOfInputs: 1,
31
+ numberOfOutputs: 1,
32
+ outputChannelCount: [2],
33
+ parameterData: {
34
+ ...this.options,
35
+ sampleRate: this.sampleRate
36
+ },
37
+ processorOptions: {
38
+ module: compiledWebAssemblyModule
39
+ }
40
+ });
41
+ this.parentialContext = parentialContext;
42
+ }
43
+ SetBaseDelayMs(value) {
44
+ this.baseDelayMs = value;
45
+ this.options.baseDelayMs = value;
46
+ this.audioWorkletNode?.port.postMessage({
47
+ type: "set-base-delay-ms",
48
+ value
49
+ });
50
+ }
51
+ SetDepthMs(value) {
52
+ this.depthMs = value;
53
+ this.options.depthMs = value;
54
+ this.audioWorkletNode?.port.postMessage({
55
+ type: "set-depth-ms",
56
+ value
57
+ });
58
+ }
59
+ SetRateHz(value) {
60
+ this.rateHz = value;
61
+ this.options.rateHz = value;
62
+ this.audioWorkletNode?.port.postMessage({
63
+ type: "set-rate-hz",
64
+ value
65
+ });
66
+ }
67
+ SetMix(value) {
68
+ this.mix = value;
69
+ this.options.mix = value;
70
+ this.audioWorkletNode?.port.postMessage({
71
+ type: "set-mix",
72
+ value
73
+ });
74
+ }
75
+ SetFeedback(value) {
76
+ this.feedback = value;
77
+ this.options.feedback = value;
78
+ this.audioWorkletNode?.port.postMessage({
79
+ type: "set-mix",
80
+ value
81
+ });
82
+ }
83
+ }
@@ -0,0 +1,3 @@
1
+ export declare class Distortion {
2
+ }
3
+ //# sourceMappingURL=Distortion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Distortion.d.ts","sourceRoot":"","sources":["../../../src/effects/classes/Distortion.ts"],"names":[],"mappings":"AAAA,qBAAa,UAAU;CAAG"}
@@ -0,0 +1,2 @@
1
+ export class Distortion {
2
+ }
@@ -0,0 +1,3 @@
1
+ export declare class Equalizer {
2
+ }
3
+ //# sourceMappingURL=Equalizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Equalizer.d.ts","sourceRoot":"","sources":["../../../src/effects/classes/Equalizer.ts"],"names":[],"mappings":"AAAA,qBAAa,SAAS;CAAG"}
@@ -0,0 +1,2 @@
1
+ export class Equalizer {
2
+ }
@@ -0,0 +1,3 @@
1
+ export declare class Filter {
2
+ }
3
+ //# sourceMappingURL=Filter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Filter.d.ts","sourceRoot":"","sources":["../../../src/effects/classes/Filter.ts"],"names":[],"mappings":"AAAA,qBAAa,MAAM;CAAG"}
@@ -0,0 +1,2 @@
1
+ export class Filter {
2
+ }
@@ -0,0 +1,3 @@
1
+ export declare class Limiter {
2
+ }
3
+ //# sourceMappingURL=Limiter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Limiter.d.ts","sourceRoot":"","sources":["../../../src/effects/classes/Limiter.ts"],"names":[],"mappings":"AAAA,qBAAa,OAAO;CAAG"}
@@ -0,0 +1,2 @@
1
+ export class Limiter {
2
+ }
@@ -0,0 +1,3 @@
1
+ export declare class Saturation {
2
+ }
3
+ //# sourceMappingURL=Saturation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Saturation.d.ts","sourceRoot":"","sources":["../../../src/effects/classes/Saturation.ts"],"names":[],"mappings":"AAAA,qBAAa,UAAU;CAAG"}
@@ -0,0 +1,2 @@
1
+ export class Saturation {
2
+ }
@@ -0,0 +1,8 @@
1
+ import { Effector } from "../../core/classes/Effector";
2
+ export declare class SoftClip extends Effector {
3
+ drive: number;
4
+ constructor(drive?: number);
5
+ InitializeOnAttachment(parentialContext: AudioContext): Promise<void>;
6
+ SetDrive(drive: number): SoftClip;
7
+ }
8
+ //# sourceMappingURL=SoftClip.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SoftClip.d.ts","sourceRoot":"","sources":["../../../src/effects/classes/SoftClip.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,6BAA6B,CAAC;AAGvD,qBAAa,QAAS,SAAQ,QAAQ;IAEf,KAAK,EAAE,MAAM;gBAAb,KAAK,GAAE,MAAU;IAIvB,sBAAsB,CAAC,gBAAgB,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAqB3E,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ;CAU3C"}