@fluex/fluexgl-dsp 0.3.1 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/dist/core/classes/Channel.js +10 -8
- package/lib/dist/core/classes/Effector.d.ts +9 -0
- package/lib/dist/core/classes/Effector.d.ts.map +1 -1
- package/lib/dist/core/classes/Effector.js +56 -0
- package/lib/dist/effects/classes/filters/LowPassFilter.d.ts +3 -1
- package/lib/dist/effects/classes/filters/LowPassFilter.d.ts.map +1 -1
- package/lib/dist/effects/classes/filters/LowPassFilter.js +14 -4
- package/lib/dist/index.d.ts +1 -1
- package/lib/dist/index.d.ts.map +1 -1
- package/lib/dist/typings.d.ts +32 -1
- package/lib/dist/typings.d.ts.map +1 -1
- package/lib/dist/typings.js +7 -1
- package/lib/src/core/classes/Channel.ts +17 -17
- package/lib/src/core/classes/Effector.ts +79 -2
- package/lib/src/effects/classes/filters/LowPassFilter.ts +17 -5
- package/lib/src/index.ts +7 -1
- package/lib/src/typings.ts +38 -5
- package/package.json +1 -1
|
@@ -22,29 +22,31 @@ export class Channel {
|
|
|
22
22
|
}
|
|
23
23
|
rebuildEffectChain() {
|
|
24
24
|
Debug.Log("Attempting to rebuild effect chain.");
|
|
25
|
-
if (!this.audioClipsInputGainNode || !this.
|
|
26
|
-
return Debug.Error("Could not rebuild effect chain, because one or more
|
|
25
|
+
if (!this.audioClipsInputGainNode || !this.stereoPannerNode) {
|
|
26
|
+
return Debug.Error("Could not rebuild effect chain, because one or more nodes on this channel are undefined.", [
|
|
27
27
|
`Channel id: ${this.id}.`,
|
|
28
28
|
`Current amount of effects: ${this.effects.length}.`
|
|
29
29
|
]);
|
|
30
|
+
}
|
|
30
31
|
this.audioClipsInputGainNode.disconnect();
|
|
31
32
|
for (const effect of this.effects) {
|
|
32
33
|
effect.audioWorkletNode?.disconnect();
|
|
33
34
|
}
|
|
34
|
-
const activeEffects = this.effects.filter(
|
|
35
|
+
const activeEffects = this.effects.filter(function (e) {
|
|
36
|
+
return !!e.audioWorkletNode;
|
|
37
|
+
});
|
|
35
38
|
if (activeEffects.length === 0) {
|
|
36
|
-
this.audioClipsInputGainNode.connect(this.
|
|
39
|
+
this.audioClipsInputGainNode.connect(this.stereoPannerNode);
|
|
37
40
|
}
|
|
38
41
|
else {
|
|
39
|
-
|
|
40
|
-
this.audioClipsInputGainNode.connect(firstEffectGain);
|
|
42
|
+
this.audioClipsInputGainNode.connect(activeEffects[0].audioWorkletNode);
|
|
41
43
|
for (let i = 0; i < activeEffects.length - 1; i++) {
|
|
42
44
|
const current = activeEffects[i].audioWorkletNode;
|
|
43
45
|
const next = activeEffects[i + 1].audioWorkletNode;
|
|
44
46
|
current.connect(next);
|
|
45
47
|
}
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
+
const lastEffectNode = activeEffects[activeEffects.length - 1].audioWorkletNode;
|
|
49
|
+
lastEffectNode.connect(this.stereoPannerNode);
|
|
48
50
|
}
|
|
49
51
|
Debug.Success("Successfully rebuilt effect chain.", [
|
|
50
52
|
`Channel id: ${this.id}.`,
|
|
@@ -1,9 +1,18 @@
|
|
|
1
|
+
import { EffectorEventMap } from "../../typings";
|
|
1
2
|
export declare abstract class Effector {
|
|
2
3
|
id: string;
|
|
3
4
|
label: string | null;
|
|
4
5
|
name: string;
|
|
5
6
|
audioWorkletNode: AudioWorkletNode | null;
|
|
6
7
|
parentialContext: AudioContext | null;
|
|
8
|
+
private hasRegisteredMessageEventListener;
|
|
9
|
+
private events;
|
|
10
|
+
private handleIncomingMessages;
|
|
11
|
+
protected registerMessageEventListener(node: AudioWorkletNode): void;
|
|
12
|
+
AddEventListener<K extends keyof EffectorEventMap>(event: K, cb: EffectorEventMap[K]): () => void;
|
|
13
|
+
Once<K extends keyof EffectorEventMap>(event: K, cb: EffectorEventMap[K]): () => void;
|
|
14
|
+
RemoveEventListener<K extends keyof EffectorEventMap>(event: K, cb: EffectorEventMap[K]): Effector;
|
|
15
|
+
ClearEventListeners(event?: keyof EffectorEventMap): Effector;
|
|
7
16
|
abstract InitializeOnAttachment(parentialContext: AudioContext): Promise<void>;
|
|
8
17
|
}
|
|
9
18
|
//# sourceMappingURL=Effector.d.ts.map
|
|
@@ -1 +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,IAAI,EAAE,MAAM,CAAc;IAC1B,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAQ;IACjD,gBAAgB,EAAE,YAAY,GAAG,IAAI,CAAQ;
|
|
1
|
+
{"version":3,"file":"Effector.d.ts","sourceRoot":"","sources":["../../../src/core/classes/Effector.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEhH,8BAAsB,QAAQ;IAEnB,EAAE,EAAE,MAAM,CAAQ;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC5B,IAAI,EAAE,MAAM,CAAc;IAC1B,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAQ;IACjD,gBAAgB,EAAE,YAAY,GAAG,IAAI,CAAQ;IAEpD,OAAO,CAAC,iCAAiC,CAAkB;IAE3D,OAAO,CAAC,MAAM,CAMb;IAED,OAAO,CAAC,sBAAsB;IAgB9B,SAAS,CAAC,4BAA4B,CAAC,IAAI,EAAE,gBAAgB;IAKtD,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,gBAAgB,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;CACxF"}
|
|
@@ -5,4 +5,60 @@ export class Effector {
|
|
|
5
5
|
name = "Effector";
|
|
6
6
|
audioWorkletNode = null;
|
|
7
7
|
parentialContext = null;
|
|
8
|
+
hasRegisteredMessageEventListener = false;
|
|
9
|
+
events = {
|
|
10
|
+
"incoming-processor-error": [],
|
|
11
|
+
"incoming-processor-message": [],
|
|
12
|
+
"incoming-processor-warning": [],
|
|
13
|
+
"processor-wasm-instantiated": [],
|
|
14
|
+
"initialized-on-channel-attachment": []
|
|
15
|
+
};
|
|
16
|
+
handleIncomingMessages(event) {
|
|
17
|
+
const messageData = event.data;
|
|
18
|
+
switch (messageData.type) {
|
|
19
|
+
case "message":
|
|
20
|
+
return this.events["incoming-processor-message"].forEach(ev => ev(messageData));
|
|
21
|
+
case "error":
|
|
22
|
+
return this.events["incoming-processor-error"].forEach(ev => ev(messageData));
|
|
23
|
+
case "warning":
|
|
24
|
+
return this.events["incoming-processor-message"].forEach(ev => ev(messageData));
|
|
25
|
+
case "wasm-instantiated":
|
|
26
|
+
return this.events["processor-wasm-instantiated"].forEach(ev => ev(messageData));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
registerMessageEventListener(node) {
|
|
30
|
+
if (!this.hasRegisteredMessageEventListener)
|
|
31
|
+
node.port.onmessage = this.handleIncomingMessages.bind(this);
|
|
32
|
+
}
|
|
33
|
+
AddEventListener(event, cb) {
|
|
34
|
+
this.events[event].push(cb);
|
|
35
|
+
return () => this.RemoveEventListener(event, cb);
|
|
36
|
+
}
|
|
37
|
+
Once(event, cb) {
|
|
38
|
+
const wrapper = ((...args) => {
|
|
39
|
+
// @ts-ignore
|
|
40
|
+
cb(...args);
|
|
41
|
+
this.RemoveEventListener(event, wrapper);
|
|
42
|
+
});
|
|
43
|
+
return this.AddEventListener(event, wrapper);
|
|
44
|
+
}
|
|
45
|
+
RemoveEventListener(event, cb) {
|
|
46
|
+
const arr = this.events[event];
|
|
47
|
+
for (let i = 0; i < arr.length; i++) {
|
|
48
|
+
if (arr[i] === cb) {
|
|
49
|
+
arr.splice(i, 1);
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return this;
|
|
54
|
+
}
|
|
55
|
+
ClearEventListeners(event) {
|
|
56
|
+
if (event) {
|
|
57
|
+
this.events[event].length = 0;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
Object.keys(this.events).forEach((k) => (this.events[k].length = 0));
|
|
61
|
+
}
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
8
64
|
}
|
|
@@ -4,11 +4,13 @@ export declare class LowPassFilter extends Effector {
|
|
|
4
4
|
name: string;
|
|
5
5
|
label: string | null;
|
|
6
6
|
cutoff: number;
|
|
7
|
+
q: number;
|
|
7
8
|
minFrequency: number;
|
|
8
|
-
constructor({ cutoff, minFrequency }: Partial<LowPassFilterOptions>);
|
|
9
|
+
constructor({ cutoff, minFrequency, q }: Partial<LowPassFilterOptions>);
|
|
9
10
|
InitializeOnAttachment(parentialContext: AudioContext): Promise<void>;
|
|
10
11
|
ReturnOptionsAsObject(): LowPassFilterOptions;
|
|
11
12
|
SetCutoff(cutoff?: number): boolean;
|
|
12
13
|
SetMinFrequency(minFrequency?: number): boolean;
|
|
14
|
+
SetQ(q?: number): boolean;
|
|
13
15
|
}
|
|
14
16
|
//# sourceMappingURL=LowPassFilter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LowPassFilter.d.ts","sourceRoot":"","sources":["../../../../src/effects/classes/filters/LowPassFilter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAI1D,OAAO,EAAE,oBAAoB,EAA6D,MAAM,kBAAkB,CAAC;AAEnH,qBAAa,aAAc,SAAQ,QAAQ;IAEhC,IAAI,EAAE,MAAM,CAAmB;IAC/B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAmB;IAEvC,MAAM,EAAE,MAAM,CAAQ;IACtB,YAAY,EAAE,MAAM,CAAM;gBAErB,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,OAAO,CAAC,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"LowPassFilter.d.ts","sourceRoot":"","sources":["../../../../src/effects/classes/filters/LowPassFilter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAI1D,OAAO,EAAE,oBAAoB,EAA6D,MAAM,kBAAkB,CAAC;AAEnH,qBAAa,aAAc,SAAQ,QAAQ;IAEhC,IAAI,EAAE,MAAM,CAAmB;IAC/B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAmB;IAEvC,MAAM,EAAE,MAAM,CAAQ;IACtB,CAAC,EAAE,MAAM,CAAO;IAChB,YAAY,EAAE,MAAM,CAAM;gBAErB,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,EAAE,EAAE,OAAO,CAAC,oBAAoB,CAAC;IAQzD,sBAAsB,CAAC,gBAAgB,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAO3E,qBAAqB,IAAI,oBAAoB;IAQ7C,SAAS,CAAC,MAAM,GAAE,MAAa,GAAG,OAAO;IAWzC,eAAe,CAAC,YAAY,GAAE,MAAW,GAAG,OAAO;IASnD,IAAI,CAAC,CAAC,GAAE,MAAY,GAAG,OAAO;CAQxC"}
|
|
@@ -4,24 +4,28 @@ import { LowPassFilterMessageCommandId, AudioWorkletProcessorNames } from "../..
|
|
|
4
4
|
export class LowPassFilter extends Effector {
|
|
5
5
|
name = "LowPassFilter";
|
|
6
6
|
label = "LowPassFilter";
|
|
7
|
-
cutoff =
|
|
7
|
+
cutoff = 1000;
|
|
8
|
+
q = 0.7;
|
|
8
9
|
minFrequency = 10;
|
|
9
|
-
constructor({ cutoff, minFrequency }) {
|
|
10
|
+
constructor({ cutoff, minFrequency, q }) {
|
|
10
11
|
super();
|
|
11
12
|
this.cutoff = cutoff ?? this.cutoff;
|
|
12
13
|
this.minFrequency = minFrequency ?? this.minFrequency;
|
|
14
|
+
this.q = q ?? this.q;
|
|
13
15
|
}
|
|
14
16
|
async InitializeOnAttachment(parentialContext) {
|
|
15
17
|
this.parentialContext = parentialContext;
|
|
16
18
|
this.audioWorkletNode = CreateAudioWorkletNode(parentialContext, AudioWorkletProcessorNames.LowPassFilter, this.ReturnOptionsAsObject());
|
|
19
|
+
this.registerMessageEventListener(this.audioWorkletNode);
|
|
17
20
|
}
|
|
18
21
|
ReturnOptionsAsObject() {
|
|
19
22
|
return {
|
|
20
23
|
cutoff: this.cutoff,
|
|
21
|
-
minFrequency: this.minFrequency
|
|
24
|
+
minFrequency: this.minFrequency,
|
|
25
|
+
q: this.q
|
|
22
26
|
};
|
|
23
27
|
}
|
|
24
|
-
SetCutoff(cutoff =
|
|
28
|
+
SetCutoff(cutoff = 1000) {
|
|
25
29
|
if (!this.parentialContext)
|
|
26
30
|
return false;
|
|
27
31
|
if (cutoff >= this.parentialContext.sampleRate)
|
|
@@ -35,4 +39,10 @@ export class LowPassFilter extends Effector {
|
|
|
35
39
|
this.minFrequency = minFrequency;
|
|
36
40
|
return SendMessageToWorklet(this.audioWorkletNode, LowPassFilterMessageCommandId.SetMinFrequency, minFrequency);
|
|
37
41
|
}
|
|
42
|
+
SetQ(q = 0.7) {
|
|
43
|
+
if (q > 4)
|
|
44
|
+
q = 4;
|
|
45
|
+
this.q = q;
|
|
46
|
+
return SendMessageToWorklet(this.audioWorkletNode, LowPassFilterMessageCommandId.SetQ, q);
|
|
47
|
+
}
|
|
38
48
|
}
|
package/lib/dist/index.d.ts
CHANGED
|
@@ -9,5 +9,5 @@ export { AudioDevice, Channel, Effector, Master, AudioClip, DspPipeline } from "
|
|
|
9
9
|
export { InitializeDspPipeline, ResolveAudioOutputDevices, ResolveAudioInputDevices, ResolveDefaultAudioInputDevice, ResolveDefaultAudioOutputDevice, LoadAudioSource, LoadAudioSourceFromBlob, LoadWorkletOnMasterChannel, SendMessageToWorklet } from "./utilities/helpers";
|
|
10
10
|
export { SUPPORTED_FILE_TYPES } from "./utilities/constants";
|
|
11
11
|
export { hasInitializedWasm, } from "./utilities/web-assembly";
|
|
12
|
-
export type { FluexGLAudioDescriptor, FluexGLAudioDebuggerOptions, FluexGLAudioOptions, LoadAudioSourceOptions, AudioSourceData, ChannelOptions, ChannelSpatialization, AudioClipEventMap, AudioClipEvents, AudioClipOnProgressEvent, AudioClipAnalyserProperty, AudioClipAnalyserType, DspPipelineInitializationOptions, DspPipelineInitializationState, ChorusEffectOptions, LowPassFilterOptions, LowPassFilterMessageCommandId, ChorusMessageCommandId, AudioWorkletProcessorNames, SoftClipMessageCommandId, SoftClipOptions, HardClipMessageCommandId, HardClipOptions } from "./typings";
|
|
12
|
+
export type { FluexGLAudioDescriptor, FluexGLAudioDebuggerOptions, FluexGLAudioOptions, LoadAudioSourceOptions, AudioSourceData, ChannelOptions, ChannelSpatialization, AudioClipEventMap, AudioClipEvents, AudioClipOnProgressEvent, AudioClipAnalyserProperty, AudioClipAnalyserType, DspPipelineInitializationOptions, DspPipelineInitializationState, ChorusEffectOptions, LowPassFilterOptions, LowPassFilterMessageCommandId, ChorusMessageCommandId, AudioWorkletProcessorNames, SoftClipMessageCommandId, SoftClipOptions, HardClipMessageCommandId, HardClipOptions, EffectorEventMap, IncomingMessageType, IncomingProcessorMessage, ProcessorData, ProcessorIdentificationCodes, EffectorEvents } from "./typings";
|
|
13
13
|
//# 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,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAEnD,eAAO,MAAM,YAAY,EAAE,sBAkB1B,CAAA;AAED,OAAO,EACH,MAAM,EACN,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,EACd,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACH,qBAAqB,EACrB,yBAAyB,EACzB,wBAAwB,EACxB,8BAA8B,EAC9B,+BAA+B,EAC/B,eAAe,EACf,uBAAuB,EACvB,0BAA0B,EAC1B,oBAAoB,EACvB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACH,oBAAoB,EACvB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACH,kBAAkB,GACrB,MAAM,0BAA0B,CAAC;AAElC,YAAY,EACR,sBAAsB,EACtB,2BAA2B,EAC3B,mBAAmB,EACnB,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,6BAA6B,EAC7B,sBAAsB,EACtB,0BAA0B,EAC1B,wBAAwB,EACxB,eAAe,EACf,wBAAwB,EACxB,eAAe,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AAEnD,eAAO,MAAM,YAAY,EAAE,sBAkB1B,CAAA;AAED,OAAO,EACH,MAAM,EACN,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,EACd,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACH,qBAAqB,EACrB,yBAAyB,EACzB,wBAAwB,EACxB,8BAA8B,EAC9B,+BAA+B,EAC/B,eAAe,EACf,uBAAuB,EACvB,0BAA0B,EAC1B,oBAAoB,EACvB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACH,oBAAoB,EACvB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACH,kBAAkB,GACrB,MAAM,0BAA0B,CAAC;AAElC,YAAY,EACR,sBAAsB,EACtB,2BAA2B,EAC3B,mBAAmB,EACnB,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,6BAA6B,EAC7B,sBAAsB,EACtB,0BAA0B,EAC1B,wBAAwB,EACxB,eAAe,EACf,wBAAwB,EACxB,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,wBAAwB,EACxB,aAAa,EACb,4BAA4B,EAC5B,cAAc,EACjB,MAAM,WAAW,CAAC"}
|
package/lib/dist/typings.d.ts
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
export type ChannelSpatialization = "mono" | "stereo" | "surround";
|
|
2
2
|
export type AudioClipAnalyserType = "pre" | "post";
|
|
3
3
|
export type AudioClipAnalyserProperty = "fftSize" | "minDecibels" | "maxDecibels" | "smoothingTimeConstant";
|
|
4
|
+
export type IncomingMessageType = "message" | "error" | "warning" | "wasm-instantiated";
|
|
4
5
|
export type AudioClipEvents = {
|
|
5
6
|
[K in keyof AudioClipEventMap]: AudioClipEventMap[K][];
|
|
6
7
|
};
|
|
8
|
+
export type EffectorEvents = {
|
|
9
|
+
[K in keyof EffectorEventMap]: EffectorEventMap[K][];
|
|
10
|
+
};
|
|
7
11
|
export declare enum LowPassFilterMessageCommandId {
|
|
8
12
|
SetCutoff = 0,
|
|
9
|
-
SetMinFrequency = 1
|
|
13
|
+
SetMinFrequency = 1,
|
|
14
|
+
SetQ = 2
|
|
10
15
|
}
|
|
11
16
|
export declare enum ChorusMessageCommandId {
|
|
12
17
|
SetBaseDelayMs = 0,
|
|
@@ -41,6 +46,11 @@ export declare enum AudioWorkletProcessorNames {
|
|
|
41
46
|
SoftClip = "SoftClipProcessor",
|
|
42
47
|
HardClip = "HardClipProcessor"
|
|
43
48
|
}
|
|
49
|
+
export declare enum ProcessorIdentificationCodes {
|
|
50
|
+
UnknownProcessorId = "UNKNOWN_PROCESSOR_ID",
|
|
51
|
+
UnknownProcessorName = "UNKNOWN_PROCESSOR_NAME",
|
|
52
|
+
UnknownProcessorCreationDate = "UNKNOWN_PROCESSOR_CREATION_DATE"
|
|
53
|
+
}
|
|
44
54
|
export interface FluexGLAudioDebuggerOptions {
|
|
45
55
|
breakOnError: boolean;
|
|
46
56
|
showInfo: boolean;
|
|
@@ -104,6 +114,7 @@ export interface ChorusEffectOptions {
|
|
|
104
114
|
export interface LowPassFilterOptions {
|
|
105
115
|
cutoff: number;
|
|
106
116
|
minFrequency: number;
|
|
117
|
+
q: number;
|
|
107
118
|
}
|
|
108
119
|
export interface SoftClipOptions {
|
|
109
120
|
drive: number;
|
|
@@ -113,4 +124,24 @@ export interface HardClipOptions {
|
|
|
113
124
|
drive: number;
|
|
114
125
|
gain: number;
|
|
115
126
|
}
|
|
127
|
+
export interface EffectorEventMap {
|
|
128
|
+
"incoming-processor-message": (message: IncomingProcessorMessage) => void;
|
|
129
|
+
"incoming-processor-warning": (message: IncomingProcessorMessage) => void;
|
|
130
|
+
"incoming-processor-error": (message: IncomingProcessorMessage) => void;
|
|
131
|
+
"initialized-on-channel-attachment": (message: IncomingProcessorMessage) => void;
|
|
132
|
+
"processor-wasm-instantiated": (message: IncomingProcessorMessage) => void;
|
|
133
|
+
}
|
|
134
|
+
export interface ProcessorData {
|
|
135
|
+
id: string | ProcessorIdentificationCodes.UnknownProcessorId;
|
|
136
|
+
name: string | ProcessorIdentificationCodes.UnknownProcessorName;
|
|
137
|
+
createdAt: number | ProcessorIdentificationCodes.UnknownProcessorCreationDate;
|
|
138
|
+
}
|
|
139
|
+
export interface IncomingProcessorMessage {
|
|
140
|
+
id: string;
|
|
141
|
+
timestamp: number;
|
|
142
|
+
message: string;
|
|
143
|
+
type: IncomingMessageType;
|
|
144
|
+
processor: ProcessorData;
|
|
145
|
+
additionalData?: any;
|
|
146
|
+
}
|
|
116
147
|
//# sourceMappingURL=typings.d.ts.map
|
|
@@ -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;
|
|
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;AAExF,MAAM,MAAM,eAAe,GAAG;KACzB,CAAC,IAAI,MAAM,iBAAiB,GAAG,iBAAiB,CAAC,CAAC,CAAC,EAAE;CACzD,CAAA;AAED,MAAM,MAAM,cAAc,GAAG;KACxB,CAAC,IAAI,MAAM,gBAAgB,GAAG,gBAAgB,CAAC,CAAC,CAAC,EAAE;CACvD,CAAA;AAED,oBAAY,6BAA6B;IACrC,SAAS,IAAA;IACT,eAAe,IAAA;IACf,IAAI,IAAA;CACP;AAED,oBAAY,sBAAsB;IAC9B,cAAc,IAAA;IACd,UAAU,IAAA;IACV,SAAS,IAAA;IACT,MAAM,IAAA;IACN,WAAW,IAAA;CACd;AAED,oBAAY,wBAAwB;IAChC,QAAQ,IAAA;IACR,OAAO,IAAA;CACV;AAED,oBAAY,wBAAwB;IAChC,QAAQ,IAAA;IACR,OAAO,IAAA;CACV;AAED,oBAAY,0BAA0B;IAClC,UAAU,wBAAwB;IAClC,mBAAmB,iCAAiC;IACpD,aAAa,2BAA2B;IACxC,SAAS,uBAAuB;IAChC,aAAa,2BAA2B;IACxC,WAAW,yBAAyB;IACpC,aAAa,2BAA2B;IACxC,cAAc,4BAA4B;IAC1C,cAAc,4BAA4B;IAC1C,WAAW,yBAAyB;IACpC,MAAM,oBAAoB;IAC1B,OAAO,qBAAqB;IAC5B,MAAM,oBAAoB;IAC1B,MAAM,oBAAoB;IAC1B,QAAQ,sBAAsB;IAC9B,QAAQ,sBAAsB;CACjC;AAED,oBAAY,4BAA4B;IACpC,kBAAkB,yBAAyB;IAC3C,oBAAoB,2BAA2B;IAC/C,4BAA4B,oCAAoC;CACnE;AAED,MAAM,WAAW,2BAA2B;IACxC,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,mBAAmB;IAChC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,qBAAqB,CAAC;IACtC,QAAQ,EAAE,2BAA2B,CAAC;CACzC;AAED,MAAM,WAAW,sBAAsB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,mBAAmB,CAAC;CAChC;AAED,MAAM,WAAW,sBAAsB;IACnC,qBAAqB,EAAE,OAAO,CAAC;CAClC;AAED,MAAM,WAAW,eAAe;IAC5B,WAAW,EAAE,WAAW,CAAC;IACzB,WAAW,EAAE,WAAW,CAAC;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC3B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,wBAAwB;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAC9B,UAAU,EAAE,CAAC,KAAK,EAAE,wBAAwB,KAAK,IAAI,CAAC;CACzD;AAED,MAAM,WAAW,gCAAgC;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,8BAA8B;IAC3C,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;CAC1B;AAID,MAAM,WAAW,mBAAmB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,eAAe;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC7B,4BAA4B,EAAE,CAAC,OAAO,EAAE,wBAAwB,KAAK,IAAI,CAAC;IAC1E,4BAA4B,EAAE,CAAC,OAAO,EAAE,wBAAwB,KAAK,IAAI,CAAC;IAC1E,0BAA0B,EAAE,CAAC,OAAO,EAAE,wBAAwB,KAAK,IAAI,CAAC;IACxE,mCAAmC,EAAE,CAAC,OAAO,EAAE,wBAAwB,KAAK,IAAI,CAAC;IACjF,6BAA6B,EAAE,CAAC,OAAO,EAAE,wBAAwB,KAAK,IAAI,CAAC;CAC9E;AAED,MAAM,WAAW,aAAa;IAC1B,EAAE,EAAE,MAAM,GAAG,4BAA4B,CAAC,kBAAkB,CAAC;IAC7D,IAAI,EAAE,MAAM,GAAG,4BAA4B,CAAC,oBAAoB,CAAC;IACjE,SAAS,EAAE,MAAM,GAAG,4BAA4B,CAAC,4BAA4B,CAAC;CACjF;AAED,MAAM,WAAW,wBAAwB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,mBAAmB,CAAC;IAC1B,SAAS,EAAE,aAAa,CAAC;IACzB,cAAc,CAAC,EAAE,GAAG,CAAC;CACxB"}
|
package/lib/dist/typings.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
// ======== Audio worklet command id's ========
|
|
2
1
|
export var LowPassFilterMessageCommandId;
|
|
3
2
|
(function (LowPassFilterMessageCommandId) {
|
|
4
3
|
LowPassFilterMessageCommandId[LowPassFilterMessageCommandId["SetCutoff"] = 0] = "SetCutoff";
|
|
5
4
|
LowPassFilterMessageCommandId[LowPassFilterMessageCommandId["SetMinFrequency"] = 1] = "SetMinFrequency";
|
|
5
|
+
LowPassFilterMessageCommandId[LowPassFilterMessageCommandId["SetQ"] = 2] = "SetQ";
|
|
6
6
|
})(LowPassFilterMessageCommandId || (LowPassFilterMessageCommandId = {}));
|
|
7
7
|
export var ChorusMessageCommandId;
|
|
8
8
|
(function (ChorusMessageCommandId) {
|
|
@@ -41,3 +41,9 @@ export var AudioWorkletProcessorNames;
|
|
|
41
41
|
AudioWorkletProcessorNames["SoftClip"] = "SoftClipProcessor";
|
|
42
42
|
AudioWorkletProcessorNames["HardClip"] = "HardClipProcessor";
|
|
43
43
|
})(AudioWorkletProcessorNames || (AudioWorkletProcessorNames = {}));
|
|
44
|
+
export var ProcessorIdentificationCodes;
|
|
45
|
+
(function (ProcessorIdentificationCodes) {
|
|
46
|
+
ProcessorIdentificationCodes["UnknownProcessorId"] = "UNKNOWN_PROCESSOR_ID";
|
|
47
|
+
ProcessorIdentificationCodes["UnknownProcessorName"] = "UNKNOWN_PROCESSOR_NAME";
|
|
48
|
+
ProcessorIdentificationCodes["UnknownProcessorCreationDate"] = "UNKNOWN_PROCESSOR_CREATION_DATE";
|
|
49
|
+
})(ProcessorIdentificationCodes || (ProcessorIdentificationCodes = {}));
|
|
@@ -37,38 +37,38 @@ export class Channel {
|
|
|
37
37
|
private rebuildEffectChain() {
|
|
38
38
|
Debug.Log("Attempting to rebuild effect chain.");
|
|
39
39
|
|
|
40
|
-
if (!this.audioClipsInputGainNode || !this.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
40
|
+
if (!this.audioClipsInputGainNode || !this.stereoPannerNode) {
|
|
41
|
+
return Debug.Error(
|
|
42
|
+
"Could not rebuild effect chain, because one or more nodes on this channel are undefined.",
|
|
43
|
+
[
|
|
44
|
+
`Channel id: ${this.id}.`,
|
|
45
|
+
`Current amount of effects: ${this.effects.length}.`
|
|
46
|
+
]
|
|
47
|
+
);
|
|
48
|
+
}
|
|
45
49
|
this.audioClipsInputGainNode.disconnect();
|
|
46
50
|
|
|
47
51
|
for (const effect of this.effects) {
|
|
48
52
|
effect.audioWorkletNode?.disconnect();
|
|
49
53
|
}
|
|
50
54
|
|
|
51
|
-
const activeEffects = this.effects.filter(
|
|
55
|
+
const activeEffects = this.effects.filter(function (e) {
|
|
56
|
+
return !!e.audioWorkletNode;
|
|
57
|
+
});
|
|
52
58
|
|
|
53
59
|
if (activeEffects.length === 0) {
|
|
54
|
-
|
|
55
|
-
this.audioClipsInputGainNode.connect(this.gainNode);
|
|
60
|
+
this.audioClipsInputGainNode.connect(this.stereoPannerNode);
|
|
56
61
|
} else {
|
|
57
|
-
|
|
58
|
-
const firstEffectGain = activeEffects[0].audioWorkletNode!;
|
|
59
|
-
this.audioClipsInputGainNode.connect(firstEffectGain);
|
|
62
|
+
this.audioClipsInputGainNode.connect(activeEffects[0].audioWorkletNode!);
|
|
60
63
|
|
|
61
64
|
for (let i = 0; i < activeEffects.length - 1; i++) {
|
|
62
|
-
|
|
63
65
|
const current = activeEffects[i].audioWorkletNode!;
|
|
64
66
|
const next = activeEffects[i + 1].audioWorkletNode!;
|
|
65
|
-
|
|
66
67
|
current.connect(next);
|
|
67
68
|
}
|
|
68
69
|
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
lastEffectGain.connect(this.gainNode);
|
|
70
|
+
const lastEffectNode = activeEffects[activeEffects.length - 1].audioWorkletNode!;
|
|
71
|
+
lastEffectNode.connect(this.stereoPannerNode);
|
|
72
72
|
}
|
|
73
73
|
|
|
74
74
|
Debug.Success("Successfully rebuilt effect chain.", [
|
|
@@ -258,7 +258,7 @@ export class Channel {
|
|
|
258
258
|
|
|
259
259
|
public SetAnalyserOptions(options: AnalyserOptions): Channel | null {
|
|
260
260
|
|
|
261
|
-
this.analyserOptions = {...options};
|
|
261
|
+
this.analyserOptions = { ...options };
|
|
262
262
|
|
|
263
263
|
if (!this.analyserNode) return null;
|
|
264
264
|
|
|
@@ -1,12 +1,89 @@
|
|
|
1
1
|
import { v4 } from "uuid";
|
|
2
2
|
|
|
3
|
+
import { IncomingProcessorMessage, IncomingMessageType, EffectorEvents, EffectorEventMap } from "../../typings";
|
|
4
|
+
|
|
3
5
|
export abstract class Effector {
|
|
4
|
-
|
|
6
|
+
|
|
5
7
|
public id: string = v4();
|
|
6
8
|
public label: string | null = null;
|
|
7
9
|
public name: string = "Effector";
|
|
8
10
|
public audioWorkletNode: AudioWorkletNode | null = null;
|
|
9
11
|
public parentialContext: AudioContext | null = null;
|
|
10
12
|
|
|
13
|
+
private hasRegisteredMessageEventListener: boolean = false;
|
|
14
|
+
|
|
15
|
+
private events: EffectorEvents = {
|
|
16
|
+
"incoming-processor-error": [],
|
|
17
|
+
"incoming-processor-message": [],
|
|
18
|
+
"incoming-processor-warning": [],
|
|
19
|
+
"processor-wasm-instantiated": [],
|
|
20
|
+
"initialized-on-channel-attachment": []
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
private handleIncomingMessages(event: MessageEvent) {
|
|
24
|
+
|
|
25
|
+
const messageData = event.data as IncomingProcessorMessage;
|
|
26
|
+
|
|
27
|
+
switch (messageData.type) {
|
|
28
|
+
case "message":
|
|
29
|
+
return this.events["incoming-processor-message"].forEach(ev => ev(messageData));
|
|
30
|
+
case "error":
|
|
31
|
+
return this.events["incoming-processor-error"].forEach(ev => ev(messageData));
|
|
32
|
+
case "warning":
|
|
33
|
+
return this.events["incoming-processor-message"].forEach(ev => ev(messageData));
|
|
34
|
+
case "wasm-instantiated":
|
|
35
|
+
return this.events["processor-wasm-instantiated"].forEach(ev => ev(messageData));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
protected registerMessageEventListener(node: AudioWorkletNode) {
|
|
40
|
+
if (!this.hasRegisteredMessageEventListener)
|
|
41
|
+
node.port.onmessage = this.handleIncomingMessages.bind(this);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public AddEventListener<K extends keyof EffectorEventMap>(event: K, cb: EffectorEventMap[K]): () => void {
|
|
45
|
+
|
|
46
|
+
this.events[event].push(cb);
|
|
47
|
+
|
|
48
|
+
return () => this.RemoveEventListener(event, cb);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public Once<K extends keyof EffectorEventMap>(event: K, cb: EffectorEventMap[K]): () => void {
|
|
52
|
+
|
|
53
|
+
const wrapper = ((...args: unknown[]) => {
|
|
54
|
+
|
|
55
|
+
// @ts-ignore
|
|
56
|
+
cb(...args);
|
|
57
|
+
|
|
58
|
+
this.RemoveEventListener(event, wrapper as unknown as EffectorEventMap[K]);
|
|
59
|
+
}) as unknown as EffectorEventMap[K];
|
|
60
|
+
|
|
61
|
+
return this.AddEventListener(event, wrapper);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public RemoveEventListener<K extends keyof EffectorEventMap>(event: K, cb: EffectorEventMap[K]): Effector {
|
|
65
|
+
|
|
66
|
+
const arr = this.events[event];
|
|
67
|
+
|
|
68
|
+
for (let i = 0; i < arr.length; i++) {
|
|
69
|
+
if (arr[i] === cb) {
|
|
70
|
+
arr.splice(i, 1);
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return this;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
public ClearEventListeners(event?: keyof EffectorEventMap): Effector {
|
|
78
|
+
|
|
79
|
+
if (event) {
|
|
80
|
+
this.events[event].length = 0;
|
|
81
|
+
} else {
|
|
82
|
+
(Object.keys(this.events) as (keyof EffectorEventMap)[]).forEach((k) => (this.events[k].length = 0));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return this;
|
|
86
|
+
}
|
|
87
|
+
|
|
11
88
|
public abstract InitializeOnAttachment(parentialContext: AudioContext): Promise<void>;
|
|
12
|
-
}
|
|
89
|
+
}
|
|
@@ -9,30 +9,34 @@ export class LowPassFilter extends Effector {
|
|
|
9
9
|
public name: string = "LowPassFilter";
|
|
10
10
|
public label: string | null = "LowPassFilter";
|
|
11
11
|
|
|
12
|
-
public cutoff: number =
|
|
12
|
+
public cutoff: number = 1000;
|
|
13
|
+
public q: number = 0.7;
|
|
13
14
|
public minFrequency: number = 10;
|
|
14
15
|
|
|
15
|
-
constructor({ cutoff, minFrequency }: Partial<LowPassFilterOptions>) {
|
|
16
|
+
constructor({ cutoff, minFrequency, q }: Partial<LowPassFilterOptions>) {
|
|
16
17
|
super();
|
|
17
18
|
|
|
18
19
|
this.cutoff = cutoff ?? this.cutoff;
|
|
19
20
|
this.minFrequency = minFrequency ?? this.minFrequency;
|
|
21
|
+
this.q = q ?? this.q;
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
public async InitializeOnAttachment(parentialContext: AudioContext): Promise<void> {
|
|
23
25
|
|
|
24
26
|
this.parentialContext = parentialContext;
|
|
25
27
|
this.audioWorkletNode = CreateAudioWorkletNode(parentialContext, AudioWorkletProcessorNames.LowPassFilter, this.ReturnOptionsAsObject());
|
|
28
|
+
this.registerMessageEventListener(this.audioWorkletNode as AudioWorkletNode);
|
|
26
29
|
}
|
|
27
30
|
|
|
28
31
|
public ReturnOptionsAsObject(): LowPassFilterOptions {
|
|
29
32
|
return {
|
|
30
33
|
cutoff: this.cutoff,
|
|
31
|
-
minFrequency: this.minFrequency
|
|
34
|
+
minFrequency: this.minFrequency,
|
|
35
|
+
q: this.q
|
|
32
36
|
}
|
|
33
37
|
}
|
|
34
38
|
|
|
35
|
-
public SetCutoff(cutoff: number =
|
|
39
|
+
public SetCutoff(cutoff: number = 1000): boolean {
|
|
36
40
|
|
|
37
41
|
if (!this.parentialContext) return false;
|
|
38
42
|
|
|
@@ -45,11 +49,19 @@ export class LowPassFilter extends Effector {
|
|
|
45
49
|
|
|
46
50
|
public SetMinFrequency(minFrequency: number = 10): boolean {
|
|
47
51
|
|
|
48
|
-
|
|
49
52
|
if (minFrequency < 10)
|
|
50
53
|
minFrequency = 10;
|
|
51
54
|
|
|
52
55
|
this.minFrequency = minFrequency;
|
|
53
56
|
return SendMessageToWorklet<LowPassFilterMessageCommandId, number>(this.audioWorkletNode, LowPassFilterMessageCommandId.SetMinFrequency, minFrequency);
|
|
54
57
|
}
|
|
58
|
+
|
|
59
|
+
public SetQ(q: number = 0.7): boolean {
|
|
60
|
+
|
|
61
|
+
if(q > 4)
|
|
62
|
+
q = 4;
|
|
63
|
+
|
|
64
|
+
this.q = q;
|
|
65
|
+
return SendMessageToWorklet<LowPassFilterMessageCommandId, number>(this.audioWorkletNode, LowPassFilterMessageCommandId.SetQ, q);
|
|
66
|
+
}
|
|
55
67
|
}
|
package/lib/src/index.ts
CHANGED
|
@@ -100,5 +100,11 @@ export type {
|
|
|
100
100
|
SoftClipMessageCommandId,
|
|
101
101
|
SoftClipOptions,
|
|
102
102
|
HardClipMessageCommandId,
|
|
103
|
-
HardClipOptions
|
|
103
|
+
HardClipOptions,
|
|
104
|
+
EffectorEventMap,
|
|
105
|
+
IncomingMessageType,
|
|
106
|
+
IncomingProcessorMessage,
|
|
107
|
+
ProcessorData,
|
|
108
|
+
ProcessorIdentificationCodes,
|
|
109
|
+
EffectorEvents
|
|
104
110
|
} from "./typings";
|
package/lib/src/typings.ts
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
export type ChannelSpatialization = "mono" | "stereo" | "surround";
|
|
2
|
-
|
|
3
2
|
export type AudioClipAnalyserType = "pre" | "post";
|
|
4
3
|
export type AudioClipAnalyserProperty = "fftSize" | "minDecibels" | "maxDecibels" | "smoothingTimeConstant";
|
|
4
|
+
export type IncomingMessageType = "message" | "error" | "warning" | "wasm-instantiated";
|
|
5
5
|
|
|
6
|
-
export type AudioClipEvents
|
|
6
|
+
export type AudioClipEvents = {
|
|
7
7
|
[K in keyof AudioClipEventMap]: AudioClipEventMap[K][];
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
export type EffectorEvents = {
|
|
11
|
+
[K in keyof EffectorEventMap]: EffectorEventMap[K][];
|
|
12
|
+
}
|
|
11
13
|
|
|
12
14
|
export enum LowPassFilterMessageCommandId {
|
|
13
15
|
SetCutoff,
|
|
14
|
-
SetMinFrequency
|
|
16
|
+
SetMinFrequency,
|
|
17
|
+
SetQ
|
|
15
18
|
}
|
|
16
19
|
|
|
17
20
|
export enum ChorusMessageCommandId {
|
|
@@ -51,6 +54,12 @@ export enum AudioWorkletProcessorNames {
|
|
|
51
54
|
HardClip = "HardClipProcessor"
|
|
52
55
|
}
|
|
53
56
|
|
|
57
|
+
export enum ProcessorIdentificationCodes {
|
|
58
|
+
UnknownProcessorId = "UNKNOWN_PROCESSOR_ID",
|
|
59
|
+
UnknownProcessorName = "UNKNOWN_PROCESSOR_NAME",
|
|
60
|
+
UnknownProcessorCreationDate = "UNKNOWN_PROCESSOR_CREATION_DATE"
|
|
61
|
+
}
|
|
62
|
+
|
|
54
63
|
export interface FluexGLAudioDebuggerOptions {
|
|
55
64
|
breakOnError: boolean;
|
|
56
65
|
showInfo: boolean;
|
|
@@ -121,12 +130,13 @@ export interface ChorusEffectOptions {
|
|
|
121
130
|
depthMs: number;
|
|
122
131
|
rateHz: number;
|
|
123
132
|
mix: number;
|
|
124
|
-
feedback: number;
|
|
133
|
+
feedback: number;
|
|
125
134
|
}
|
|
126
135
|
|
|
127
136
|
export interface LowPassFilterOptions {
|
|
128
137
|
cutoff: number;
|
|
129
138
|
minFrequency: number;
|
|
139
|
+
q: number;
|
|
130
140
|
}
|
|
131
141
|
|
|
132
142
|
export interface SoftClipOptions {
|
|
@@ -137,4 +147,27 @@ export interface SoftClipOptions {
|
|
|
137
147
|
export interface HardClipOptions {
|
|
138
148
|
drive: number;
|
|
139
149
|
gain: number;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export interface EffectorEventMap {
|
|
153
|
+
"incoming-processor-message": (message: IncomingProcessorMessage) => void;
|
|
154
|
+
"incoming-processor-warning": (message: IncomingProcessorMessage) => void;
|
|
155
|
+
"incoming-processor-error": (message: IncomingProcessorMessage) => void;
|
|
156
|
+
"initialized-on-channel-attachment": (message: IncomingProcessorMessage) => void;
|
|
157
|
+
"processor-wasm-instantiated": (message: IncomingProcessorMessage) => void;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export interface ProcessorData {
|
|
161
|
+
id: string | ProcessorIdentificationCodes.UnknownProcessorId;
|
|
162
|
+
name: string | ProcessorIdentificationCodes.UnknownProcessorName;
|
|
163
|
+
createdAt: number | ProcessorIdentificationCodes.UnknownProcessorCreationDate;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export interface IncomingProcessorMessage {
|
|
167
|
+
id: string;
|
|
168
|
+
timestamp: number;
|
|
169
|
+
message: string;
|
|
170
|
+
type: IncomingMessageType;
|
|
171
|
+
processor: ProcessorData;
|
|
172
|
+
additionalData?: any;
|
|
140
173
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluex/fluexgl-dsp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.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",
|