@fluex/fluexgl-dsp 0.4.4 → 0.4.6
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/lib/dist/core/classes/Channel.d.ts +19 -4
- package/lib/dist/core/classes/Channel.d.ts.map +1 -1
- package/lib/dist/core/classes/Channel.js +113 -36
- package/lib/dist/core/classes/Effector.d.ts.map +1 -1
- package/lib/dist/core/classes/Effector.js +1 -0
- package/lib/dist/effects/classes/clips/SoftClip.d.ts +1 -1
- package/lib/dist/effects/classes/clips/SoftClip.d.ts.map +1 -1
- package/lib/dist/effects/classes/clips/SoftClip.js +5 -3
- package/lib/dist/index.d.ts +2 -2
- package/lib/dist/index.d.ts.map +1 -1
- package/lib/dist/index.js +2 -2
- package/lib/dist/typings.d.ts +1 -0
- package/lib/dist/typings.d.ts.map +1 -1
- package/lib/src/core/classes/Channel.ts +159 -55
- package/lib/src/core/classes/Effector.ts +2 -1
- package/lib/src/effects/classes/clips/SoftClip.ts +7 -3
- package/lib/src/index.ts +4 -3
- package/lib/src/typings.ts +2 -0
- package/package.json +1 -1
|
@@ -2,6 +2,7 @@ import { AudioClipPlayer } from "./AudioClipPlayer";
|
|
|
2
2
|
import { AudioClip } from "./AudioClip";
|
|
3
3
|
import { Master } from "./Master";
|
|
4
4
|
import { Effector } from "./Effector";
|
|
5
|
+
import { ArrayPosition } from "../../typings";
|
|
5
6
|
export declare class Channel {
|
|
6
7
|
id: string;
|
|
7
8
|
label: string;
|
|
@@ -16,13 +17,22 @@ export declare class Channel {
|
|
|
16
17
|
audioClipPlayer: AudioClipPlayer | null;
|
|
17
18
|
constructor(context: AudioContext, label?: string);
|
|
18
19
|
private rebuildEffectChain;
|
|
19
|
-
AddEffect(effect: Effector): void;
|
|
20
|
-
AttachEffect(effect: Effector): void;
|
|
21
|
-
RemoveEffect(effect: Effector): void;
|
|
22
|
-
DetachEffect(effect: Effector): void;
|
|
23
20
|
private disconnectAudioNodes;
|
|
24
21
|
private isInitialized;
|
|
25
22
|
private isReachable;
|
|
23
|
+
/**
|
|
24
|
+
* Public method to manually rebuild the effect chain.
|
|
25
|
+
* Can be useful when the automatic rebuilt did not
|
|
26
|
+
* work properly.
|
|
27
|
+
* @returns
|
|
28
|
+
*/
|
|
29
|
+
RebuildEffectChain(): void;
|
|
30
|
+
AddEffect(effect: Effector): Channel;
|
|
31
|
+
AttachEffect(effect: Effector): Channel;
|
|
32
|
+
RemoveEffect(effect: Effector): void;
|
|
33
|
+
RemoveAllEffects(): void;
|
|
34
|
+
DetachEffect(effect: Effector): void;
|
|
35
|
+
DetachAllEffects(): void;
|
|
26
36
|
Send(channel: Channel | Master): void;
|
|
27
37
|
Unsend(channel: Channel | Master): void;
|
|
28
38
|
HasAudioClipPlayer(): boolean;
|
|
@@ -30,5 +40,10 @@ export declare class Channel {
|
|
|
30
40
|
AttachAudioClip(audioClip: AudioClip): Channel;
|
|
31
41
|
Volume(volume?: number): number;
|
|
32
42
|
Pan(pan?: number): number;
|
|
43
|
+
GetEffectsByLabel(label: string): Effector[];
|
|
44
|
+
GetFirstEffectByLabel(label: string): Effector | null;
|
|
45
|
+
GetEffectById(id: string): Effector[];
|
|
46
|
+
GetFirstEffectById(id: string): Effector | null;
|
|
47
|
+
MoveEffectToIndex(effect: Effector, index: number | ArrayPosition): void;
|
|
33
48
|
}
|
|
34
49
|
//# sourceMappingURL=Channel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Channel.d.ts","sourceRoot":"","sources":["../../../src/core/classes/Channel.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Channel.d.ts","sourceRoot":"","sources":["../../../src/core/classes/Channel.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,qBAAa,OAAO;IAET,EAAE,EAAE,MAAM,CAAQ;IAClB,KAAK,EAAE,MAAM,CAAa;IAE1B,KAAK,EAAE,SAAS,GAAG,IAAI,CAAQ;IAC/B,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAQ;IACjD,YAAY,EAAE,YAAY,GAAG,IAAI,CAAQ;IACzC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAQ;IACjC,MAAM,EAAE,SAAS,GAAG,IAAI,CAAQ;IAEhC,OAAO,EAAE,QAAQ,EAAE,CAAM;IACzB,OAAO,EAAE,YAAY,GAAG,IAAI,CAAQ;IAEpC,KAAK,EAAE,OAAO,EAAE,CAAM;IACtB,eAAe,EAAE,eAAe,GAAG,IAAI,CAAQ;gBAE1C,OAAO,EAAE,YAAY,EAAE,KAAK,CAAC,EAAE,MAAM;IAsBjD,OAAO,CAAC,kBAAkB;IAsC1B,OAAO,CAAC,oBAAoB;IAqB5B,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,WAAW;IAwBnB;;;;;OAKG;IACI,kBAAkB;IAIlB,SAAS,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO;IAcpC,YAAY,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO;IAIvC,YAAY,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI;IAqBpC,gBAAgB;IAMhB,YAAY,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI;IAIpC,gBAAgB;IAIhB,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM;IAkC9B,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM;IAehC,kBAAkB,IAAI,OAAO;IAI7B,mBAAmB;IAOnB,eAAe,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO;IAQ9C,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM;IAS/B,GAAG,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM;IASzB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,EAAE;IAI5C,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;IAMrD,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,QAAQ,EAAE;IAIrC,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;IAM/C,iBAAiB,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;CAmElF"}
|
|
@@ -58,42 +58,6 @@ export class Channel {
|
|
|
58
58
|
}
|
|
59
59
|
activeEffects[activeEffects.length - 1].audioWorkletNode.connect(this.stereoPannerNode);
|
|
60
60
|
}
|
|
61
|
-
AddEffect(effect) {
|
|
62
|
-
if (!this.context) {
|
|
63
|
-
Debug.Error("Could not add effect because this channel has no AudioContext.");
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
if (this.effects.includes(effect)) {
|
|
67
|
-
Debug.Error("Could not add effect because it is already part of this channel", [
|
|
68
|
-
"Call .RemoveEffect([effect Effector]) before adding effect."
|
|
69
|
-
], ErrorCodes.EFFECT_ALREADY_ATTACHED);
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
this.effects.push(effect);
|
|
73
|
-
effect.InitializeOnAttachment(this.context);
|
|
74
|
-
this.rebuildEffectChain();
|
|
75
|
-
}
|
|
76
|
-
AttachEffect(effect) {
|
|
77
|
-
return this.AddEffect(effect);
|
|
78
|
-
}
|
|
79
|
-
RemoveEffect(effect) {
|
|
80
|
-
if (!this.effects.includes(effect)) {
|
|
81
|
-
Debug.Error("Could not remove effect, because it is not part of this channel.", [
|
|
82
|
-
"Call .AddEffect([effect Effector]) before removing effect."
|
|
83
|
-
], ErrorCodes.EFFECT_NOT_FOUND);
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
const self = this;
|
|
87
|
-
this.effects.forEach(function (_effect, index) {
|
|
88
|
-
if (effect.id === _effect.id)
|
|
89
|
-
self.effects.splice(index, 1);
|
|
90
|
-
});
|
|
91
|
-
effect.audioWorkletNode?.disconnect();
|
|
92
|
-
this.rebuildEffectChain();
|
|
93
|
-
}
|
|
94
|
-
DetachEffect(effect) {
|
|
95
|
-
return this.RemoveEffect(effect);
|
|
96
|
-
}
|
|
97
61
|
disconnectAudioNodes(gc) {
|
|
98
62
|
this.input?.disconnect();
|
|
99
63
|
this.stereoPannerNode?.disconnect();
|
|
@@ -129,6 +93,54 @@ export class Channel {
|
|
|
129
93
|
}
|
|
130
94
|
return false;
|
|
131
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* Public method to manually rebuild the effect chain.
|
|
98
|
+
* Can be useful when the automatic rebuilt did not
|
|
99
|
+
* work properly.
|
|
100
|
+
* @returns
|
|
101
|
+
*/
|
|
102
|
+
RebuildEffectChain() {
|
|
103
|
+
return this.rebuildEffectChain();
|
|
104
|
+
}
|
|
105
|
+
AddEffect(effect) {
|
|
106
|
+
if (!this.context)
|
|
107
|
+
throw new Error(`Could not add effect (${effect.id}), to channel (${this.id}), because the channel's AudioContext is undefined.`);
|
|
108
|
+
if (this.effects.includes(effect))
|
|
109
|
+
throw new Error(`Could not add effect (${effect.id}), to channel (${this.id}), because it has already been added to the channel.`);
|
|
110
|
+
this.effects.push(effect);
|
|
111
|
+
effect.InitializeOnAttachment(this.context);
|
|
112
|
+
this.rebuildEffectChain();
|
|
113
|
+
return this;
|
|
114
|
+
}
|
|
115
|
+
AttachEffect(effect) {
|
|
116
|
+
return this.AddEffect(effect);
|
|
117
|
+
}
|
|
118
|
+
RemoveEffect(effect) {
|
|
119
|
+
if (!this.effects.includes(effect)) {
|
|
120
|
+
Debug.Error("Could not remove effect, because it is not part of this channel.", [
|
|
121
|
+
"Call .AddEffect([effect Effector]) before removing effect."
|
|
122
|
+
], ErrorCodes.EFFECT_NOT_FOUND);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const self = this;
|
|
126
|
+
this.effects.forEach(function (_effect, index) {
|
|
127
|
+
if (effect.id === _effect.id)
|
|
128
|
+
self.effects.splice(index, 1);
|
|
129
|
+
});
|
|
130
|
+
effect.audioWorkletNode?.disconnect();
|
|
131
|
+
this.rebuildEffectChain();
|
|
132
|
+
}
|
|
133
|
+
RemoveAllEffects() {
|
|
134
|
+
for (const effect of this.effects) {
|
|
135
|
+
this.RemoveEffect(effect);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
DetachEffect(effect) {
|
|
139
|
+
return this.RemoveEffect(effect);
|
|
140
|
+
}
|
|
141
|
+
DetachAllEffects() {
|
|
142
|
+
return this.RemoveAllEffects();
|
|
143
|
+
}
|
|
132
144
|
Send(channel) {
|
|
133
145
|
if (channel instanceof Master)
|
|
134
146
|
return channel.AttachChannel(this);
|
|
@@ -200,4 +212,69 @@ export class Channel {
|
|
|
200
212
|
pan && this.stereoPannerNode.pan.setValueAtTime(pan, this.context.currentTime);
|
|
201
213
|
return pan ?? this.stereoPannerNode.pan.value;
|
|
202
214
|
}
|
|
215
|
+
GetEffectsByLabel(label) {
|
|
216
|
+
return this.effects.filter(effect => effect.label === label);
|
|
217
|
+
}
|
|
218
|
+
GetFirstEffectByLabel(label) {
|
|
219
|
+
const filteredEffects = this.effects.filter(effect => effect.label === label);
|
|
220
|
+
return filteredEffects.length !== 0 ? filteredEffects[0] : null;
|
|
221
|
+
}
|
|
222
|
+
GetEffectById(id) {
|
|
223
|
+
return this.effects.filter(effect => effect.id === id);
|
|
224
|
+
}
|
|
225
|
+
GetFirstEffectById(id) {
|
|
226
|
+
const filteredEffects = this.effects.filter(effect => effect.id === id);
|
|
227
|
+
return filteredEffects.length !== 0 ? filteredEffects[0] : null;
|
|
228
|
+
}
|
|
229
|
+
MoveEffectToIndex(effect, index) {
|
|
230
|
+
let fromIndex = -1, matches = 0, i = 0;
|
|
231
|
+
for (i = 0; i < this.effects.length; i++) {
|
|
232
|
+
if (this.effects[i].id === effect.id) {
|
|
233
|
+
if (fromIndex === -1)
|
|
234
|
+
fromIndex = i;
|
|
235
|
+
matches++;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (matches === 0)
|
|
239
|
+
throw new Error("Effect '" + effect.id + "' (" + effect.label + ") could not be found. " +
|
|
240
|
+
"The effect ID may have changed, or the effect is not attached to this channel.");
|
|
241
|
+
if (matches > 1)
|
|
242
|
+
throw new Error("Multiple effects with the ID '" + effect.id + "' are attached to this channel. " +
|
|
243
|
+
"Make sure every effect has a unique ID.");
|
|
244
|
+
let toIndex;
|
|
245
|
+
if (typeof index === "number") {
|
|
246
|
+
toIndex = index;
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
switch (index) {
|
|
250
|
+
case "start":
|
|
251
|
+
toIndex = 0;
|
|
252
|
+
break;
|
|
253
|
+
case "end":
|
|
254
|
+
toIndex = this.effects.length - 1;
|
|
255
|
+
break;
|
|
256
|
+
case "one-after-start":
|
|
257
|
+
toIndex = 1;
|
|
258
|
+
break;
|
|
259
|
+
case "one-before-end":
|
|
260
|
+
toIndex = this.effects.length - 2;
|
|
261
|
+
break;
|
|
262
|
+
default:
|
|
263
|
+
throw new Error("Invalid ArrayPosition: " + String(index));
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
if (toIndex < 0)
|
|
267
|
+
toIndex = 0;
|
|
268
|
+
if (toIndex >= this.effects.length)
|
|
269
|
+
toIndex = this.effects.length - 1;
|
|
270
|
+
if (fromIndex === toIndex)
|
|
271
|
+
return;
|
|
272
|
+
const item = this.effects.splice(fromIndex, 1)[0];
|
|
273
|
+
if (fromIndex < toIndex)
|
|
274
|
+
toIndex = toIndex - 1;
|
|
275
|
+
this.effects.splice(toIndex, 0, item);
|
|
276
|
+
// Initializing the effect is unnessecary because it should have been intialized already
|
|
277
|
+
// otherwise it could not been found. Rebuilding the effect chain is nessecary though.
|
|
278
|
+
this.rebuildEffectChain();
|
|
279
|
+
}
|
|
203
280
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Effector.d.ts","sourceRoot":"","sources":["../../../src/core/classes/Effector.ts"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"Effector.d.ts","sourceRoot":"","sources":["../../../src/core/classes/Effector.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiD,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGhG,8BAAsB,QAAQ;IAEnB,EAAE,EAAE,MAAM,CAAQ;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC5B,IAAI,EAAE,MAAM,CAAc;IAE1B,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAQ;IACjD,OAAO,EAAE,YAAY,GAAG,IAAI,CAAQ;IAE3C,OAAO,CAAC,iCAAiC,CAAkB;IAE3D,OAAO,CAAC,MAAM,CAMb;IAED,OAAO,CAAC,sBAAsB;IAgB9B,SAAS,CAAC,4BAA4B,CAAC,IAAI,EAAE,gBAAgB;IAQtD,gBAAgB,CAAC,CAAC,SAAS,MAAM,gBAAgB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI;IAOjG,IAAI,CAAC,CAAC,SAAS,MAAM,gBAAgB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI;IAarF,mBAAmB,CAAC,CAAC,SAAS,MAAM,gBAAgB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,gBAAgB,CAAC,CAAC,CAAC,GAAG,QAAQ;IAalG,mBAAmB,CAAC,KAAK,CAAC,EAAE,MAAM,gBAAgB,GAAG,QAAQ;aAWpD,sBAAsB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;CAC/E"}
|
|
@@ -30,6 +30,7 @@ export class Effector {
|
|
|
30
30
|
registerMessageEventListener(node) {
|
|
31
31
|
if (this.hasRegisteredMessageEventListener)
|
|
32
32
|
return;
|
|
33
|
+
this.hasRegisteredMessageEventListener = true;
|
|
33
34
|
node.port.onmessage = this.handleIncomingMessages.bind(this);
|
|
34
35
|
Debug.Log(`Succesfully registered event listener on effector ${this.name} (${this.label}) [${this.id}]`);
|
|
35
36
|
}
|
|
@@ -6,7 +6,7 @@ export declare class SoftClip extends Effector {
|
|
|
6
6
|
drive: number;
|
|
7
7
|
gain: number;
|
|
8
8
|
strictMode: StrictMode;
|
|
9
|
-
constructor({ drive, gain, strictMode }
|
|
9
|
+
constructor({ drive, gain, strictMode }?: Partial<SoftClipOptions>);
|
|
10
10
|
InitializeOnAttachment(context: AudioContext): Promise<void>;
|
|
11
11
|
ReturnOptionsAsObject(): SoftClipOptions;
|
|
12
12
|
SetDrive(drive: number): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SoftClip.d.ts","sourceRoot":"","sources":["../../../../src/effects/classes/clips/SoftClip.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAwD,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAErH,qBAAa,QAAS,SAAQ,QAAQ;IAE3B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAc;IAClC,IAAI,EAAE,MAAM,CAAc;IAE1B,KAAK,EAAE,MAAM,CAAK;IAClB,IAAI,EAAE,MAAM,CAAK;IACjB,UAAU,EAAE,UAAU,CAAuB;gBAExC,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"SoftClip.d.ts","sourceRoot":"","sources":["../../../../src/effects/classes/clips/SoftClip.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAwD,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAErH,qBAAa,QAAS,SAAQ,QAAQ;IAE3B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAc;IAClC,IAAI,EAAE,MAAM,CAAc;IAE1B,KAAK,EAAE,MAAM,CAAK;IAClB,IAAI,EAAE,MAAM,CAAK;IACjB,UAAU,EAAE,UAAU,CAAuB;gBAExC,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,GAAE,OAAO,CAAC,eAAe,CAAM;IAUzD,sBAAsB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IASlE,qBAAqB,IAAI,eAAe;IAQxC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAMhC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;CAKxC"}
|
|
@@ -7,7 +7,7 @@ export class SoftClip extends Effector {
|
|
|
7
7
|
drive = 1;
|
|
8
8
|
gain = 1;
|
|
9
9
|
strictMode = StrictMode.Disabled;
|
|
10
|
-
constructor({ drive, gain, strictMode }) {
|
|
10
|
+
constructor({ drive, gain, strictMode } = {}) {
|
|
11
11
|
super();
|
|
12
12
|
this.drive = Math.max(0, CoerceFiniteNumber(drive, this.drive));
|
|
13
13
|
this.gain = Math.max(0, CoerceFiniteNumber(gain, this.gain));
|
|
@@ -15,8 +15,10 @@ export class SoftClip extends Effector {
|
|
|
15
15
|
this.strictMode = mode === StrictMode.Enabled ? StrictMode.Enabled : StrictMode.Disabled;
|
|
16
16
|
}
|
|
17
17
|
async InitializeOnAttachment(context) {
|
|
18
|
-
this.context
|
|
19
|
-
|
|
18
|
+
if (this.context === null)
|
|
19
|
+
this.context = context;
|
|
20
|
+
if (this.audioWorkletNode === null)
|
|
21
|
+
this.audioWorkletNode = CreateAudioWorkletNode(context, AudioWorkletProcessorNames.SoftClip, this.ReturnOptionsAsObject());
|
|
20
22
|
}
|
|
21
23
|
ReturnOptionsAsObject() {
|
|
22
24
|
return {
|
package/lib/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,6 @@ export { AudioDevice, Channel, Effector, Master, AudioClip, DspPipeline, AudioCl
|
|
|
9
9
|
export { InitializeDspPipeline, ResolveAudioOutputDevices, ResolveAudioInputDevices, ResolveDefaultAudioInputDevice, ResolveDefaultAudioOutputDevice, LoadAudioSource, LoadAudioSourceFromBlob, LoadWorkletOnAudioDevice, SendMessageToWorklet } from "./utilities/helpers";
|
|
10
10
|
export { SUPPORTED_FILE_TYPES } from "./utilities/constants";
|
|
11
11
|
export { hasInitializedWasm, } from "./utilities/web-assembly";
|
|
12
|
-
export { StrictMode, ProcessorIdentificationCodes, HardClipMessageCommandId, SoftClipMessageCommandId, AudioWorkletProcessorNames, ChorusMessageCommandId, LowPassFilterMessageCommandId } from "./typings";
|
|
13
|
-
export type { DspDebuggerOptions, DspOptions, LoadAudioSourceOptions, AudioSourceData, ChannelOptions, ChannelSpatialization, AudioClipEventMap, AudioClipEvents, AudioClipOnProgressEvent, AudioClipAnalyserProperty, AudioClipAnalyserType, DspPipelineInitializationOptions, DspPipelineInitializationState, ChorusEffectOptions, LowPassFilterOptions, SoftClipOptions, HardClipOptions, EffectorEventMap, IncomingMessageType, IncomingProcessorMessage, ProcessorData, EffectorEvents, } from "./typings";
|
|
12
|
+
export { StrictMode, ProcessorIdentificationCodes, HardClipMessageCommandId, SoftClipMessageCommandId, AudioWorkletProcessorNames, ChorusMessageCommandId, LowPassFilterMessageCommandId, } from "./typings";
|
|
13
|
+
export type { DspDebuggerOptions, DspOptions, LoadAudioSourceOptions, AudioSourceData, ChannelOptions, ChannelSpatialization, AudioClipEventMap, AudioClipEvents, AudioClipOnProgressEvent, AudioClipAnalyserProperty, AudioClipAnalyserType, DspPipelineInitializationOptions, DspPipelineInitializationState, ChorusEffectOptions, LowPassFilterOptions, SoftClipOptions, HardClipOptions, EffectorEventMap, IncomingMessageType, IncomingProcessorMessage, ProcessorData, EffectorEvents, ArrayPosition } from "./typings";
|
|
14
14
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,eAAO,MAAM,GAAG,EAAE,UAYjB,CAAA;AAED,OAAO,EACH,MAAM,EACN,QAAQ,EACR,UAAU,EACV,SAAS,EACT,OAAO,EACP,UAAU,EACV,YAAY,EACZ,UAAU,EACV,mBAAmB,EACnB,aAAa,EACb,SAAS,EACT,aAAa,EACb,WAAW,EACX,aAAa,EACb,eAAe,EACf,aAAa,EACb,UAAU,EACV,UAAU,EACV,QAAQ,EACR,aAAa,EACb,QAAQ,EACX,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACH,WAAW,EACX,OAAO,EACP,QAAQ,EACR,MAAM,EACN,SAAS,EACT,WAAW,EACX,eAAe,EAClB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACH,qBAAqB,EACrB,yBAAyB,EACzB,wBAAwB,EACxB,8BAA8B,EAC9B,+BAA+B,EAC/B,eAAe,EACf,uBAAuB,EACvB,wBAAwB,EACxB,oBAAoB,EACvB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACH,oBAAoB,EACvB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACH,kBAAkB,GACrB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EACH,UAAU,EACV,4BAA4B,EAC5B,wBAAwB,EACxB,wBAAwB,EACxB,0BAA0B,EAC1B,sBAAsB,EACtB,6BAA6B,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,eAAO,MAAM,GAAG,EAAE,UAYjB,CAAA;AAED,OAAO,EACH,MAAM,EACN,QAAQ,EACR,UAAU,EACV,SAAS,EACT,OAAO,EACP,UAAU,EACV,YAAY,EACZ,UAAU,EACV,mBAAmB,EACnB,aAAa,EACb,SAAS,EACT,aAAa,EACb,WAAW,EACX,aAAa,EACb,eAAe,EACf,aAAa,EACb,UAAU,EACV,UAAU,EACV,QAAQ,EACR,aAAa,EACb,QAAQ,EACX,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACH,WAAW,EACX,OAAO,EACP,QAAQ,EACR,MAAM,EACN,SAAS,EACT,WAAW,EACX,eAAe,EAClB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACH,qBAAqB,EACrB,yBAAyB,EACzB,wBAAwB,EACxB,8BAA8B,EAC9B,+BAA+B,EAC/B,eAAe,EACf,uBAAuB,EACvB,wBAAwB,EACxB,oBAAoB,EACvB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACH,oBAAoB,EACvB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACH,kBAAkB,GACrB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EACH,UAAU,EACV,4BAA4B,EAC5B,wBAAwB,EACxB,wBAAwB,EACxB,0BAA0B,EAC1B,sBAAsB,EACtB,6BAA6B,GAChC,MAAM,WAAW,CAAC;AAEnB,YAAY,EACR,kBAAkB,EAClB,UAAU,EACV,sBAAsB,EACtB,eAAe,EACf,cAAc,EACd,qBAAqB,EACrB,iBAAiB,EACjB,eAAe,EACf,wBAAwB,EACxB,yBAAyB,EACzB,qBAAqB,EACrB,gCAAgC,EAChC,8BAA8B,EAC9B,mBAAmB,EACnB,oBAAoB,EACpB,eAAe,EACf,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,wBAAwB,EACxB,aAAa,EACb,cAAc,EACd,aAAa,EAChB,MAAM,WAAW,CAAC"}
|
package/lib/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
export const DSP = {
|
|
6
6
|
maxMasterChannels: 8,
|
|
7
7
|
maxTotalChannels: 128,
|
|
8
|
-
sampleRate:
|
|
8
|
+
sampleRate: 41000,
|
|
9
9
|
spatialization: "stereo",
|
|
10
10
|
overrideMaxAudioBufferNodes: false,
|
|
11
11
|
debugger: {
|
|
@@ -20,4 +20,4 @@ export { AudioDevice, Channel, Effector, Master, AudioClip, DspPipeline, AudioCl
|
|
|
20
20
|
export { InitializeDspPipeline, ResolveAudioOutputDevices, ResolveAudioInputDevices, ResolveDefaultAudioInputDevice, ResolveDefaultAudioOutputDevice, LoadAudioSource, LoadAudioSourceFromBlob, LoadWorkletOnAudioDevice, SendMessageToWorklet } from "./utilities/helpers";
|
|
21
21
|
export { SUPPORTED_FILE_TYPES } from "./utilities/constants";
|
|
22
22
|
export { hasInitializedWasm, } from "./utilities/web-assembly";
|
|
23
|
-
export { StrictMode, ProcessorIdentificationCodes, HardClipMessageCommandId, SoftClipMessageCommandId, AudioWorkletProcessorNames, ChorusMessageCommandId, LowPassFilterMessageCommandId } from "./typings";
|
|
23
|
+
export { StrictMode, ProcessorIdentificationCodes, HardClipMessageCommandId, SoftClipMessageCommandId, AudioWorkletProcessorNames, ChorusMessageCommandId, LowPassFilterMessageCommandId, } from "./typings";
|
package/lib/dist/typings.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export type ChannelSpatialization = "mono" | "stereo" | "surround";
|
|
|
2
2
|
export type AudioClipAnalyserType = "pre" | "post";
|
|
3
3
|
export type AudioClipAnalyserProperty = "fftSize" | "minDecibels" | "maxDecibels" | "smoothingTimeConstant";
|
|
4
4
|
export type IncomingMessageType = "message" | "error" | "warning" | "wasm-instantiated";
|
|
5
|
+
export type ArrayPosition = "start" | "middle" | "end" | "one-after-start" | "one-before-end";
|
|
5
6
|
export type AudioClipEvents = {
|
|
6
7
|
[K in keyof AudioClipEventMap]: AudioClipEventMap[K][];
|
|
7
8
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typings.d.ts","sourceRoot":"","sources":["../src/typings.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,qBAAqB,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;AACnE,MAAM,MAAM,qBAAqB,GAAG,KAAK,GAAG,MAAM,CAAC;AACnD,MAAM,MAAM,yBAAyB,GAAG,SAAS,GAAG,aAAa,GAAG,aAAa,GAAG,uBAAuB,CAAC;AAC5G,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"typings.d.ts","sourceRoot":"","sources":["../src/typings.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { v4 } from "uuid";
|
|
2
|
+
|
|
2
3
|
import { Debug } from "../../utilities/debugger";
|
|
3
4
|
import { AudioClipPlayer } from "./AudioClipPlayer";
|
|
4
5
|
import { AudioClip } from "./AudioClip";
|
|
5
6
|
import { Master } from "./Master";
|
|
6
7
|
import { Effector } from "./Effector";
|
|
7
8
|
import { ErrorCodes } from "../../console-codes";
|
|
9
|
+
import { ArrayPosition } from "../../typings";
|
|
8
10
|
|
|
9
11
|
export class Channel {
|
|
10
12
|
|
|
@@ -73,7 +75,7 @@ export class Channel {
|
|
|
73
75
|
this.input.connect(activeEffects[0].audioWorkletNode as AudioNode);
|
|
74
76
|
|
|
75
77
|
for (let i: number = 0; i < activeEffects.length - 1; i++) {
|
|
76
|
-
|
|
78
|
+
|
|
77
79
|
const current = activeEffects[i].audioWorkletNode as AudioNode;
|
|
78
80
|
const next = activeEffects[i + 1].audioWorkletNode as AudioNode;
|
|
79
81
|
|
|
@@ -83,54 +85,6 @@ export class Channel {
|
|
|
83
85
|
(activeEffects[activeEffects.length - 1].audioWorkletNode as AudioNode).connect(this.stereoPannerNode);
|
|
84
86
|
}
|
|
85
87
|
|
|
86
|
-
public AddEffect(effect: Effector): void {
|
|
87
|
-
|
|
88
|
-
if (!this.context) {
|
|
89
|
-
Debug.Error("Could not add effect because this channel has no AudioContext.");
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (this.effects.includes(effect)) {
|
|
94
|
-
Debug.Error("Could not add effect because it is already part of this channel", [
|
|
95
|
-
"Call .RemoveEffect([effect Effector]) before adding effect."
|
|
96
|
-
], ErrorCodes.EFFECT_ALREADY_ATTACHED);
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
this.effects.push(effect);
|
|
101
|
-
effect.InitializeOnAttachment(this.context);
|
|
102
|
-
this.rebuildEffectChain();
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
public AttachEffect(effect: Effector): void {
|
|
106
|
-
return this.AddEffect(effect);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
public RemoveEffect(effect: Effector): void {
|
|
110
|
-
|
|
111
|
-
if (!this.effects.includes(effect)) {
|
|
112
|
-
Debug.Error("Could not remove effect, because it is not part of this channel.", [
|
|
113
|
-
"Call .AddEffect([effect Effector]) before removing effect."
|
|
114
|
-
], ErrorCodes.EFFECT_NOT_FOUND);
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const self: Channel = this;
|
|
119
|
-
|
|
120
|
-
this.effects.forEach(function (_effect: Effector, index: number): void {
|
|
121
|
-
if (effect.id === _effect.id)
|
|
122
|
-
self.effects.splice(index, 1);
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
effect.audioWorkletNode?.disconnect();
|
|
126
|
-
|
|
127
|
-
this.rebuildEffectChain();
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
public DetachEffect(effect: Effector): void {
|
|
131
|
-
return this.RemoveEffect(effect);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
88
|
private disconnectAudioNodes(gc?: boolean) {
|
|
135
89
|
|
|
136
90
|
this.input?.disconnect();
|
|
@@ -180,6 +134,69 @@ export class Channel {
|
|
|
180
134
|
return false;
|
|
181
135
|
}
|
|
182
136
|
|
|
137
|
+
/**
|
|
138
|
+
* Public method to manually rebuild the effect chain.
|
|
139
|
+
* Can be useful when the automatic rebuilt did not
|
|
140
|
+
* work properly.
|
|
141
|
+
* @returns
|
|
142
|
+
*/
|
|
143
|
+
public RebuildEffectChain() {
|
|
144
|
+
return this.rebuildEffectChain();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
public AddEffect(effect: Effector): Channel {
|
|
148
|
+
|
|
149
|
+
if (!this.context)
|
|
150
|
+
throw new Error(`Could not add effect (${effect.id}), to channel (${this.id}), because the channel's AudioContext is undefined.`);
|
|
151
|
+
|
|
152
|
+
if (this.effects.includes(effect))
|
|
153
|
+
throw new Error(`Could not add effect (${effect.id}), to channel (${this.id}), because it has already been added to the channel.`);
|
|
154
|
+
|
|
155
|
+
this.effects.push(effect);
|
|
156
|
+
effect.InitializeOnAttachment(this.context);
|
|
157
|
+
this.rebuildEffectChain();
|
|
158
|
+
return this;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
public AttachEffect(effect: Effector): Channel {
|
|
162
|
+
return this.AddEffect(effect);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
public RemoveEffect(effect: Effector): void {
|
|
166
|
+
|
|
167
|
+
if (!this.effects.includes(effect)) {
|
|
168
|
+
Debug.Error("Could not remove effect, because it is not part of this channel.", [
|
|
169
|
+
"Call .AddEffect([effect Effector]) before removing effect."
|
|
170
|
+
], ErrorCodes.EFFECT_NOT_FOUND);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const self: Channel = this;
|
|
175
|
+
|
|
176
|
+
this.effects.forEach(function (_effect: Effector, index: number): void {
|
|
177
|
+
if (effect.id === _effect.id)
|
|
178
|
+
self.effects.splice(index, 1);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
effect.audioWorkletNode?.disconnect();
|
|
182
|
+
|
|
183
|
+
this.rebuildEffectChain();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
public RemoveAllEffects() {
|
|
187
|
+
for (const effect of this.effects) {
|
|
188
|
+
this.RemoveEffect(effect);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
public DetachEffect(effect: Effector): void {
|
|
193
|
+
return this.RemoveEffect(effect);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
public DetachAllEffects() {
|
|
197
|
+
return this.RemoveAllEffects();
|
|
198
|
+
}
|
|
199
|
+
|
|
183
200
|
public Send(channel: Channel | Master) {
|
|
184
201
|
|
|
185
202
|
if (channel instanceof Master)
|
|
@@ -234,7 +251,6 @@ export class Channel {
|
|
|
234
251
|
}
|
|
235
252
|
|
|
236
253
|
public UnsendToAllChannels() {
|
|
237
|
-
|
|
238
254
|
for (var i: number = 0; i < this.sends.length; i++) {
|
|
239
255
|
this.Unsend(this.sends[i]);
|
|
240
256
|
i--;
|
|
@@ -251,19 +267,107 @@ export class Channel {
|
|
|
251
267
|
|
|
252
268
|
public Volume(volume?: number): number {
|
|
253
269
|
|
|
254
|
-
if(!this.context) throw new Error("Could not set volume on channel, because it's context is undefined.");
|
|
255
|
-
if(!this.gainNode) throw new Error("Could not set volume on channel, because it's GainNode is undefined.")
|
|
270
|
+
if (!this.context) throw new Error("Could not set volume on channel, because it's context is undefined.");
|
|
271
|
+
if (!this.gainNode) throw new Error("Could not set volume on channel, because it's GainNode is undefined.")
|
|
256
272
|
|
|
257
273
|
volume && this.gainNode.gain.setValueAtTime(volume, this.context.currentTime);
|
|
258
274
|
return volume ?? this.gainNode.gain.value;
|
|
259
275
|
}
|
|
260
276
|
|
|
261
277
|
public Pan(pan?: number): number {
|
|
262
|
-
|
|
263
|
-
if(!this.context) throw new Error("Could not set pan on channel, because it's context is undefined.");
|
|
264
|
-
if(!this.stereoPannerNode) throw new Error("Cannot set pan on channel, because it's StereoPannerNode is undefined.");
|
|
278
|
+
|
|
279
|
+
if (!this.context) throw new Error("Could not set pan on channel, because it's context is undefined.");
|
|
280
|
+
if (!this.stereoPannerNode) throw new Error("Cannot set pan on channel, because it's StereoPannerNode is undefined.");
|
|
265
281
|
|
|
266
282
|
pan && this.stereoPannerNode.pan.setValueAtTime(pan, this.context.currentTime);
|
|
267
283
|
return pan ?? this.stereoPannerNode.pan.value;
|
|
268
284
|
}
|
|
285
|
+
|
|
286
|
+
public GetEffectsByLabel(label: string): Effector[] {
|
|
287
|
+
return this.effects.filter(effect => effect.label === label);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
public GetFirstEffectByLabel(label: string): Effector | null {
|
|
291
|
+
|
|
292
|
+
const filteredEffects: Effector[] = this.effects.filter(effect => effect.label === label);
|
|
293
|
+
return filteredEffects.length !== 0 ? filteredEffects[0] : null;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
public GetEffectById(id: string): Effector[] {
|
|
297
|
+
return this.effects.filter(effect => effect.id === id);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
public GetFirstEffectById(id: string): Effector | null {
|
|
301
|
+
|
|
302
|
+
const filteredEffects: Effector[] = this.effects.filter(effect => effect.id === id);
|
|
303
|
+
return filteredEffects.length !== 0 ? filteredEffects[0] : null;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
public MoveEffectToIndex(effect: Effector, index: number | ArrayPosition): void {
|
|
307
|
+
|
|
308
|
+
let fromIndex: number = -1,
|
|
309
|
+
matches: number = 0,
|
|
310
|
+
i: number = 0;
|
|
311
|
+
|
|
312
|
+
for (i = 0; i < this.effects.length; i++) {
|
|
313
|
+
if (this.effects[i].id === effect.id) {
|
|
314
|
+
if (fromIndex === -1)
|
|
315
|
+
fromIndex = i;
|
|
316
|
+
|
|
317
|
+
matches++;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (matches === 0) throw new Error(
|
|
322
|
+
"Effect '" + effect.id + "' (" + effect.label + ") could not be found. " +
|
|
323
|
+
"The effect ID may have changed, or the effect is not attached to this channel."
|
|
324
|
+
);
|
|
325
|
+
|
|
326
|
+
if (matches > 1) throw new Error(
|
|
327
|
+
"Multiple effects with the ID '" + effect.id + "' are attached to this channel. " +
|
|
328
|
+
"Make sure every effect has a unique ID."
|
|
329
|
+
);
|
|
330
|
+
|
|
331
|
+
let toIndex: number;
|
|
332
|
+
|
|
333
|
+
if (typeof index === "number") {
|
|
334
|
+
toIndex = index;
|
|
335
|
+
} else {
|
|
336
|
+
switch (index) {
|
|
337
|
+
case "start":
|
|
338
|
+
toIndex = 0;
|
|
339
|
+
break;
|
|
340
|
+
case "end":
|
|
341
|
+
toIndex = this.effects.length - 1;
|
|
342
|
+
break;
|
|
343
|
+
case "one-after-start":
|
|
344
|
+
toIndex = 1;
|
|
345
|
+
break;
|
|
346
|
+
case "one-before-end":
|
|
347
|
+
toIndex = this.effects.length - 2;
|
|
348
|
+
break;
|
|
349
|
+
default:
|
|
350
|
+
throw new Error("Invalid ArrayPosition: " + String(index));
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (toIndex < 0)
|
|
355
|
+
toIndex = 0;
|
|
356
|
+
|
|
357
|
+
if (toIndex >= this.effects.length)
|
|
358
|
+
toIndex = this.effects.length - 1;
|
|
359
|
+
|
|
360
|
+
if (fromIndex === toIndex) return;
|
|
361
|
+
|
|
362
|
+
const item: Effector = this.effects.splice(fromIndex, 1)[0];
|
|
363
|
+
|
|
364
|
+
if (fromIndex < toIndex)
|
|
365
|
+
toIndex = toIndex - 1;
|
|
366
|
+
|
|
367
|
+
this.effects.splice(toIndex, 0, item);
|
|
368
|
+
|
|
369
|
+
// Initializing the effect is unnessecary because it should have been intialized already
|
|
370
|
+
// otherwise it could not been found. Rebuilding the effect chain is nessecary though.
|
|
371
|
+
this.rebuildEffectChain();
|
|
372
|
+
}
|
|
269
373
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { v4 } from "uuid";
|
|
2
2
|
|
|
3
|
-
import { IncomingProcessorMessage,
|
|
3
|
+
import { IncomingProcessorMessage, type EffectorEvents, EffectorEventMap } from "../../typings";
|
|
4
4
|
import { Debug } from "../../utilities/debugger";
|
|
5
5
|
|
|
6
6
|
export abstract class Effector {
|
|
@@ -41,6 +41,7 @@ export abstract class Effector {
|
|
|
41
41
|
protected registerMessageEventListener(node: AudioWorkletNode) {
|
|
42
42
|
if (this.hasRegisteredMessageEventListener) return;
|
|
43
43
|
|
|
44
|
+
this.hasRegisteredMessageEventListener = true;
|
|
44
45
|
node.port.onmessage = this.handleIncomingMessages.bind(this);
|
|
45
46
|
Debug.Log(`Succesfully registered event listener on effector ${this.name} (${this.label}) [${this.id}]`);
|
|
46
47
|
}
|
|
@@ -11,7 +11,7 @@ export class SoftClip extends Effector {
|
|
|
11
11
|
public gain: number = 1;
|
|
12
12
|
public strictMode: StrictMode = StrictMode.Disabled;
|
|
13
13
|
|
|
14
|
-
constructor({ drive, gain, strictMode }: Partial<SoftClipOptions>) {
|
|
14
|
+
constructor({ drive, gain, strictMode }: Partial<SoftClipOptions> = {}) {
|
|
15
15
|
super();
|
|
16
16
|
|
|
17
17
|
this.drive = Math.max(0, CoerceFiniteNumber(drive, this.drive));
|
|
@@ -22,8 +22,12 @@ export class SoftClip extends Effector {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
public async InitializeOnAttachment(context: AudioContext): Promise<void> {
|
|
25
|
-
|
|
26
|
-
this.
|
|
25
|
+
|
|
26
|
+
if(this.context === null)
|
|
27
|
+
this.context = context;
|
|
28
|
+
|
|
29
|
+
if(this.audioWorkletNode === null)
|
|
30
|
+
this.audioWorkletNode = CreateAudioWorkletNode<SoftClipOptions>(context, AudioWorkletProcessorNames.SoftClip, this.ReturnOptionsAsObject());
|
|
27
31
|
}
|
|
28
32
|
|
|
29
33
|
public ReturnOptionsAsObject(): SoftClipOptions {
|
package/lib/src/index.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { DspOptions } from "./typings";
|
|
|
8
8
|
export const DSP: DspOptions = {
|
|
9
9
|
maxMasterChannels: 8,
|
|
10
10
|
maxTotalChannels: 128,
|
|
11
|
-
sampleRate:
|
|
11
|
+
sampleRate: 41000,
|
|
12
12
|
spatialization: "stereo",
|
|
13
13
|
overrideMaxAudioBufferNodes: false,
|
|
14
14
|
debugger: {
|
|
@@ -80,7 +80,7 @@ export {
|
|
|
80
80
|
SoftClipMessageCommandId,
|
|
81
81
|
AudioWorkletProcessorNames,
|
|
82
82
|
ChorusMessageCommandId,
|
|
83
|
-
LowPassFilterMessageCommandId
|
|
83
|
+
LowPassFilterMessageCommandId,
|
|
84
84
|
} from "./typings";
|
|
85
85
|
|
|
86
86
|
export type {
|
|
@@ -106,4 +106,5 @@ export type {
|
|
|
106
106
|
IncomingProcessorMessage,
|
|
107
107
|
ProcessorData,
|
|
108
108
|
EffectorEvents,
|
|
109
|
-
|
|
109
|
+
ArrayPosition
|
|
110
|
+
} from "./typings";
|
package/lib/src/typings.ts
CHANGED
|
@@ -2,6 +2,8 @@ export type ChannelSpatialization = "mono" | "stereo" | "surround";
|
|
|
2
2
|
export type AudioClipAnalyserType = "pre" | "post";
|
|
3
3
|
export type AudioClipAnalyserProperty = "fftSize" | "minDecibels" | "maxDecibels" | "smoothingTimeConstant";
|
|
4
4
|
export type IncomingMessageType = "message" | "error" | "warning" | "wasm-instantiated";
|
|
5
|
+
export type ArrayPosition = "start" | "middle" | "end" | "one-after-start" | "one-before-end";
|
|
6
|
+
|
|
5
7
|
|
|
6
8
|
export type AudioClipEvents = {
|
|
7
9
|
[K in keyof AudioClipEventMap]: AudioClipEventMap[K][];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluex/fluexgl-dsp",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.6",
|
|
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",
|