@fluex/fluexgl-dsp 0.3.4 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/lib/dist/core/classes/AudioClip.d.ts +10 -28
  2. package/lib/dist/core/classes/AudioClip.d.ts.map +1 -1
  3. package/lib/dist/core/classes/AudioClip.js +56 -192
  4. package/lib/dist/core/classes/AudioClipPlayer.d.ts +15 -0
  5. package/lib/dist/core/classes/AudioClipPlayer.d.ts.map +1 -0
  6. package/lib/dist/core/classes/AudioClipPlayer.js +31 -0
  7. package/lib/dist/core/classes/AudioDevice.d.ts +2 -0
  8. package/lib/dist/core/classes/AudioDevice.d.ts.map +1 -1
  9. package/lib/dist/core/classes/AudioDevice.js +6 -2
  10. package/lib/dist/core/classes/Channel.d.ts +16 -34
  11. package/lib/dist/core/classes/Channel.d.ts.map +1 -1
  12. package/lib/dist/core/classes/Channel.js +95 -190
  13. package/lib/dist/core/classes/DpsPipeline.js +2 -2
  14. package/lib/dist/core/classes/Effector.d.ts.map +1 -1
  15. package/lib/dist/core/classes/Effector.js +0 -1
  16. package/lib/dist/core/classes/Master.d.ts +4 -4
  17. package/lib/dist/core/classes/Master.d.ts.map +1 -1
  18. package/lib/dist/core/classes/Master.js +11 -5
  19. package/lib/dist/core/exports.d.ts +1 -0
  20. package/lib/dist/core/exports.d.ts.map +1 -1
  21. package/lib/dist/core/exports.js +1 -0
  22. package/lib/dist/core/functions/rebuild-effect-chain.d.ts +3 -0
  23. package/lib/dist/core/functions/rebuild-effect-chain.d.ts.map +1 -0
  24. package/lib/dist/core/functions/rebuild-effect-chain.js +2 -0
  25. package/lib/dist/index.d.ts +2 -2
  26. package/lib/dist/index.d.ts.map +1 -1
  27. package/lib/dist/index.js +2 -2
  28. package/lib/dist/test/linkable-channels.d.ts +2 -0
  29. package/lib/dist/test/linkable-channels.d.ts.map +1 -0
  30. package/lib/dist/test/linkable-channels.js +16 -0
  31. package/lib/dist/utilities/helpers.d.ts +1 -2
  32. package/lib/dist/utilities/helpers.d.ts.map +1 -1
  33. package/lib/dist/utilities/helpers.js +5 -5
  34. package/lib/src/core/classes/AudioClip.ts +62 -236
  35. package/lib/src/core/classes/AudioClipPlayer.ts +45 -0
  36. package/lib/src/core/classes/AudioDevice.ts +12 -6
  37. package/lib/src/core/classes/Channel.ts +88 -221
  38. package/lib/src/core/classes/DpsPipeline.ts +2 -2
  39. package/lib/src/core/classes/Effector.ts +1 -3
  40. package/lib/src/core/classes/Master.ts +24 -12
  41. package/lib/src/core/exports.ts +2 -1
  42. package/lib/src/core/functions/rebuild-effect-chain.ts +5 -0
  43. package/lib/src/index.ts +3 -2
  44. package/lib/src/utilities/helpers.ts +5 -5
  45. package/package.json +2 -1
@@ -4,13 +4,13 @@ import { format } from "date-fns";
4
4
  import { AudioClipAnalyserProperty, AudioClipAnalyserType, AudioClipEventMap, AudioClipEvents, AudioSourceData } from "../../typings";
5
5
  import { Debug } from "../../utilities/debugger";
6
6
  import { Channel } from "./Channel";
7
+ import { AudioClipPlayer } from "./AudioClipPlayer";
7
8
 
8
9
  type ProgressPayload = Parameters<AudioClipEventMap["progress"]>[0];
9
10
 
