@fluex/fluexgl-dsp 0.1.2 → 0.2.1
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 +86 -86
- package/lib/dist/core/classes/AudioClip.d.ts +5 -4
- package/lib/dist/core/classes/AudioClip.d.ts.map +1 -1
- package/lib/dist/core/classes/AudioClip.js +2 -6
- package/lib/dist/core/classes/Channel.d.ts +12 -0
- package/lib/dist/core/classes/Channel.d.ts.map +1 -1
- package/lib/dist/core/classes/Channel.js +68 -2
- package/lib/dist/core/classes/Effector.d.ts +1 -0
- 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/Chorus.d.ts +2 -0
- package/lib/dist/effects/classes/Chorus.d.ts.map +1 -1
- package/lib/dist/effects/classes/Chorus.js +2 -0
- package/lib/dist/effects/classes/Distortion.d.ts +5 -1
- package/lib/dist/effects/classes/Distortion.d.ts.map +1 -1
- package/lib/dist/effects/classes/Distortion.js +8 -1
- package/lib/dist/effects/classes/Saturation.d.ts.map +1 -1
- package/lib/dist/effects/classes/SoftClip.d.ts +2 -0
- package/lib/dist/effects/classes/SoftClip.d.ts.map +1 -1
- package/lib/dist/effects/classes/SoftClip.js +2 -0
- package/lib/dist/effects/classes/StereoPanner.d.ts +1 -0
- package/lib/dist/effects/classes/StereoPanner.d.ts.map +1 -1
- package/lib/dist/effects/classes/StereoPanner.js +1 -0
- package/lib/dist/index.d.ts +1 -1
- package/lib/dist/index.d.ts.map +1 -1
- package/lib/dist/index.js +1 -1
- package/lib/dist/utilities/helpers.d.ts +4 -0
- package/lib/dist/utilities/helpers.d.ts.map +1 -1
- package/lib/dist/utilities/helpers.js +12 -0
- package/lib/dist/utilities/web-assembly.d.ts.map +1 -1
- package/lib/src/console-codes.ts +15 -15
- package/lib/src/core/classes/AudioClip.ts +539 -544
- package/lib/src/core/classes/AudioDevice.ts +38 -38
- package/lib/src/core/classes/Channel.ts +288 -198
- package/lib/src/core/classes/DpsPipeline.ts +152 -152
- package/lib/src/core/classes/Effector.ts +11 -10
- package/lib/src/core/classes/Master.ts +49 -49
- package/lib/src/core/exports.ts +5 -5
- package/lib/src/effects/classes/Chorus.ts +111 -108
- package/lib/src/effects/classes/Distortion.ts +14 -1
- package/lib/src/effects/classes/Saturation.ts +3 -1
- package/lib/src/effects/classes/SoftClip.ts +44 -41
- package/lib/src/effects/classes/StereoPanner.ts +3 -1
- package/lib/src/effects/exports.ts +22 -22
- package/lib/src/index.ts +93 -92
- package/lib/src/typings.ts +78 -78
- package/lib/src/utilities/constants.ts +8 -8
- package/lib/src/utilities/debugger.ts +65 -65
- package/lib/src/utilities/helpers.ts +237 -215
- package/lib/src/utilities/web-assembly.ts +12 -13
- package/package.json +51 -50
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
import { v4 } from "uuid";
|
|
2
|
-
|
|
3
|
-
import { Master } from "./Master";
|
|
4
|
-
|
|
5
|
-
import { ErrorCodes } from "../../console-codes";
|
|
6
|
-
import { Debug } from "../../utilities/debugger";
|
|
7
|
-
|
|
8
|
-
export class AudioDevice {
|
|
9
|
-
|
|
10
|
-
public id: string = v4();
|
|
11
|
-
public timestamp: number = Date.now();
|
|
12
|
-
|
|
13
|
-
public masterChannel: Master = new Master();
|
|
14
|
-
public masterChannels: Master[] = [];
|
|
15
|
-
|
|
16
|
-
constructor(public deviceInfo: MediaDeviceInfo) {}
|
|
17
|
-
|
|
18
|
-
public GetMasterChannel(): Master {
|
|
19
|
-
return this.masterChannel;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
public SetMasterChannel(channel: Master): void {
|
|
23
|
-
|
|
24
|
-
if(channel.id === this.masterChannel.id) return Debug.Error("The provided master channel is the same as the current channel.", [
|
|
25
|
-
"Provide this method with a different master channel.",
|
|
26
|
-
`Received master channel ID ${channel.id}.`
|
|
27
|
-
], ErrorCodes.SAME_MASTER_CHANNEL);
|
|
28
|
-
|
|
29
|
-
this.masterChannel = channel;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
public CreateMasterChannel(): Master {
|
|
33
|
-
|
|
34
|
-
const master = new Master();
|
|
35
|
-
|
|
36
|
-
this.masterChannels.push(master);
|
|
37
|
-
return master;
|
|
38
|
-
}
|
|
1
|
+
import { v4 } from "uuid";
|
|
2
|
+
|
|
3
|
+
import { Master } from "./Master";
|
|
4
|
+
|
|
5
|
+
import { ErrorCodes } from "../../console-codes";
|
|
6
|
+
import { Debug } from "../../utilities/debugger";
|
|
7
|
+
|
|
8
|
+
export class AudioDevice {
|
|
9
|
+
|
|
10
|
+
public id: string = v4();
|
|
11
|
+
public timestamp: number = Date.now();
|
|
12
|
+
|
|
13
|
+
public masterChannel: Master = new Master();
|
|
14
|
+
public masterChannels: Master[] = [];
|
|
15
|
+
|
|
16
|
+
constructor(public deviceInfo: MediaDeviceInfo) {}
|
|
17
|
+
|
|
18
|
+
public GetMasterChannel(): Master {
|
|
19
|
+
return this.masterChannel;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
public SetMasterChannel(channel: Master): void {
|
|
23
|
+
|
|
24
|
+
if(channel.id === this.masterChannel.id) return Debug.Error("The provided master channel is the same as the current channel.", [
|
|
25
|
+
"Provide this method with a different master channel.",
|
|
26
|
+
`Received master channel ID ${channel.id}.`
|
|
27
|
+
], ErrorCodes.SAME_MASTER_CHANNEL);
|
|
28
|
+
|
|
29
|
+
this.masterChannel = channel;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public CreateMasterChannel(): Master {
|
|
33
|
+
|
|
34
|
+
const master = new Master();
|
|
35
|
+
|
|
36
|
+
this.masterChannels.push(master);
|
|
37
|
+
return master;
|
|
38
|
+
}
|
|
39
39
|
}
|
|
@@ -1,199 +1,289 @@
|
|
|
1
|
-
import { v4 } from "uuid";
|
|
2
|
-
|
|
3
|
-
import { Effector } from "./Effector";
|
|
4
|
-
import { AudioClip } from "./AudioClip";
|
|
5
|
-
import { Master } from "./Master";
|
|
6
|
-
|
|
7
|
-
import { ChannelOptions } from "../../typings";
|
|
8
|
-
import { Debug } from "../../utilities/debugger";
|
|
9
|
-
|
|
10
|
-
export class Channel {
|
|
11
|
-
|
|
12
|
-
public id: string = v4();
|
|
13
|
-
public effects: Effector[] = [];
|
|
14
|
-
public label: string | null;
|
|
15
|
-
|
|
16
|
-
public parentialContext: AudioContext | null = null;
|
|
17
|
-
public parentialMasterChannel: Master | null = null;
|
|
18
|
-
|
|
19
|
-
public audioClips: AudioClip[] = [];
|
|
20
|
-
|
|
21
|
-
public gainNode: GainNode | null = null;
|
|
22
|
-
public stereoPannerNode: StereoPannerNode | null = null;
|
|
23
|
-
|
|
24
|
-
public
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
this.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
this.
|
|
86
|
-
this.
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
this.
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
this.
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
this.
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
clip
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
clip.
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
])
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
return this.
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
public
|
|
195
|
-
|
|
196
|
-
if (!this.
|
|
197
|
-
|
|
198
|
-
|
|
1
|
+
import { v4 } from "uuid";
|
|
2
|
+
|
|
3
|
+
import { Effector } from "./Effector";
|
|
4
|
+
import { AudioClip } from "./AudioClip";
|
|
5
|
+
import { Master } from "./Master";
|
|
6
|
+
|
|
7
|
+
import { ChannelOptions } from "../../typings";
|
|
8
|
+
import { Debug } from "../../utilities/debugger";
|
|
9
|
+
|
|
10
|
+
export class Channel {
|
|
11
|
+
|
|
12
|
+
public id: string = v4();
|
|
13
|
+
public effects: Effector[] = [];
|
|
14
|
+
public label: string | null;
|
|
15
|
+
|
|
16
|
+
public parentialContext: AudioContext | null = null;
|
|
17
|
+
public parentialMasterChannel: Master | null = null;
|
|
18
|
+
|
|
19
|
+
public audioClips: AudioClip[] = [];
|
|
20
|
+
|
|
21
|
+
public gainNode: GainNode | null = null;
|
|
22
|
+
public stereoPannerNode: StereoPannerNode | null = null;
|
|
23
|
+
public analyserNode: AnalyserNode | null = null;
|
|
24
|
+
public channelSplitterNode: ChannelSplitterNode | null = null;
|
|
25
|
+
|
|
26
|
+
public analyserFloatArrayBuffer = new Float32Array();
|
|
27
|
+
public analyserByteArrayBuffer = new Uint8Array();
|
|
28
|
+
|
|
29
|
+
public audioClipsInputGainNode: GainNode | null = null;
|
|
30
|
+
|
|
31
|
+
public analyserOptions: AnalyserOptions = { fftSize: 32 };
|
|
32
|
+
|
|
33
|
+
constructor(public options: Partial<ChannelOptions> = { maxAudioNodes: 8, maxEffects: 8 }) {
|
|
34
|
+
this.label = options.label ?? null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
private rebuildEffectChain() {
|
|
38
|
+
Debug.Log("Attempting to rebuild effect chain.");
|
|
39
|
+
|
|
40
|
+
if (!this.audioClipsInputGainNode || !this.gainNode) return Debug.Error("Could not rebuild effect chain, because one or more gain nodes on this channel are undefined.", [
|
|
41
|
+
`Channel id: ${this.id}.`,
|
|
42
|
+
`Current amount of effects: ${this.effects.length}.`
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
this.audioClipsInputGainNode.disconnect();
|
|
46
|
+
|
|
47
|
+
for (const effect of this.effects) {
|
|
48
|
+
effect.audioWorkletNode?.disconnect();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const activeEffects = this.effects.filter(e => !!e.audioWorkletNode);
|
|
52
|
+
|
|
53
|
+
if (activeEffects.length === 0) {
|
|
54
|
+
|
|
55
|
+
this.audioClipsInputGainNode.connect(this.gainNode);
|
|
56
|
+
} else {
|
|
57
|
+
|
|
58
|
+
const firstEffectGain = activeEffects[0].audioWorkletNode!;
|
|
59
|
+
this.audioClipsInputGainNode.connect(firstEffectGain);
|
|
60
|
+
|
|
61
|
+
for (let i = 0; i < activeEffects.length - 1; i++) {
|
|
62
|
+
|
|
63
|
+
const current = activeEffects[i].audioWorkletNode!;
|
|
64
|
+
const next = activeEffects[i + 1].audioWorkletNode!;
|
|
65
|
+
|
|
66
|
+
current.connect(next);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const lastEffectGain = activeEffects[activeEffects.length - 1].audioWorkletNode!;
|
|
70
|
+
|
|
71
|
+
lastEffectGain.connect(this.gainNode);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
Debug.Success("Successfully rebuilt effect chain.", [
|
|
75
|
+
`Channel id: ${this.id}.`,
|
|
76
|
+
`Current amount of effects: ${this.effects.length}`
|
|
77
|
+
]);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public InitializeChannelOnMasterAttachment(master: Master) {
|
|
81
|
+
|
|
82
|
+
this.parentialMasterChannel = master;
|
|
83
|
+
this.parentialContext = master.context;
|
|
84
|
+
|
|
85
|
+
this.gainNode = new GainNode(this.parentialContext);
|
|
86
|
+
this.stereoPannerNode = new StereoPannerNode(this.parentialContext);
|
|
87
|
+
this.analyserNode = new AnalyserNode(this.parentialContext, this.analyserOptions);
|
|
88
|
+
|
|
89
|
+
this.analyserFloatArrayBuffer = new Float32Array(this.analyserNode.fftSize);
|
|
90
|
+
this.analyserByteArrayBuffer = new Uint8Array(this.analyserNode.fftSize);
|
|
91
|
+
|
|
92
|
+
this.audioClipsInputGainNode = new GainNode(this.parentialContext);
|
|
93
|
+
|
|
94
|
+
this.audioClipsInputGainNode.connect(this.stereoPannerNode);
|
|
95
|
+
this.stereoPannerNode.connect(this.gainNode);
|
|
96
|
+
this.gainNode.connect(this.analyserNode);
|
|
97
|
+
this.analyserNode.connect(this.parentialMasterChannel.gainNode);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
public SetLabel(label: string): void {
|
|
101
|
+
|
|
102
|
+
this.options.label = label;
|
|
103
|
+
this.label = label;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
public ClearLabel(): void {
|
|
107
|
+
|
|
108
|
+
this.options.label = "";
|
|
109
|
+
this.label = null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
public AttachAudioClip(clip: AudioClip) {
|
|
113
|
+
|
|
114
|
+
if (this.audioClips.includes(clip)) return Debug.Error("Could not attach audio clip because it is already part of this channel", [
|
|
115
|
+
"Call .DetachAudioClip([clip AudioClip]) before attaching audio clip."
|
|
116
|
+
]);
|
|
117
|
+
|
|
118
|
+
clip.InitializeAudioClipOnAttaching(this);
|
|
119
|
+
this.audioClips.push(clip);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public DetachAudioClip(clip: AudioClip) {
|
|
123
|
+
|
|
124
|
+
if (!this.audioClips.includes(clip)) return Debug.Error("Could not detach audio clip, because it is not part of this channel.", [
|
|
125
|
+
"Call .AttachAudioClip([clip AudioClip]) before deattaching audio clip."
|
|
126
|
+
]);
|
|
127
|
+
|
|
128
|
+
const self: Channel = this;
|
|
129
|
+
|
|
130
|
+
clip.parentialAudioContext = null;
|
|
131
|
+
clip.parentialChannel = null;
|
|
132
|
+
clip.hasAttachedToChannel = false;
|
|
133
|
+
|
|
134
|
+
clip.stereoPannerNode?.disconnect();
|
|
135
|
+
clip.gainNode?.disconnect();
|
|
136
|
+
|
|
137
|
+
clip.DisconnectAllAudioBufferSourceNodes();
|
|
138
|
+
|
|
139
|
+
this.audioClips.forEach(function (_clip: AudioClip, index: number) {
|
|
140
|
+
if (clip.id === _clip.id)
|
|
141
|
+
return self.audioClips.splice(index, 1);
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
public HasAudioClip(clip: AudioClip): boolean {
|
|
146
|
+
|
|
147
|
+
for (let _clip of this.audioClips) {
|
|
148
|
+
if (_clip.id === clip.id) return true;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
public SetVolume(volume: number): void {
|
|
155
|
+
|
|
156
|
+
if (!this.gainNode) return Debug.Error("Could not set channel volume because the channel is not attached to a master channel.", [
|
|
157
|
+
"Attach the channel to a master channel before setting the volume."
|
|
158
|
+
]);
|
|
159
|
+
|
|
160
|
+
this.gainNode.gain.setValueAtTime(volume, this.parentialContext!.currentTime);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
public SetPanLevel(pan: number): void {
|
|
164
|
+
|
|
165
|
+
if (!this.stereoPannerNode) return Debug.Error("Could not set channel pan level because the channel is not attached to a master channel.", [
|
|
166
|
+
"Attach the channel to a master channel before setting the pan level."
|
|
167
|
+
]);
|
|
168
|
+
|
|
169
|
+
this.stereoPannerNode.pan.setValueAtTime(pan, this.parentialContext!.currentTime);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
public AddEffect(effect: Effector): void {
|
|
173
|
+
|
|
174
|
+
if (!this.parentialContext) return Debug.Error("Could not add effect on channel, because the parential context is undefined.", [
|
|
175
|
+
`Channel ID: ${this.id}`,
|
|
176
|
+
`Effect ID: ${effect.id}`,
|
|
177
|
+
`Effect name: ${effect.constructor.name}`
|
|
178
|
+
])
|
|
179
|
+
|
|
180
|
+
if (this.effects.includes(effect)) return Debug.Error("Could not add effect because it is already part of this channel", [
|
|
181
|
+
"Call .RemoveEffect([effect Effector]) before adding effect."
|
|
182
|
+
]);
|
|
183
|
+
|
|
184
|
+
effect.InitializeOnAttachment(this.parentialContext);
|
|
185
|
+
|
|
186
|
+
this.effects.push(effect);
|
|
187
|
+
this.rebuildEffectChain();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
public AttachEffect(effect: Effector): void {
|
|
191
|
+
return this.AddEffect(effect);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
public RemoveEffect(effect: Effector): void {
|
|
195
|
+
|
|
196
|
+
if (!this.effects.includes(effect)) return Debug.Error("Could not remove effect, because it is not part of this channel.", [
|
|
197
|
+
"Call .AddEffect([effect Effector]) before removing effect."
|
|
198
|
+
]);
|
|
199
|
+
|
|
200
|
+
const self: Channel = this;
|
|
201
|
+
|
|
202
|
+
this.effects.forEach(function (_effect: Effector, index: number) {
|
|
203
|
+
if (effect.id === _effect.id)
|
|
204
|
+
return self.effects.splice(index, 1);
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
this.rebuildEffectChain();
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
public DetachEffect(effect: Effector): void {
|
|
211
|
+
return this.RemoveEffect(effect);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
public SetAnalyserFftSize(value: number): number | null {
|
|
215
|
+
|
|
216
|
+
if (!this.analyserNode) {
|
|
217
|
+
Debug.Error("Could not set FFT size on analyser because the analyser has not been defined.");
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
this.analyserNode.fftSize = value;
|
|
222
|
+
|
|
223
|
+
this.analyserFloatArrayBuffer = new Float32Array(this.analyserNode.fftSize);
|
|
224
|
+
this.analyserByteArrayBuffer = new Uint8Array(this.analyserNode.fftSize);
|
|
225
|
+
|
|
226
|
+
return this.analyserNode.fftSize;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
public GetWaveformFloatData(): Float32Array | null {
|
|
230
|
+
|
|
231
|
+
if (!this.analyserNode) {
|
|
232
|
+
Debug.Error("Could not get waveform float data, because the analyser has not been defined.");
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (this.analyserFloatArrayBuffer.length !== this.analyserNode.fftSize) {
|
|
237
|
+
this.analyserFloatArrayBuffer = new Float32Array(this.analyserNode.fftSize);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
this.analyserNode.getFloatTimeDomainData(this.analyserFloatArrayBuffer);
|
|
241
|
+
return this.analyserFloatArrayBuffer;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
public GetWaveformByteData(): Uint8Array | null {
|
|
245
|
+
|
|
246
|
+
if (!this.analyserNode) {
|
|
247
|
+
Debug.Error("Could not get waveform byte data, because the analyser has not been defined.");
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (this.analyserByteArrayBuffer.length !== this.analyserNode.fftSize) {
|
|
252
|
+
this.analyserByteArrayBuffer = new Uint8Array(this.analyserNode.fftSize);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
this.analyserNode.getByteTimeDomainData(this.analyserByteArrayBuffer);
|
|
256
|
+
return this.analyserByteArrayBuffer;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
public SetAnalyserOptions(options: AnalyserOptions): Channel | null {
|
|
260
|
+
|
|
261
|
+
this.analyserOptions = {...options};
|
|
262
|
+
|
|
263
|
+
if (!this.analyserNode) return null;
|
|
264
|
+
|
|
265
|
+
this.analyserNode.minDecibels = options.minDecibels ?? this.analyserNode.minDecibels;
|
|
266
|
+
this.analyserNode.maxDecibels = options.maxDecibels ?? this.analyserNode.maxDecibels;
|
|
267
|
+
this.analyserNode.fftSize = options.fftSize ?? 32;
|
|
268
|
+
this.analyserNode.smoothingTimeConstant = options.smoothingTimeConstant ?? this.analyserNode.smoothingTimeConstant;
|
|
269
|
+
|
|
270
|
+
this.analyserByteArrayBuffer = new Uint8Array(this.analyserNode.fftSize);
|
|
271
|
+
this.analyserFloatArrayBuffer = new Float32Array(this.analyserNode.fftSize);
|
|
272
|
+
|
|
273
|
+
return this;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Public getters and setters
|
|
277
|
+
|
|
278
|
+
public get volume(): number | null {
|
|
279
|
+
|
|
280
|
+
if (!this.gainNode) return null;
|
|
281
|
+
return this.gainNode.gain.value;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
public get panLevel(): number | null {
|
|
285
|
+
|
|
286
|
+
if (!this.stereoPannerNode) return null;
|
|
287
|
+
return this.stereoPannerNode.pan.value;
|
|
288
|
+
}
|
|
199
289
|
}
|