@fluex/fluexgl-dsp 0.4.1 → 0.4.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/README.md +16 -38
- package/lib/dist/console-codes.d.ts +22 -7
- package/lib/dist/console-codes.d.ts.map +1 -1
- package/lib/dist/console-codes.js +22 -7
- package/lib/dist/core/classes/AudioClip.d.ts +3 -1
- package/lib/dist/core/classes/AudioClip.d.ts.map +1 -1
- package/lib/dist/core/classes/AudioClip.js +23 -17
- package/lib/dist/core/classes/AudioClipPlayer.d.ts +10 -2
- package/lib/dist/core/classes/AudioClipPlayer.d.ts.map +1 -1
- package/lib/dist/core/classes/AudioClipPlayer.js +56 -2
- package/lib/dist/core/classes/AudioDevice.d.ts +2 -0
- package/lib/dist/core/classes/AudioDevice.d.ts.map +1 -1
- package/lib/dist/core/classes/AudioDevice.js +5 -0
- package/lib/dist/core/classes/Channel.d.ts +14 -4
- package/lib/dist/core/classes/Channel.d.ts.map +1 -1
- package/lib/dist/core/classes/Channel.js +93 -7
- package/lib/dist/core/classes/DpsPipeline.d.ts +1 -1
- package/lib/dist/core/classes/DpsPipeline.d.ts.map +1 -1
- package/lib/dist/core/classes/DpsPipeline.js +7 -3
- package/lib/dist/core/classes/Effector.d.ts +2 -2
- package/lib/dist/core/classes/Effector.d.ts.map +1 -1
- package/lib/dist/core/classes/Effector.js +1 -1
- package/lib/dist/core/classes/Master.d.ts +12 -0
- package/lib/dist/core/classes/Master.d.ts.map +1 -1
- package/lib/dist/core/classes/Master.js +80 -9
- package/lib/dist/effects/classes/Analyser.d.ts +16 -0
- package/lib/dist/effects/classes/Analyser.d.ts.map +1 -0
- package/lib/dist/effects/classes/Analyser.js +62 -0
- package/lib/dist/effects/classes/Chorus.d.ts +4 -3
- package/lib/dist/effects/classes/Chorus.d.ts.map +1 -1
- package/lib/dist/effects/classes/Chorus.js +21 -12
- package/lib/dist/effects/classes/clips/HardClip.d.ts +4 -3
- package/lib/dist/effects/classes/clips/HardClip.d.ts.map +1 -1
- package/lib/dist/effects/classes/clips/HardClip.js +15 -9
- package/lib/dist/effects/classes/clips/SoftClip.d.ts +4 -3
- package/lib/dist/effects/classes/clips/SoftClip.d.ts.map +1 -1
- package/lib/dist/effects/classes/clips/SoftClip.js +15 -9
- package/lib/dist/effects/classes/filters/LowPassFilter.d.ts +4 -3
- package/lib/dist/effects/classes/filters/LowPassFilter.d.ts.map +1 -1
- package/lib/dist/effects/classes/filters/LowPassFilter.js +23 -14
- package/lib/dist/effects/exports.d.ts +1 -0
- package/lib/dist/effects/exports.d.ts.map +1 -1
- package/lib/dist/effects/exports.js +1 -0
- package/lib/dist/index.d.ts +5 -4
- package/lib/dist/index.d.ts.map +1 -1
- package/lib/dist/index.js +13 -18
- package/lib/dist/typings.d.ts +13 -11
- package/lib/dist/typings.d.ts.map +1 -1
- package/lib/dist/typings.js +5 -0
- package/lib/dist/utilities/debugger.js +6 -6
- package/lib/dist/utilities/helpers.d.ts +2 -0
- package/lib/dist/utilities/helpers.d.ts.map +1 -1
- package/lib/dist/utilities/helpers.js +35 -12
- package/lib/dist/utilities/web-assembly.d.ts.map +1 -1
- package/lib/dist/utilities/web-assembly.js +6 -0
- package/lib/src/console-codes.ts +22 -7
- package/lib/src/core/classes/AudioClip.ts +28 -19
- package/lib/src/core/classes/AudioClipPlayer.ts +77 -8
- package/lib/src/core/classes/AudioDevice.ts +6 -1
- package/lib/src/core/classes/Channel.ts +126 -13
- package/lib/src/core/classes/DpsPipeline.ts +7 -3
- package/lib/src/core/classes/Effector.ts +3 -2
- package/lib/src/core/classes/Master.ts +101 -13
- package/lib/src/effects/classes/Analyser.ts +84 -0
- package/lib/src/effects/classes/Chorus.ts +22 -13
- package/lib/src/effects/classes/clips/HardClip.ts +17 -10
- package/lib/src/effects/classes/clips/SoftClip.ts +17 -10
- package/lib/src/effects/classes/filters/LowPassFilter.ts +28 -15
- package/lib/src/effects/exports.ts +2 -1
- package/lib/src/index.ts +27 -29
- package/lib/src/typings.ts +14 -14
- package/lib/src/utilities/debugger.ts +6 -6
- package/lib/src/utilities/helpers.ts +39 -15
- package/lib/src/utilities/web-assembly.ts +8 -0
- package/package.json +1 -1
- package/lib/dist/effects/classes/Filter.d.ts +0 -3
- package/lib/dist/effects/classes/Filter.d.ts.map +0 -1
- package/lib/dist/effects/classes/Filter.js +0 -2
- package/lib/dist/effects/classes/SoftClip.d.ts +0 -10
- package/lib/dist/effects/classes/SoftClip.d.ts.map +0 -1
- package/lib/dist/effects/classes/SoftClip.js +0 -39
- package/lib/dist/test/linkable-channels.d.ts +0 -2
- package/lib/dist/test/linkable-channels.d.ts.map +0 -1
- package/lib/dist/test/linkable-channels.js +0 -16
- package/lib/src/core/functions/rebuild-effect-chain.ts +0 -5
package/README.md
CHANGED
|
@@ -21,57 +21,35 @@ $ npm i @fluex/fluexgl-dsp
|
|
|
21
21
|
## ⚡ Quick start
|
|
22
22
|
|
|
23
23
|
```ts
|
|
24
|
-
import {
|
|
25
|
-
AudioDevice,
|
|
26
|
-
InitializeDspPipeline,
|
|
27
|
-
LoadAudioSource,
|
|
28
|
-
ResolveDefaultAudioOutputDevice,
|
|
29
|
-
Channel,
|
|
30
|
-
AudioSourceData,
|
|
31
|
-
AudioClip
|
|
32
|
-
} from "@fluexgl/dsp";
|
|
24
|
+
import { DspPipeline, Channel, LoadAudioSource, AudioClip } from "@fluex/fluexgl-dsp";
|
|
33
25
|
|
|
34
26
|
(async function() {
|
|
35
27
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if(!hasInitialized) return null;
|
|
40
|
-
|
|
41
|
-
// Resolves the default audio output device.
|
|
42
|
-
const audioDevice: AudioDevice | null = await ResolveDefaultAudioOutputDevice({
|
|
43
|
-
pathToWasm: "/wasm/fluexgl-dsp-wasm_bg.wasm"
|
|
28
|
+
const pipeline = new DspPipeline({
|
|
29
|
+
pathToWasm: "/data/fluexgl-dsp-wasm_bg.wasm",
|
|
30
|
+
pathToWorklet: "/data/fluexgl-dsp-processor.worklet"
|
|
44
31
|
});
|
|
45
32
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
// Get the master channel from the default audio output device.
|
|
49
|
-
const masterChannel = audioDevice.GetMasterChannel();
|
|
50
|
-
|
|
51
|
-
// Create a new empty channel.
|
|
52
|
-
const channel = new Channel();
|
|
33
|
+
await pipeline.InitializeDpsPipeline();
|
|
53
34
|
|
|
54
|
-
|
|
55
|
-
channel.SetLabel("BackgroundMusic");
|
|
35
|
+
const audioDevice = await pipeline.ResolveDefaultAudioOutputDevice();
|
|
56
36
|
|
|
57
|
-
|
|
58
|
-
masterChannel.AttachChannel(channel);
|
|
37
|
+
if(!audioDevice) return;
|
|
59
38
|
|
|
60
|
-
|
|
61
|
-
const
|
|
39
|
+
const master = audioDevice.GetMasterChannel();
|
|
40
|
+
const context = audioDevice.GetContext();
|
|
62
41
|
|
|
63
|
-
|
|
42
|
+
const audioSource = await LoadAudioSource("/music.mp3");
|
|
64
43
|
|
|
65
|
-
|
|
66
|
-
const audioClip = new AudioClip(audioSourceData);
|
|
44
|
+
if(!audioSource) return;
|
|
67
45
|
|
|
68
|
-
|
|
69
|
-
channel
|
|
46
|
+
const audioClip = new AudioClip(audioSource);
|
|
47
|
+
const channel = new Channel(context);
|
|
70
48
|
|
|
71
|
-
|
|
72
|
-
|
|
49
|
+
channel.Send(master);
|
|
50
|
+
audioClip.Send(channel);
|
|
73
51
|
|
|
74
|
-
|
|
52
|
+
button.addEventListener("click", function() {
|
|
75
53
|
audioClip.Play();
|
|
76
54
|
});
|
|
77
55
|
})();
|
|
@@ -1,13 +1,28 @@
|
|
|
1
1
|
export declare enum ErrorCodes {
|
|
2
|
-
NO_CONTEXT_PERMISSION = "FLUEXGL@
|
|
3
|
-
NO_FILE_TYPE_FOUND = "FLUEXGL@
|
|
4
|
-
PATH_TO_FILE_NOT_FOUND = "FLUEXGL@
|
|
5
|
-
SAME_MASTER_CHANNEL = "FLUEXGL@
|
|
6
|
-
WASM_MODULE_INITIALIZATION_FAILED = "FLUEXGL@
|
|
7
|
-
PATH_TO_WASM_FILE_NOT_FOUND = "FLUEXGL@
|
|
2
|
+
NO_CONTEXT_PERMISSION = "ERROR:FLUEXGL-DSP@0001",
|
|
3
|
+
NO_FILE_TYPE_FOUND = "ERROR:FLUEXGL-DSP@0002",
|
|
4
|
+
PATH_TO_FILE_NOT_FOUND = "ERROR:FLUEXGL-DSP@0003",
|
|
5
|
+
SAME_MASTER_CHANNEL = "ERROR:FLUEXGL-DSP@0004",
|
|
6
|
+
WASM_MODULE_INITIALIZATION_FAILED = "ERROR:FLUEXGL-DSP@0005",
|
|
7
|
+
PATH_TO_WASM_FILE_NOT_FOUND = "ERROR:FLUEXGL-DSP@0006",
|
|
8
|
+
WASM_COMPILATION_ERROR = "ERROR:FLUEXGL-DSP@0007",
|
|
9
|
+
WORKLET_NO_WASM_MODULE_INSTANTIATED = "ERROR:FLUEXGL-DSP@0008",
|
|
10
|
+
EFFECT_ALREADY_ATTACHED = "ERROR:FLUEXGL-DSP@0009",
|
|
11
|
+
EFFECT_NOT_FOUND = "ERROR:FLUEXGL-DSP@0010",
|
|
12
|
+
CHANNEL_ALREADY_ATTACHED = "ERROR:FLUEXGL-DSP@0011",
|
|
13
|
+
CHANNEL_NOT_FOUND = "ERROR:FLUEXGL-DSP@0012",
|
|
14
|
+
CHANNEL_CANNOT_LINK_TO_ITSELF = "ERROR:FLUEXGL-DSP@0013",
|
|
15
|
+
CHANNEL_NOT_INITIALIZED = "ERROR:FLUEXGL-DSP@0014",
|
|
16
|
+
CHANNEL_NOT_SAME_AUDIO_CONTEXT = "ERROR:FLUEXGL-DSP@0015",
|
|
17
|
+
CHANNEL_ALREADY_LINKED = "ERROR:FLUEXGL-DSP@0016",
|
|
18
|
+
CHANNEL_POSSIBLE_FEEDBACK_LOOP = "ERROR:FLUEXGL-DSP@0017",
|
|
19
|
+
AUDIO_CLIP_ALREADY_ATTACHED = "ERROR:FLUEXGL-DSP@0018",
|
|
20
|
+
AUDIO_CLIP_NOT_FOUND = "ERROR:FLUEXGL-DSP@0019",
|
|
21
|
+
AUDIO_CLIP_PLAYER_NO_CONTEXT = "ERROR:FLUEXGL-DSP@0020",
|
|
22
|
+
PANNING_OUT_OF_RANGE = "ERROR:FLUEXGL-DSP@0021"
|
|
8
23
|
}
|
|
9
24
|
export declare enum WarningCodes {
|
|
10
|
-
NO_DEFAULT_AUDIO_DEVICE_FOUND = "FLUEXGL@
|
|
25
|
+
NO_DEFAULT_AUDIO_DEVICE_FOUND = "WARNING:FLUEXGL-DSP@0001"
|
|
11
26
|
}
|
|
12
27
|
export declare enum SuccessCodes {
|
|
13
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"console-codes.d.ts","sourceRoot":"","sources":["../src/console-codes.ts"],"names":[],"mappings":"AAAA,oBAAY,UAAU;IAClB,qBAAqB,
|
|
1
|
+
{"version":3,"file":"console-codes.d.ts","sourceRoot":"","sources":["../src/console-codes.ts"],"names":[],"mappings":"AAAA,oBAAY,UAAU;IAClB,qBAAqB,2BAA2B;IAChD,kBAAkB,2BAA2B;IAC7C,sBAAsB,2BAA2B;IACjD,mBAAmB,2BAA2B;IAC9C,iCAAiC,2BAA2B;IAC5D,2BAA2B,2BAA2B;IACtD,sBAAsB,2BAA2B;IACjD,mCAAmC,2BAA2B;IAC9D,uBAAuB,2BAA2B;IAClD,gBAAgB,2BAA2B;IAC3C,wBAAwB,2BAA2B;IACnD,iBAAiB,2BAA2B;IAC5C,6BAA6B,2BAA2B;IACxD,uBAAuB,2BAA2B;IAClD,8BAA8B,2BAA2B;IACzD,sBAAsB,2BAA2B;IACjD,8BAA8B,2BAA2B;IACzD,2BAA2B,2BAA2B;IACtD,oBAAoB,2BAA2B;IAC/C,4BAA4B,2BAA2B;IACvD,oBAAoB,2BAA2B;CAClD;AAED,oBAAY,YAAY;IACpB,6BAA6B,6BAA6B;CAC7D;AAED,oBAAY,YAAY;CAEvB"}
|
|
@@ -1,15 +1,30 @@
|
|
|
1
1
|
export var ErrorCodes;
|
|
2
2
|
(function (ErrorCodes) {
|
|
3
|
-
ErrorCodes["NO_CONTEXT_PERMISSION"] = "FLUEXGL@
|
|
4
|
-
ErrorCodes["NO_FILE_TYPE_FOUND"] = "FLUEXGL@
|
|
5
|
-
ErrorCodes["PATH_TO_FILE_NOT_FOUND"] = "FLUEXGL@
|
|
6
|
-
ErrorCodes["SAME_MASTER_CHANNEL"] = "FLUEXGL@
|
|
7
|
-
ErrorCodes["WASM_MODULE_INITIALIZATION_FAILED"] = "FLUEXGL@
|
|
8
|
-
ErrorCodes["PATH_TO_WASM_FILE_NOT_FOUND"] = "FLUEXGL@
|
|
3
|
+
ErrorCodes["NO_CONTEXT_PERMISSION"] = "ERROR:FLUEXGL-DSP@0001";
|
|
4
|
+
ErrorCodes["NO_FILE_TYPE_FOUND"] = "ERROR:FLUEXGL-DSP@0002";
|
|
5
|
+
ErrorCodes["PATH_TO_FILE_NOT_FOUND"] = "ERROR:FLUEXGL-DSP@0003";
|
|
6
|
+
ErrorCodes["SAME_MASTER_CHANNEL"] = "ERROR:FLUEXGL-DSP@0004";
|
|
7
|
+
ErrorCodes["WASM_MODULE_INITIALIZATION_FAILED"] = "ERROR:FLUEXGL-DSP@0005";
|
|
8
|
+
ErrorCodes["PATH_TO_WASM_FILE_NOT_FOUND"] = "ERROR:FLUEXGL-DSP@0006";
|
|
9
|
+
ErrorCodes["WASM_COMPILATION_ERROR"] = "ERROR:FLUEXGL-DSP@0007";
|
|
10
|
+
ErrorCodes["WORKLET_NO_WASM_MODULE_INSTANTIATED"] = "ERROR:FLUEXGL-DSP@0008";
|
|
11
|
+
ErrorCodes["EFFECT_ALREADY_ATTACHED"] = "ERROR:FLUEXGL-DSP@0009";
|
|
12
|
+
ErrorCodes["EFFECT_NOT_FOUND"] = "ERROR:FLUEXGL-DSP@0010";
|
|
13
|
+
ErrorCodes["CHANNEL_ALREADY_ATTACHED"] = "ERROR:FLUEXGL-DSP@0011";
|
|
14
|
+
ErrorCodes["CHANNEL_NOT_FOUND"] = "ERROR:FLUEXGL-DSP@0012";
|
|
15
|
+
ErrorCodes["CHANNEL_CANNOT_LINK_TO_ITSELF"] = "ERROR:FLUEXGL-DSP@0013";
|
|
16
|
+
ErrorCodes["CHANNEL_NOT_INITIALIZED"] = "ERROR:FLUEXGL-DSP@0014";
|
|
17
|
+
ErrorCodes["CHANNEL_NOT_SAME_AUDIO_CONTEXT"] = "ERROR:FLUEXGL-DSP@0015";
|
|
18
|
+
ErrorCodes["CHANNEL_ALREADY_LINKED"] = "ERROR:FLUEXGL-DSP@0016";
|
|
19
|
+
ErrorCodes["CHANNEL_POSSIBLE_FEEDBACK_LOOP"] = "ERROR:FLUEXGL-DSP@0017";
|
|
20
|
+
ErrorCodes["AUDIO_CLIP_ALREADY_ATTACHED"] = "ERROR:FLUEXGL-DSP@0018";
|
|
21
|
+
ErrorCodes["AUDIO_CLIP_NOT_FOUND"] = "ERROR:FLUEXGL-DSP@0019";
|
|
22
|
+
ErrorCodes["AUDIO_CLIP_PLAYER_NO_CONTEXT"] = "ERROR:FLUEXGL-DSP@0020";
|
|
23
|
+
ErrorCodes["PANNING_OUT_OF_RANGE"] = "ERROR:FLUEXGL-DSP@0021";
|
|
9
24
|
})(ErrorCodes || (ErrorCodes = {}));
|
|
10
25
|
export var WarningCodes;
|
|
11
26
|
(function (WarningCodes) {
|
|
12
|
-
WarningCodes["NO_DEFAULT_AUDIO_DEVICE_FOUND"] = "FLUEXGL@
|
|
27
|
+
WarningCodes["NO_DEFAULT_AUDIO_DEVICE_FOUND"] = "WARNING:FLUEXGL-DSP@0001";
|
|
13
28
|
})(WarningCodes || (WarningCodes = {}));
|
|
14
29
|
export var SuccessCodes;
|
|
15
30
|
(function (SuccessCodes) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AudioClipEventMap, AudioSourceData } from "../../typings";
|
|
2
2
|
import { Channel } from "./Channel";
|
|
3
3
|
import { AudioClipPlayer } from "./AudioClipPlayer";
|
|
4
|
+
import { Master } from "./Master";
|
|
4
5
|
export declare class AudioClip {
|
|
5
6
|
data: AudioSourceData;
|
|
6
7
|
id: string;
|
|
@@ -37,7 +38,8 @@ export declare class AudioClip {
|
|
|
37
38
|
RemoveEventListener<K extends keyof AudioClipEventMap>(event: K, cb: AudioClipEventMap[K]): AudioClip;
|
|
38
39
|
ClearEventListeners(event?: keyof AudioClipEventMap): AudioClip;
|
|
39
40
|
GetChannelData(channel?: number): Float32Array;
|
|
40
|
-
Send(channel: Channel): void;
|
|
41
|
+
Send(channel: Channel | Master): void;
|
|
42
|
+
Unsend(channel: Channel | Master): void;
|
|
41
43
|
get currentPlaybackTime(): number;
|
|
42
44
|
get duration(): number;
|
|
43
45
|
get volume(): number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AudioClip.d.ts","sourceRoot":"","sources":["../../../src/core/classes/AudioClip.ts"],"names":[],"mappings":"AAGA,OAAO,
|
|
1
|
+
{"version":3,"file":"AudioClip.d.ts","sourceRoot":"","sources":["../../../src/core/classes/AudioClip.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAmB,eAAe,EAAE,MAAM,eAAe,CAAC;AAEpF,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAMlC,qBAAa,SAAS;IA2BC,IAAI,EAAE,eAAe;IAzBjC,EAAE,EAAE,MAAM,CAAQ;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE5B,IAAI,EAAE,OAAO,CAAS;IACtB,SAAS,EAAE,OAAO,CAAS;IAC3B,SAAS,EAAE,MAAM,CAAK;IACtB,aAAa,EAAE,MAAM,CAAK;IAE1B,mBAAmB,EAAE,MAAM,CAAM;IAEjC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAQ;IACjC,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAQ;IAEjD,OAAO,EAAE,YAAY,GAAG,IAAI,CAAQ;IACpC,eAAe,EAAE,eAAe,GAAG,IAAI,CAAQ;IAEtD,OAAO,CAAC,sBAAsB,CAA+B;IAC7D,OAAO,CAAC,yBAAyB,CAAa;IAE9C,OAAO,CAAC,gBAAgB,CAAoB;IAE5C,OAAO,CAAC,MAAM,CAEb;gBAEkB,IAAI,EAAE,eAAe;IAExC,OAAO,CAAC,kBAAkB;IAa1B,OAAO,CAAC,gBAAgB;IAOxB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,gBAAgB;IAmBjB,UAAU,CAAC,eAAe,EAAE,eAAe;IAc3C,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;IAqExC,IAAI,CAAC,OAAO,EAAE,MAAM;IAsBpB,IAAI,IAAI,SAAS,GAAG,IAAI;IAkBxB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS;IAUpC,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS;IAexC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS;IAU/B,4BAA4B,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS;IAatD,mCAAmC,IAAI,OAAO;IAc9C,gBAAgB,CAAC,CAAC,SAAS,MAAM,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI;IAMnG,IAAI,CAAC,CAAC,SAAS,MAAM,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI;IAYvF,mBAAmB,CAAC,CAAC,SAAS,MAAM,iBAAiB,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC,GAAG,SAAS;IAarG,mBAAmB,CAAC,KAAK,CAAC,EAAE,MAAM,iBAAiB,GAAG,SAAS;IAW/D,cAAc,CAAC,OAAO,GAAE,MAAU,GAAG,YAAY;IAIjD,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM;IAW9B,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM;IAWvC,IAAW,mBAAmB,IAAI,MAAM,CAIvC;IAED,IAAW,QAAQ,IAAI,MAAM,CAE5B;IAED,IAAW,MAAM,IAAI,MAAM,CAE1B;IAED,IAAW,aAAa,IAAI,MAAM,CAEjC;IAED,IAAW,iBAAiB,IAAI,MAAM,CAKrC;IAED,IAAW,UAAU,IAAI,MAAM,CAE9B;IAED,IAAW,gBAAgB,IAAI,MAAM,CAEpC;IAED,IAAW,UAAU,IAAI,MAAM,CAE9B;CACJ"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { v4 } from "uuid";
|
|
2
2
|
import { format } from "date-fns";
|
|
3
3
|
import { Debug } from "../../utilities/debugger";
|
|
4
|
+
import { DSP } from "../../index";
|
|
5
|
+
import { ErrorCodes } from "lib/src/console-codes";
|
|
4
6
|
export class AudioClip {
|
|
5
7
|
data;
|
|
6
8
|
id = v4();
|
|
@@ -59,7 +61,7 @@ export class AudioClip {
|
|
|
59
61
|
return Debug.Error("Could not initialize AudioClip, because the AudioClipPlayer somehow has no audio context.", [
|
|
60
62
|
`AudioClipPlayer id: ${audioClipPlayer.id}`,
|
|
61
63
|
`AudioClip id: ${this.id}`
|
|
62
|
-
]);
|
|
64
|
+
], ErrorCodes.AUDIO_CLIP_PLAYER_NO_CONTEXT);
|
|
63
65
|
this.audioClipPlayer = audioClipPlayer;
|
|
64
66
|
this.context = audioClipPlayer.context;
|
|
65
67
|
this.gainNode = new GainNode(this.context);
|
|
@@ -148,11 +150,7 @@ export class AudioClip {
|
|
|
148
150
|
if (!this.context)
|
|
149
151
|
Debug.Error("Could not set volume because the context (AudioContext) of this AudioClip is undefined.", [
|
|
150
152
|
"Make sure to attach this AudioClip to an AudioClipPlayer instance before calling .SetVolume() on this AudioClip.",
|
|
151
|
-
]);
|
|
152
|
-
if (!this.gainNode)
|
|
153
|
-
Debug.Error("Could not set volume because the gainNode (GainNode) of this AudioClip is undefined.", [
|
|
154
|
-
"Make sure to attach this AudioClip to an AudioClipPlayer instance before calling .SetVolume() on this AudioClip.",
|
|
155
|
-
]);
|
|
153
|
+
], ErrorCodes.AUDIO_CLIP_PLAYER_NO_CONTEXT);
|
|
156
154
|
this.gainNode?.gain.setValueAtTime(volume, this.context?.currentTime ?? 0);
|
|
157
155
|
return this;
|
|
158
156
|
}
|
|
@@ -160,16 +158,12 @@ export class AudioClip {
|
|
|
160
158
|
if (!this.context)
|
|
161
159
|
Debug.Error("Could not set volume because the context (AudioContext) of this AudioClip is undefined.", [
|
|
162
160
|
"Make sure to attach this AudioClip to an AudioClipPlayer instance before calling .SetPanLevel() on this AudioClip.",
|
|
163
|
-
]);
|
|
164
|
-
if (!this.stereoPannerNode)
|
|
165
|
-
Debug.Error("Could not set volume because the stereoPannerNode (StereoPannerNode) of this AudioClip is undefined.", [
|
|
166
|
-
"Make sure to attach this AudioClip to an AudioClipPlayer instance before calling .SetPanLevel() on this AudioClip.",
|
|
167
|
-
]);
|
|
161
|
+
], ErrorCodes.AUDIO_CLIP_PLAYER_NO_CONTEXT);
|
|
168
162
|
if (panLevel < -1 || panLevel > 1)
|
|
169
163
|
Debug.Error("Could not set the pan level because it is not between -1 and 1.", [
|
|
170
164
|
`Given value: ${panLevel}.`,
|
|
171
165
|
`Accepts a value between -1 and 1. Can be a floating number.`
|
|
172
|
-
]);
|
|
166
|
+
], ErrorCodes.PANNING_OUT_OF_RANGE);
|
|
173
167
|
this.stereoPannerNode?.pan.setValueAtTime(panLevel, this.context?.currentTime ?? 0);
|
|
174
168
|
return this;
|
|
175
169
|
}
|
|
@@ -181,9 +175,12 @@ export class AudioClip {
|
|
|
181
175
|
return this;
|
|
182
176
|
}
|
|
183
177
|
SetMaxAudioBufferSourceNodes(value) {
|
|
184
|
-
|
|
185
|
-
"
|
|
186
|
-
|
|
178
|
+
if (!DSP.overrideMaxAudioBufferNodes) {
|
|
179
|
+
Debug.Warn("Cannot set maxAudioBufferSourceNodes because the option to override the current maximum value is disabled.", [
|
|
180
|
+
"Set overrideMaxAudioBufferNodes on DSP to true, in order to override the maximum audio buffer source nodes."
|
|
181
|
+
]);
|
|
182
|
+
return this;
|
|
183
|
+
}
|
|
187
184
|
this.maxAudioBufferSourceNodes = value;
|
|
188
185
|
return this;
|
|
189
186
|
}
|
|
@@ -232,13 +229,22 @@ export class AudioClip {
|
|
|
232
229
|
return this.data.audioBuffer.getChannelData(channel);
|
|
233
230
|
}
|
|
234
231
|
Send(channel) {
|
|
235
|
-
if (!channel.
|
|
232
|
+
if (!channel.audioClipPlayer)
|
|
236
233
|
return Debug.Error("Could not send AudioClip signal to channel, because the channel's AudioClipPlayer is undefined.", [
|
|
237
234
|
"Make sure to initialize the Channel.",
|
|
238
235
|
`Channel id: ${channel.id}.`,
|
|
239
236
|
`AudioClip id: ${this.id}.`
|
|
240
237
|
]);
|
|
241
|
-
channel.AttachAudioClip(this);
|
|
238
|
+
channel.audioClipPlayer.AttachAudioClip(this);
|
|
239
|
+
}
|
|
240
|
+
Unsend(channel) {
|
|
241
|
+
if (!channel.audioClipPlayer)
|
|
242
|
+
return Debug.Error("Could not unsend AudioClip signal to channel, because the channel's AudioClipPlayer is undefined.", [
|
|
243
|
+
"Make sure to initialize the Channel.",
|
|
244
|
+
`Channel id: ${channel.id}.`,
|
|
245
|
+
`AudioClip id: ${this.id}.`
|
|
246
|
+
]);
|
|
247
|
+
channel.audioClipPlayer.DetachAudioClip(this);
|
|
242
248
|
}
|
|
243
249
|
get currentPlaybackTime() {
|
|
244
250
|
return (!this.isPlaying || !this.context)
|
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
import { AudioClip } from "./AudioClip";
|
|
2
2
|
import { Channel } from "./Channel";
|
|
3
|
+
import { Master } from "./Master";
|
|
3
4
|
export declare class AudioClipPlayer {
|
|
4
5
|
label: string;
|
|
5
6
|
id: string;
|
|
6
7
|
audioClips: AudioClip[];
|
|
7
8
|
outputGainNode: GainNode | null;
|
|
8
9
|
context: AudioContext | null;
|
|
9
|
-
channel: Channel | null;
|
|
10
|
+
channel: Channel | Master | null;
|
|
10
11
|
constructor(context: AudioContext);
|
|
11
12
|
AttachAudioClip(audioClip: AudioClip): void;
|
|
12
|
-
|
|
13
|
+
DetachAudioClip(clip: AudioClip): void;
|
|
14
|
+
Send(channel: Channel | Master): void;
|
|
15
|
+
Unsend(): void;
|
|
16
|
+
SetVolume(value: number): void;
|
|
17
|
+
StopAll(): void;
|
|
18
|
+
Dispose(): void;
|
|
13
19
|
SetLabel(label: string): void;
|
|
20
|
+
get length(): number;
|
|
21
|
+
get volume(): number;
|
|
14
22
|
}
|
|
15
23
|
//# sourceMappingURL=AudioClipPlayer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AudioClipPlayer.d.ts","sourceRoot":"","sources":["../../../src/core/classes/AudioClipPlayer.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"AudioClipPlayer.d.ts","sourceRoot":"","sources":["../../../src/core/classes/AudioClipPlayer.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAGlC,qBAAa,eAAe;IAEjB,KAAK,EAAE,MAAM,CAAqB;IAClC,EAAE,EAAE,MAAM,CAAQ;IAElB,UAAU,EAAE,SAAS,EAAE,CAAM;IAC7B,cAAc,EAAE,QAAQ,GAAG,IAAI,CAAQ;IAEvC,OAAO,EAAE,YAAY,GAAG,IAAI,CAAQ;IACpC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAAQ;gBAEnC,OAAO,EAAE,YAAY;IAK1B,eAAe,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI;IAU3C,eAAe,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI;IAgBtC,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI;IAUrC,MAAM,IAAI,IAAI;IAad,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAU9B,OAAO,IAAI,IAAI;IAOf,OAAO,IAAI,IAAI;IAYf,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIpC,IAAW,MAAM,IAAI,MAAM,CAE1B;IAED,IAAW,MAAM,IAAI,MAAM,CAE1B;CACJ"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { v4 } from "uuid";
|
|
2
2
|
import { Debug } from "../../utilities/debugger";
|
|
3
|
+
import { ErrorCodes } from "lib/src/console-codes";
|
|
3
4
|
export class AudioClipPlayer {
|
|
4
5
|
label = "AudioClipPlayer";
|
|
5
6
|
id = v4();
|
|
@@ -15,17 +16,70 @@ export class AudioClipPlayer {
|
|
|
15
16
|
if (this.audioClips.includes(audioClip))
|
|
16
17
|
return Debug.Error("Could not attach audio clip because it is already part of this channel", [
|
|
17
18
|
"Call .DetachAudioClip([clip AudioClip]) before attaching audio clip."
|
|
18
|
-
]);
|
|
19
|
+
], ErrorCodes.AUDIO_CLIP_ALREADY_ATTACHED);
|
|
19
20
|
audioClip.Initialize(this);
|
|
20
21
|
this.audioClips.push(audioClip);
|
|
21
22
|
}
|
|
23
|
+
DetachAudioClip(clip) {
|
|
24
|
+
if (!this.audioClips.includes(clip))
|
|
25
|
+
return Debug.Error("Could not detach audio clip because it is not part of this channel", [
|
|
26
|
+
"Call .AttachAudioClip([clip AudioClip]) before detaching audio clip."
|
|
27
|
+
], ErrorCodes.AUDIO_CLIP_NOT_FOUND);
|
|
28
|
+
clip.Stop();
|
|
29
|
+
const self = this;
|
|
30
|
+
this.audioClips.forEach(function (_clip, index) {
|
|
31
|
+
if (clip.id === _clip.id)
|
|
32
|
+
return self.audioClips.splice(index, 1);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
22
35
|
Send(channel) {
|
|
23
36
|
if (!this.outputGainNode || !channel.input)
|
|
24
|
-
return Debug.Error("Could not send AudioClipPlayer signal to a channel.");
|
|
37
|
+
return Debug.Error("Could not send AudioClipPlayer signal to a channel/master.");
|
|
38
|
+
this.Unsend();
|
|
25
39
|
this.channel = channel;
|
|
26
40
|
this.outputGainNode.connect(channel.input);
|
|
27
41
|
}
|
|
42
|
+
Unsend() {
|
|
43
|
+
if (!this.outputGainNode)
|
|
44
|
+
return;
|
|
45
|
+
if (this.channel && this.channel.input) {
|
|
46
|
+
this.outputGainNode.disconnect(this.channel.input);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
this.outputGainNode.disconnect();
|
|
50
|
+
}
|
|
51
|
+
this.channel = null;
|
|
52
|
+
}
|
|
53
|
+
SetVolume(value) {
|
|
54
|
+
if (!this.outputGainNode)
|
|
55
|
+
return;
|
|
56
|
+
if (value < 0)
|
|
57
|
+
value = 0;
|
|
58
|
+
if (value > 1)
|
|
59
|
+
value = 1;
|
|
60
|
+
this.outputGainNode.gain.value = value;
|
|
61
|
+
}
|
|
62
|
+
StopAll() {
|
|
63
|
+
this.audioClips.forEach(function (clip) {
|
|
64
|
+
clip.Stop();
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
Dispose() {
|
|
68
|
+
this.StopAll();
|
|
69
|
+
this.Unsend();
|
|
70
|
+
this.outputGainNode?.disconnect();
|
|
71
|
+
this.audioClips = [];
|
|
72
|
+
this.outputGainNode = null;
|
|
73
|
+
this.channel = null;
|
|
74
|
+
this.context = null;
|
|
75
|
+
}
|
|
28
76
|
SetLabel(label) {
|
|
29
77
|
this.label = label;
|
|
30
78
|
}
|
|
79
|
+
get length() {
|
|
80
|
+
return this.audioClips.length;
|
|
81
|
+
}
|
|
82
|
+
get volume() {
|
|
83
|
+
return this.outputGainNode?.gain.value ?? 0;
|
|
84
|
+
}
|
|
31
85
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Master } from "./Master";
|
|
2
|
+
import { Channel } from "./Channel";
|
|
2
3
|
export declare class AudioDevice {
|
|
3
4
|
deviceInfo: MediaDeviceInfo;
|
|
4
5
|
id: string;
|
|
@@ -11,5 +12,6 @@ export declare class AudioDevice {
|
|
|
11
12
|
SetMasterChannel(channel: Master): void;
|
|
12
13
|
CreateMasterChannel(): Master;
|
|
13
14
|
GetContext(): AudioContext;
|
|
15
|
+
CreateChannel(label?: string): Channel;
|
|
14
16
|
}
|
|
15
17
|
//# sourceMappingURL=AudioDevice.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AudioDevice.d.ts","sourceRoot":"","sources":["../../../src/core/classes/AudioDevice.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"AudioDevice.d.ts","sourceRoot":"","sources":["../../../src/core/classes/AudioDevice.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKpC,qBAAa,WAAW;IAUD,UAAU,EAAE,eAAe;IARvC,EAAE,EAAE,MAAM,CAAQ;IAClB,SAAS,EAAE,MAAM,CAAc;IAE/B,OAAO,EAAE,YAAY,CAAsB;IAE3C,aAAa,EAAE,MAAM,CAA4B;IACjD,cAAc,EAAE,MAAM,EAAE,CAAM;gBAElB,UAAU,EAAE,eAAe;IAEvC,gBAAgB,IAAI,MAAM;IAI1B,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAUvC,mBAAmB,IAAI,MAAM;IAQ7B,UAAU,IAAI,YAAY;IAI1B,aAAa,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO;CAGhD"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { v4 } from "uuid";
|
|
2
2
|
import { Master } from "./Master";
|
|
3
|
+
import { Channel } from "./Channel";
|
|
3
4
|
import { ErrorCodes } from "../../console-codes";
|
|
4
5
|
import { Debug } from "../../utilities/debugger";
|
|
5
6
|
export class AudioDevice {
|
|
@@ -12,6 +13,7 @@ export class AudioDevice {
|
|
|
12
13
|
constructor(deviceInfo) {
|
|
13
14
|
this.deviceInfo = deviceInfo;
|
|
14
15
|
}
|
|
16
|
+
;
|
|
15
17
|
GetMasterChannel() {
|
|
16
18
|
return this.masterChannel;
|
|
17
19
|
}
|
|
@@ -31,4 +33,7 @@ export class AudioDevice {
|
|
|
31
33
|
GetContext() {
|
|
32
34
|
return this.context;
|
|
33
35
|
}
|
|
36
|
+
CreateChannel(label) {
|
|
37
|
+
return new Channel(this.context, label);
|
|
38
|
+
}
|
|
34
39
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { AudioClipPlayer } from "./AudioClipPlayer";
|
|
1
2
|
import { AudioClip } from "./AudioClip";
|
|
2
3
|
import { Master } from "./Master";
|
|
4
|
+
import { Effector } from "./Effector";
|
|
3
5
|
export declare class Channel {
|
|
4
6
|
id: string;
|
|
5
7
|
label: string;
|
|
@@ -8,10 +10,16 @@ export declare class Channel {
|
|
|
8
10
|
analyserNode: AnalyserNode | null;
|
|
9
11
|
gainNode: GainNode | null;
|
|
10
12
|
output: AudioNode | null;
|
|
13
|
+
effects: Effector[];
|
|
11
14
|
context: AudioContext | null;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
constructor(context: AudioContext);
|
|
15
|
+
sends: Channel[];
|
|
16
|
+
audioClipPlayer: AudioClipPlayer | null;
|
|
17
|
+
constructor(context: AudioContext, label?: string);
|
|
18
|
+
private rebuildEffectChain;
|
|
19
|
+
AddEffect(effect: Effector): void;
|
|
20
|
+
AttachEffect(effect: Effector): void;
|
|
21
|
+
RemoveEffect(effect: Effector): void;
|
|
22
|
+
DetachEffect(effect: Effector): void;
|
|
15
23
|
private disconnectAudioNodes;
|
|
16
24
|
private isInitialized;
|
|
17
25
|
private isReachable;
|
|
@@ -19,6 +27,8 @@ export declare class Channel {
|
|
|
19
27
|
Unsend(channel: Channel | Master): void;
|
|
20
28
|
HasAudioClipPlayer(): boolean;
|
|
21
29
|
UnsendToAllChannels(): void;
|
|
22
|
-
AttachAudioClip(audioClip: AudioClip):
|
|
30
|
+
AttachAudioClip(audioClip: AudioClip): Channel;
|
|
31
|
+
Volume(volume?: number): number;
|
|
32
|
+
Pan(pan?: number): number;
|
|
23
33
|
}
|
|
24
34
|
//# 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":"AAEA,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;AAGtC,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;IAsCnB,SAAS,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI;IAmBjC,YAAY,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI;IAIpC,YAAY,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI;IAqBpC,YAAY,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI;IAI3C,OAAO,CAAC,oBAAoB;IAqB5B,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,WAAW;IAwBZ,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM;IAkC9B,MAAM,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM;IAehC,kBAAkB,IAAI,OAAO;IAI7B,mBAAmB;IAQnB,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;CAQnC"}
|
|
@@ -2,6 +2,7 @@ import { v4 } from "uuid";
|
|
|
2
2
|
import { Debug } from "../../utilities/debugger";
|
|
3
3
|
import { AudioClipPlayer } from "./AudioClipPlayer";
|
|
4
4
|
import { Master } from "./Master";
|
|
5
|
+
import { ErrorCodes } from "../../console-codes";
|
|
5
6
|
export class Channel {
|
|
6
7
|
id = v4();
|
|
7
8
|
label = "Channel";
|
|
@@ -10,11 +11,13 @@ export class Channel {
|
|
|
10
11
|
analyserNode = null;
|
|
11
12
|
gainNode = null;
|
|
12
13
|
output = null;
|
|
14
|
+
effects = [];
|
|
13
15
|
context = null;
|
|
14
16
|
sends = [];
|
|
15
17
|
audioClipPlayer = null;
|
|
16
|
-
constructor(context) {
|
|
18
|
+
constructor(context, label) {
|
|
17
19
|
this.context = context;
|
|
20
|
+
this.label = label ?? this.label;
|
|
18
21
|
this.disconnectAudioNodes(true);
|
|
19
22
|
this.input = new GainNode(context);
|
|
20
23
|
this.stereoPannerNode = new StereoPannerNode(context);
|
|
@@ -28,12 +31,78 @@ export class Channel {
|
|
|
28
31
|
this.gainNode.connect(this.output);
|
|
29
32
|
this.audioClipPlayer.Send(this);
|
|
30
33
|
}
|
|
34
|
+
rebuildEffectChain() {
|
|
35
|
+
if (!this.input || !this.stereoPannerNode) {
|
|
36
|
+
Debug.Error("Could not rebuild effect chain because one or more required audio nodes are undefined.", [
|
|
37
|
+
`Channel id: ${this.id}.`,
|
|
38
|
+
`Input defined: ${!!this.input}.`,
|
|
39
|
+
`StereoPannerNode defined: ${!!this.stereoPannerNode}.`
|
|
40
|
+
]);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
this.input.disconnect();
|
|
44
|
+
for (const effect of this.effects)
|
|
45
|
+
effect.audioWorkletNode?.disconnect();
|
|
46
|
+
const activeEffects = this.effects.filter(function (e) {
|
|
47
|
+
return !!e.audioWorkletNode;
|
|
48
|
+
});
|
|
49
|
+
if (activeEffects.length === 0) {
|
|
50
|
+
this.input.connect(this.stereoPannerNode);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
this.input.connect(activeEffects[0].audioWorkletNode);
|
|
54
|
+
for (let i = 0; i < activeEffects.length - 1; i++) {
|
|
55
|
+
const current = activeEffects[i].audioWorkletNode;
|
|
56
|
+
const next = activeEffects[i + 1].audioWorkletNode;
|
|
57
|
+
current.connect(next);
|
|
58
|
+
}
|
|
59
|
+
activeEffects[activeEffects.length - 1].audioWorkletNode.connect(this.stereoPannerNode);
|
|
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
|
+
}
|
|
31
97
|
disconnectAudioNodes(gc) {
|
|
32
98
|
this.input?.disconnect();
|
|
33
99
|
this.stereoPannerNode?.disconnect();
|
|
34
100
|
this.analyserNode?.disconnect();
|
|
35
101
|
this.gainNode?.disconnect();
|
|
36
102
|
this.output?.disconnect();
|
|
103
|
+
for (const effect of this.effects) {
|
|
104
|
+
effect.audioWorkletNode?.disconnect();
|
|
105
|
+
}
|
|
37
106
|
if (gc) {
|
|
38
107
|
this.input = null;
|
|
39
108
|
this.stereoPannerNode = null;
|
|
@@ -66,27 +135,27 @@ export class Channel {
|
|
|
66
135
|
if (channel.id === this.id)
|
|
67
136
|
return Debug.Error("Could not link channel to itself.", [
|
|
68
137
|
`This channel id: ${this.id}`
|
|
69
|
-
]);
|
|
138
|
+
], ErrorCodes.CHANNEL_CANNOT_LINK_TO_ITSELF);
|
|
70
139
|
if (!this.isInitialized() || !channel.isInitialized())
|
|
71
140
|
return Debug.Error("Could not link channels because one (or both) channels are not initialized.", [
|
|
72
141
|
`This channel id: ${this.id} initialized: ${this.isInitialized()}`,
|
|
73
142
|
`Target channel id: ${channel.id} initialized: ${channel.isInitialized()}`
|
|
74
|
-
]);
|
|
143
|
+
], ErrorCodes.CHANNEL_NOT_INITIALIZED);
|
|
75
144
|
if (this.context !== channel.context)
|
|
76
145
|
return Debug.Error("Could not link channels because they do not share the same AudioContext.", [
|
|
77
146
|
`This channel context: ${this.context ? "set" : "null"}`,
|
|
78
147
|
`Target channel context: ${channel.context ? "set" : "null"}`
|
|
79
|
-
]);
|
|
148
|
+
], ErrorCodes.CHANNEL_NOT_SAME_AUDIO_CONTEXT);
|
|
80
149
|
if (this.sends.includes(channel))
|
|
81
150
|
return Debug.Error("Could not link channels, because the given channel is already linked with this one.", [
|
|
82
151
|
`This channel id: ${this.id}`,
|
|
83
152
|
`Target channel id: ${channel.id}`
|
|
84
|
-
]);
|
|
153
|
+
], ErrorCodes.CHANNEL_ALREADY_LINKED);
|
|
85
154
|
if (channel.isReachable(this))
|
|
86
155
|
return Debug.Error("Could not link channels because it would create a feedback loop.", [
|
|
87
156
|
`This channel id: ${this.id}`,
|
|
88
157
|
`Target channel id: ${channel.id}`
|
|
89
|
-
]);
|
|
158
|
+
], ErrorCodes.CHANNEL_POSSIBLE_FEEDBACK_LOOP);
|
|
90
159
|
this.output.connect(channel.input);
|
|
91
160
|
this.sends.push(channel);
|
|
92
161
|
}
|
|
@@ -111,7 +180,24 @@ export class Channel {
|
|
|
111
180
|
}
|
|
112
181
|
AttachAudioClip(audioClip) {
|
|
113
182
|
if (!this.audioClipPlayer)
|
|
114
|
-
|
|
183
|
+
throw Error("Cannot not link AudioClip to this channel because this channel's AudioClipPlayer is undefined.");
|
|
115
184
|
this.audioClipPlayer.AttachAudioClip(audioClip);
|
|
185
|
+
return this;
|
|
186
|
+
}
|
|
187
|
+
Volume(volume) {
|
|
188
|
+
if (!this.context)
|
|
189
|
+
throw new Error("Could not set volume on channel, because it's context is undefined.");
|
|
190
|
+
if (!this.gainNode)
|
|
191
|
+
throw new Error("Could not set volume on channel, because it's GainNode is undefined.");
|
|
192
|
+
volume && this.gainNode.gain.setValueAtTime(volume, this.context.currentTime);
|
|
193
|
+
return volume ?? this.gainNode.gain.value;
|
|
194
|
+
}
|
|
195
|
+
Pan(pan) {
|
|
196
|
+
if (!this.context)
|
|
197
|
+
throw new Error("Could not set pan on channel, because it's context is undefined.");
|
|
198
|
+
if (!this.stereoPannerNode)
|
|
199
|
+
throw new Error("Cannot set pan on channel, because it's StereoPannerNode is undefined.");
|
|
200
|
+
pan && this.stereoPannerNode.pan.setValueAtTime(pan, this.context.currentTime);
|
|
201
|
+
return pan ?? this.stereoPannerNode.pan.value;
|
|
116
202
|
}
|
|
117
203
|
}
|
|
@@ -31,7 +31,7 @@ export declare class DspPipeline {
|
|
|
31
31
|
* @param options - Initialization options for the DSP pipeline.
|
|
32
32
|
* Must include valid paths to the WebAssembly and AudioWorklet files.
|
|
33
33
|
*/
|
|
34
|
-
constructor(options: DspPipelineInitializationOptions);
|
|
34
|
+
constructor({ pathToWasm, pathToWorklet, options }: DspPipelineInitializationOptions);
|
|
35
35
|
/**
|
|
36
36
|
* Initializes the DSP pipeline.
|
|
37
37
|
* This is a convenience wrapper around {@link InitializeDpsPipeline}.
|