10
11
  export class AudioClip {
11
12
 
12
13
  public id: string = v4();
13
- public hasAttachedToChannel: boolean = false;
14
14
  public label: string | null = null;
15
15
 
16
16
  public loop: boolean = false;
@@ -23,23 +23,8 @@ export class AudioClip {
23
23
  public gainNode: GainNode | null = null;
24
24
  public stereoPannerNode: StereoPannerNode | null = null;
25
25
 
26
- public parentialAudioContext: AudioContext | null = null;
27
- public parentialChannel: Channel | null = null;
28
-
29
- public preAnalyser: AnalyserNode | null = null;
30
- public postAnalyser: AnalyserNode | null = null;
31
-
32
- public preAnalyserEnabled: boolean = false;
33
- public postAnalyserEnabled: boolean = false;
34
-
35
- public preAnalyserOptions: AnalyserOptions = {};
36
- public postAnalyserOptions: AnalyserOptions = {};
37
-
38
- public preAnalyserFloatArrayBuffer = new Float32Array();
39
- public postAnalyserFloatArrayBuffer = new Float32Array();
40
-
41
- public preAnalyserByteArrayBuffer = new Uint8Array();
42
- public postAnalyserByteArrayBuffer = new Uint8Array();
26
+ public context: AudioContext | null = null;
27
+ public audioClipPlayer: AudioClipPlayer | null = null;
43
28
 
44
29
  private audioBufferSourceNodes: AudioBufferSourceNode[] = [];
45
30
  private maxAudioBufferSourceNodes: number = 1;
@@ -52,13 +37,11 @@ export class AudioClip {
52
37
 
53
38
  constructor(public data: AudioSourceData) { }
54
39
 
55
- // Private methods.
56
-
57
40
  private createBufferSource(): AudioBufferSourceNode | null {
58
41
 
59
- if (!this.parentialAudioContext) return null;
42
+ if (!this.context) return null;
60
43
 
61
- const context = this.parentialAudioContext;
44
+ const context = this.context;
62
45
 
63
46
  const bufferSource = context.createBufferSource();
64
47
  bufferSource.buffer = this.data.audioBuffer;
@@ -78,74 +61,46 @@ export class AudioClip {
78
61
  node?.disconnect();
79
62
  }
80
63
 
81
- private rebuildNodeChain() {
82
-
83
- if (!this.parentialAudioContext || !this.gainNode || !this.stereoPannerNode || !this.parentialChannel || !this.parentialChannel.audioClipsInputGainNode) {
64
+ private rebuildNodeChain(): boolean {
84
65
 
85
- Debug.Error("rebuildNodeChain: missing context or core nodes (gain/panner).");
66
+ if (!this.context || !this.gainNode || !this.stereoPannerNode || !this.audioClipPlayer || !this.audioClipPlayer.outputGainNode) {
67
+ Debug.Error("Failed to rebuild node chain, because some of the core AudioNodes are missing.");
86
68
  return false;
87
69
  }
88
70
 
89
- const destination = this.parentialChannel.audioClipsInputGainNode;
71
+ const destination = this.audioClipPlayer.outputGainNode;
90
72
 
91
73
  this.safeDisconnect(this.gainNode);
92
74
  this.safeDisconnect(this.stereoPannerNode);
93
- this.safeDisconnect(this.preAnalyser);
94
- this.safeDisconnect(this.postAnalyser);
95
-
96
- let entry: AudioNode = this.gainNode;
97
-
98
- if (this.preAnalyserEnabled && this.preAnalyser) {
99
-
100
- entry = this.preAnalyser;
101
- this.preAnalyser.connect(this.gainNode);
102
- }
103
75
 
104
76
  this.gainNode.connect(this.stereoPannerNode);
77
+ this.stereoPannerNode.connect(destination);
105
78
 
106
- if (this.postAnalyserEnabled && this.postAnalyser) {
107
- this.stereoPannerNode.connect(this.postAnalyser);
108
- this.postAnalyser.connect(destination);
109
- } else {
110
- this.stereoPannerNode.connect(destination);
111
- }
112
-
113
- this.connectSourcesTo(entry);
79
+ this.connectSourcesTo(this.gainNode);
114
80
  return true;
115
81
  }
116
82
 
117
- // Public methods
118
-
119
- public InitializeAudioClipOnAttaching(channel: Channel): AudioClip | null {
120
-
121
- if (!channel.parentialContext || !channel.audioClipsInputGainNode) {
122
-
123
- Debug.Error("Could not initialize audio clip on channel attachment, because channel it's master channel has not been defined.", [
124
- `Call .AttachChannel([channel<"${channel.id}"> Channel]) on the master channel.`
125
- ]);
126
- return null;
127
- }
83
+ public Initialize(audioClipPlayer: AudioClipPlayer) {
128
84
 
129
- this.gainNode = new GainNode(channel.parentialContext);
130
- this.stereoPannerNode = new StereoPannerNode(channel.parentialContext);
85
+ if (!audioClipPlayer.context) return Debug.Error("Could not initialize AudioClip, because the AudioClipPlayer somehow has no audio context.", [
86
+ `AudioClipPlayer id: ${audioClipPlayer.id}`,
87
+ `AudioClip id: ${this.id}`
88
+ ]);
131
89
 
132
- this.parentialAudioContext = channel.parentialContext;
133
- this.parentialChannel = channel;
134
- this.hasAttachedToChannel = true;
90
+ this.audioClipPlayer = audioClipPlayer;
91
+ this.context = audioClipPlayer.context;
135
92
 
136
- return this;
93
+ this.gainNode = new GainNode(this.context);
94
+ this.stereoPannerNode = new StereoPannerNode(this.context);
137
95
  }
138
96
 
139
- public Play(timestamp?: number, offset?: number): AudioClip | null {
97
+ public Play(timestamp?: number, offset?: number) {
140
98
 
141
- if (!this.hasAttachedToChannel || !this.parentialAudioContext || !this.parentialChannel) {
142
- Debug.Error("Could not play the audio node because it is not attached to a channel", [
143
- "Call 'AttachAudioClip([clip AudioClip])' on a channel, before playing this audio node."
144
- ]);
145
- return this;
146
- }
99
+ if (!this.context) return Debug.Error("Could not play audio clip, because context (AudioContext) is undefined.", [
100
+ "Make sure to attach this AudioClip to an AudioClipPlayer instance, before calling .Play on this AudioClip."
101
+ ]);
147
102
 
148
- const context = this.parentialAudioContext;
103
+ const context = this.context;
149
104
  const self = this;
150
105
 
151
106
  if (this.audioBufferSourceNodes.length > this.maxAudioBufferSourceNodes - 1) return null;
@@ -208,19 +163,19 @@ export class AudioClip {
208
163
  return this;
209
164
  }
210
165
 
211
- public Seek(seconds: number): AudioClip | null {
166
+ public Seek(seconds: number) {
212
167
 
213
- if (!this.parentialAudioContext || !this.hasAttachedToChannel) {
214
- Debug.Error("Could not seek because the clip is not attached to a channel.", [
215
- `Clip ID: ${this.id}`
216
- ]);
217
- return null;
218
- }
168
+ if (!this.context) return Debug.Error("Could not seek because the context (AudioContext) of this AudioClip is undefined.", [
169
+ `Make sure to attach this AudioClip to an AudioClipPlayer instance before calling .Seek on this AudioClip.`,
170
+ `AudioClip id: ${this.id}`
171
+ ]);
219
172
 
220
173
  const clamped = Math.max(0, Math.min(seconds, this.duration));
221
174
 
222
175
  if (!this.isPlaying) {
176
+
223
177
  this.offsetAtStart = clamped;
178
+
224
179
  return this;
225
180
  }
226
181
 
@@ -230,20 +185,9 @@ export class AudioClip {
230
185
  return this;
231
186
  }
232
187
 
233
-
234
188
  public Stop(): AudioClip | null {
235
189
 
236
- if (!this.hasAttachedToChannel || !this.parentialAudioContext) {
237
-
238
- Debug.Error("Could not stop the audio node because it is not attached to a channel", [
239
- "Call 'AttachAudioClip([node AudioNode])' on a channel, before stopping this audio node."
240
- ]);
241
-
242
- return null;
243
- }
244
-
245
190
  this.audioBufferSourceNodes.forEach(function (node: AudioBufferSourceNode) {
246
-
247
191
  node.stop();
248
192
  node.disconnect();
249
193
  });
@@ -252,35 +196,43 @@ export class AudioClip {
252
196
  this.isPlaying = false;
253
197
 
254
198
  if (this.progressInterval) {
255
-
256
199
  clearInterval(this.progressInterval);
257
200
  this.progressInterval = null;
258
201
  }
259
202
 
260
203
  return this;
261
204
  }
262
- public SetVolume(volume: number): AudioClip | void {
263
205
 
264
- if (!this.gainNode || !this.parentialAudioContext) return Debug.Error("Something went wrong while setting the volume.", [
265
- `Gain node on audio clip '${this.id}' is undefined.`
206
+ public SetVolume(volume: number): AudioClip {
207
+
208
+ if (!this.context) Debug.Error("Could not set volume because the context (AudioContext) of this AudioClip is undefined.", [
209
+ "Make sure to attach this AudioClip to an AudioClipPlayer instance before calling .SetVolume() on this AudioClip.",
266
210
  ]);
267
211
 
268
- this.gainNode.gain.setValueAtTime(volume, this.parentialAudioContext.currentTime);
212
+ if (!this.gainNode) Debug.Error("Could not set volume because the gainNode (GainNode) of this AudioClip is undefined.", [
213
+ "Make sure to attach this AudioClip to an AudioClipPlayer instance before calling .SetVolume() on this AudioClip.",
214
+ ]);
269
215
 
216
+ this.gainNode?.gain.setValueAtTime(volume, this.context?.currentTime ?? 0);
270
217
  return this;
271
218
  }
272
219
 
273
- public SetPanLevel(panLevel: number): AudioClip | void {
220
+ public SetPanLevel(panLevel: number): AudioClip {
221
+
222
+ if (!this.context) Debug.Error("Could not set volume because the context (AudioContext) of this AudioClip is undefined.", [
223
+ "Make sure to attach this AudioClip to an AudioClipPlayer instance before calling .SetPanLevel() on this AudioClip.",
224
+ ]);
274
225
 
275
- if (!this.stereoPannerNode || !this.parentialAudioContext) return Debug.Error("Something went wrong while setting the pan level", [
276
- `Stereo panner node on audio clip '${this.id}' is undefined`
226
+ if (!this.stereoPannerNode) Debug.Error("Could not set volume because the stereoPannerNode (StereoPannerNode) of this AudioClip is undefined.", [
227
+ "Make sure to attach this AudioClip to an AudioClipPlayer instance before calling .SetPanLevel() on this AudioClip.",
277
228
  ]);
278
229
 
279
- if (panLevel < -1 || panLevel > 1) return Debug.Error("Could not set the pan level because it is not between -1 and 1.", [
280
- "Provide this method with a value between -1 and 1"
230
+ if (panLevel < -1 || panLevel > 1) Debug.Error("Could not set the pan level because it is not between -1 and 1.", [
231
+ `Given value: ${panLevel}.`,
232
+ `Accepts a value between -1 and 1. Can be a floating number.`
281
233
  ]);
282
234
 
283
- this.stereoPannerNode.pan.setValueAtTime(panLevel, this.parentialAudioContext.currentTime);
235
+ this.stereoPannerNode?.pan.setValueAtTime(panLevel, this.context?.currentTime ?? 0);
284
236
  return this;
285
237
  }
286
238
 
@@ -306,9 +258,9 @@ export class AudioClip {
306
258
 
307
259
  public DisconnectAllAudioBufferSourceNodes(): boolean {
308
260
 
309
- if (!this.parentialAudioContext) return false;
261
+ if (!this.context) return false;
310
262
 
311
- const contextCurrentTime: number = this.parentialAudioContext?.currentTime;
263
+ const contextCurrentTime: number = this.context?.currentTime;
312
264
 
313
265
  this.audioBufferSourceNodes.forEach(function (node: AudioBufferSourceNode) {
314
266
  node.stop(contextCurrentTime);
@@ -321,7 +273,6 @@ export class AudioClip {
321
273
  public AddEventListener<K extends keyof AudioClipEventMap>(event: K, cb: AudioClipEventMap[K]): () => void {
322
274
 
323
275
  this.events[event].push(cb);
324
-
325
276
  return () => this.RemoveEventListener(event, cb);
326
277
  }
327
278
 
@@ -331,7 +282,6 @@ export class AudioClip {
331
282
 
332
283
  // @ts-ignore
333
284
  cb(...args);
334
-
335
285
  this.RemoveEventListener(event, wrapper as unknown as AudioClipEventMap[K]);
336
286
  }) as unknown as AudioClipEventMap[K];
337
287
 
@@ -363,148 +313,24 @@ export class AudioClip {
363
313
  }
364
314
 
365
315
  public GetChannelData(channel: number = 0): Float32Array {
366
-
367
316
  return this.data.audioBuffer.getChannelData(channel);
368
317
  }
369
318
 
370
- public EnablePreAnalyser(): boolean {
319
+ public Send(channel: Channel) {
371
320
 
372
- if (!this.parentialAudioContext || !this.parentialChannel || !this.hasAttachedToChannel) {
373
- Debug.Error("EnablePreAnalyser: clip niet aan channel gekoppeld.");
374
- return false;
375
- }
376
-
377
- if (!this.preAnalyser)
378
- this.preAnalyser = new AnalyserNode(this.parentialAudioContext, this.preAnalyserOptions);
379
-
380
- this.preAnalyserFloatArrayBuffer = new Float32Array(this.preAnalyser.fftSize);
381
- this.preAnalyserByteArrayBuffer = new Uint8Array(this.preAnalyser.fftSize);
382
-
383
- this.preAnalyserEnabled = true;
384
- return this.rebuildNodeChain();
385
- }
386
-
387
- public DisablePreAnalyser() {
388
-
389
- this.preAnalyserEnabled = false;
390
- return this.rebuildNodeChain();
391
- }
392
-
393
- public EnablePostAnalyser() {
394
-
395
- if (!this.parentialAudioContext || !this.parentialChannel || !this.hasAttachedToChannel) {
396
-
397
- Debug.Error("EnablePostAnalyser: clip niet aan channel gekoppeld.");
398
- return false;
399
- }
400
-
401
- if (!this.postAnalyser)
402
- this.postAnalyser = new AnalyserNode(this.parentialAudioContext, this.postAnalyserOptions);
403
-
404
- this.postAnalyserFloatArrayBuffer = new Float32Array(this.postAnalyser.fftSize);
405
- this.postAnalyserByteArrayBuffer = new Uint8Array(this.postAnalyser.fftSize);
406
-
407
- this.postAnalyserEnabled = true;
408
- return this.rebuildNodeChain();
409
- }
410
-
411
- public DisablePostAnalyser() {
412
-
413
- this.postAnalyserEnabled = false;
414
- return this.rebuildNodeChain();
415
- }
416
-
417
- public SetPreAnalyserOptions(options: AnalyserOptions) {
418
-
419
- this.preAnalyserOptions = { ...options };
420
-
421
- if (!this.preAnalyser) return;
422
-
423
- this.preAnalyser.fftSize = options.fftSize ?? this.preAnalyser.fftSize;
424
- this.preAnalyser.minDecibels = options.minDecibels ?? this.preAnalyser.minDecibels;
425
- this.preAnalyser.maxDecibels = options.maxDecibels ?? this.preAnalyser.maxDecibels;
426
- this.preAnalyser.smoothingTimeConstant = options.smoothingTimeConstant ?? this.preAnalyser.smoothingTimeConstant;
427
- }
428
-
429
- public SetPostAnalyserOptions(options: AnalyserOptions) {
430
-
431
- this.postAnalyserOptions = { ...options };
432
-
433
- if (!this.postAnalyser) return;
434
-
435
- this.postAnalyser.fftSize = options.fftSize ?? this.postAnalyser.fftSize;
436
- this.postAnalyser.minDecibels = options.minDecibels ?? this.postAnalyser.minDecibels;
437
- this.postAnalyser.maxDecibels = options.maxDecibels ?? this.postAnalyser.maxDecibels;
438
- this.postAnalyser.smoothingTimeConstant = options.smoothingTimeConstant ?? this.postAnalyser.smoothingTimeConstant;
439
- }
440
-
441
- public SetAnalyserOption(analyserType: AudioClipAnalyserType, property: AudioClipAnalyserProperty, value: number) {
442
-
443
- const node = analyserType === "pre" ? this.preAnalyser : this.postAnalyser;
444
-
445
- if (node) switch (property) {
446
- case "fftSize": node.fftSize = value as AnalyserNode["fftSize"]; break;
447
- case "minDecibels": node.minDecibels = value; break;
448
- case "maxDecibels": node.maxDecibels = value; break;
449
- case "smoothingTimeConstant": node.smoothingTimeConstant = value; break;
450
- default: return false;
451
- }
452
-
453
- const opts = analyserType === "pre" ? this.preAnalyserOptions : this.postAnalyserOptions;
454
-
455
- switch (property) {
456
- case "fftSize": opts.fftSize = value as AnalyserNode["fftSize"]; break;
457
- case "minDecibels": opts.minDecibels = value; break;
458
- case "maxDecibels": opts.maxDecibels = value; break;
459
- case "smoothingTimeConstant": opts.smoothingTimeConstant = value; break;
460
- default: return false;
461
- }
462
-
463
- return true;
464
- }
465
-
466
- public GetWaveformFloatData(analyserType: AudioClipAnalyserType): Float32Array | null {
467
-
468
- if (analyserType === "pre" && this.preAnalyser) {
469
- this.preAnalyser.getFloatTimeDomainData(this.preAnalyserFloatArrayBuffer);
470
- return this.preAnalyserFloatArrayBuffer;
471
- } else if (analyserType === "post" && this.postAnalyser) {
472
- this.postAnalyser.getFloatTimeDomainData(this.postAnalyserFloatArrayBuffer);
473
- return this.postAnalyserFloatArrayBuffer;
474
- }
475
-
476
- return null;
477
- }
478
-
479
- public GetWaveformByteData(analyserType: AudioClipAnalyserType): Uint8Array | null {
480
-
481
- if (!this.preAnalyser || !this.postAnalyser) {
482
-
483
- Debug.Error("Could not get byte waveform data because the pre analyser or post analyser has not been enabled.", [
484
- "Call .EnablePreAnalyser() or .EnablePostAnalyser() before getting waveform data."
485
- ]);
486
-
487
- return null;
488
- }
321
+ if(!channel.HasAudioClipPlayer()) return Debug.Error("Could not send AudioClip signal to channel, because the channel's AudioClipPlayer is undefined.", [
322
+ "Make sure to initialize the Channel.",
323
+ `Channel id: ${channel.id}.`,
324
+ `AudioClip id: ${this.id}.`
325
+ ]);
489
326
 
490
- switch (analyserType) {
491
- case "pre":
492
- this.preAnalyser.getByteTimeDomainData(this.preAnalyserByteArrayBuffer);
493
- return this.preAnalyserByteArrayBuffer;
494
- case "post":
495
- this.postAnalyser.getByteTimeDomainData(this.postAnalyserByteArrayBuffer);
496
- return this.postAnalyserByteArrayBuffer;
497
- default:
498
- return null;
499
- }
327
+ channel.AttachAudioClip(this);
500
328
  }
501
329
 
502
- // Public getters and setters
503
-
504
330
  public get currentPlaybackTime(): number {
505
- return (!this.isPlaying || !this.parentialAudioContext)
331
+ return (!this.isPlaying || !this.context)
506
332
  ? 0
507
- : this.offsetAtStart + (this.parentialAudioContext.currentTime - this.startTime);
333
+ : this.offsetAtStart + (this.context.currentTime - this.startTime);
508
334
  }
509
335
 
510
336
  public get duration(): number {
@@ -0,0 +1,45 @@
1
+ import { v4 } from "uuid";
2
+
3
+ import { AudioClip } from "./AudioClip";
4
+ import { Debug } from "../../utilities/debugger";
5
+ import { Master } from "./Master";
6
+ import { Channel } from "./Channel";
7
+
8
+ export class AudioClipPlayer {
9
+
10
+ public label: string = "AudioClipPlayer";
11
+ public id: string = v4();
12
+
13
+ public audioClips: AudioClip[] = [];
14
+ public outputGainNode: GainNode | null = null;
15
+
16
+ public context: AudioContext | null = null;
17
+ public channel: Channel | null = null;
18
+
19
+ constructor(context: AudioContext) {
20
+ this.context = context;
21
+ this.outputGainNode = new GainNode(context);
22
+ }
23
+
24
+ public AttachAudioClip(audioClip: AudioClip) {
25
+
26
+ if (this.audioClips.includes(audioClip)) return Debug.Error("Could not attach audio clip because it is already part of this channel", [
27
+ "Call .DetachAudioClip([clip AudioClip]) before attaching audio clip."
28
+ ]);
29
+
30
+ audioClip.Initialize(this);
31
+ this.audioClips.push(audioClip);
32
+ }
33
+
34
+ public Send(channel: Channel) {
35
+
36
+ if(!this.outputGainNode || !channel.input) return Debug.Error("Could not send AudioClipPlayer signal to a channel.");
37
+
38
+ this.channel = channel;
39
+ this.outputGainNode.connect(channel.input);
40
+ }
41
+
42
+ public SetLabel(label: string) {
43
+ this.label = label;
44
+ }
45
+ }
@@ -10,20 +10,22 @@ export class AudioDevice {
10
10
  public id: string = v4();
11
11
  public timestamp: number = Date.now();
12
12
 
13
- public masterChannel: Master = new Master();
13
+ public context: AudioContext = new AudioContext();
14
+
15
+ public masterChannel: Master = new Master(this.context);
14
16
  public masterChannels: Master[] = [];
15
17
 
16
- constructor(public deviceInfo: MediaDeviceInfo) {}
18
+ constructor(public deviceInfo: MediaDeviceInfo) { }
17
19
 
18
20
  public GetMasterChannel(): Master {
19
21
  return this.masterChannel;
20
22
  }
21
23
 
22
24
  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
+
26
+ if (channel.id === this.masterChannel.id) return Debug.Error("The provided master channel is the same as the current channel.", [
25
27
  "Provide this method with a different master channel.",
26
- `Received master channel ID ${channel.id}.`
28
+ `Received master channel ID ${channel.id}.`
27
29
  ], ErrorCodes.SAME_MASTER_CHANNEL);
28
30
 
29
31
  this.masterChannel = channel;
@@ -31,9 +33,13 @@ export class AudioDevice {
31
33
 
32
34
  public CreateMasterChannel(): Master {
33
35
 
34
- const master = new Master();
36
+ const master = new Master(this.context);
35
37
 
36
38
  this.masterChannels.push(master);
37
39
  return master;
38
40
  }
41
+
42
+ public GetContext(): AudioContext {
43
+ return this.context;
44
+ }
39
45
  }