react-native-audio-api 0.4.13 → 0.5.0-rc.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.
Files changed (110) hide show
  1. package/android/src/main/java/com/swmansion/audioapi/AudioAPIModule.kt +7 -6
  2. package/android/src/main/java/com/swmansion/audioapi/AudioAPIPackage.kt +25 -24
  3. package/common/cpp/audioapi/HostObjects/AnalyserNodeHostObject.h +17 -41
  4. package/common/cpp/audioapi/HostObjects/AudioBufferHostObject.h +22 -32
  5. package/common/cpp/audioapi/HostObjects/AudioBufferSourceNodeHostObject.h +2 -17
  6. package/common/cpp/audioapi/HostObjects/AudioContextHostObject.h +14 -4
  7. package/common/cpp/audioapi/HostObjects/AudioParamHostObject.h +5 -8
  8. package/common/cpp/audioapi/HostObjects/BaseAudioContextHostObject.h +13 -9
  9. package/common/cpp/audioapi/HostObjects/BiquadFilterNodeHostObject.h +8 -19
  10. package/common/cpp/audioapi/core/AudioContext.cpp +14 -4
  11. package/common/cpp/audioapi/core/AudioContext.h +2 -2
  12. package/common/cpp/audioapi/core/BaseAudioContext.cpp +4 -2
  13. package/common/cpp/audioapi/core/BaseAudioContext.h +1 -1
  14. package/common/cpp/audioapi/core/effects/BiquadFilterNode.cpp +5 -6
  15. package/common/cpp/audioapi/core/effects/BiquadFilterNode.h +4 -3
  16. package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.cpp +5 -11
  17. package/common/cpp/audioapi/core/sources/AudioBufferSourceNode.h +3 -31
  18. package/lib/module/api.js +1 -1
  19. package/lib/module/api.js.map +1 -1
  20. package/lib/module/api.web.js +1 -2
  21. package/lib/module/api.web.js.map +1 -1
  22. package/lib/module/core/AnalyserNode.js.map +1 -1
  23. package/lib/module/core/AudioBuffer.js.map +1 -1
  24. package/lib/module/core/AudioBufferSourceNode.js +0 -6
  25. package/lib/module/core/AudioBufferSourceNode.js.map +1 -1
  26. package/lib/module/core/AudioParam.js.map +1 -1
  27. package/lib/module/core/BaseAudioContext.js +3 -2
  28. package/lib/module/core/BaseAudioContext.js.map +1 -1
  29. package/lib/module/core/BiquadFilterNode.js.map +1 -1
  30. package/lib/module/utils/index.js +6 -0
  31. package/lib/module/utils/index.js.map +1 -0
  32. package/lib/module/web-core/AnalyserNode.js +4 -20
  33. package/lib/module/web-core/AnalyserNode.js.map +1 -1
  34. package/lib/module/web-core/AudioBuffer.js +2 -6
  35. package/lib/module/web-core/AudioBuffer.js.map +1 -1
  36. package/lib/module/web-core/AudioBufferSourceNode.js +161 -21
  37. package/lib/module/web-core/AudioBufferSourceNode.js.map +1 -1
  38. package/lib/module/web-core/AudioContext.js +7 -8
  39. package/lib/module/web-core/AudioContext.js.map +1 -1
  40. package/lib/module/web-core/AudioParam.js +1 -1
  41. package/lib/module/web-core/AudioParam.js.map +1 -1
  42. package/lib/module/web-core/BiquadFilterNode.js +1 -9
  43. package/lib/module/web-core/BiquadFilterNode.js.map +1 -1
  44. package/lib/module/web-core/custom/signalsmithStretch/SignalsmithStretch.mjs +2 -2
  45. package/lib/module/web-core/custom/signalsmithStretch/SignalsmithStretch.mjs.map +1 -1
  46. package/lib/typescript/api.d.ts +1 -1
  47. package/lib/typescript/api.d.ts.map +1 -1
  48. package/lib/typescript/api.web.d.ts +1 -2
  49. package/lib/typescript/api.web.d.ts.map +1 -1
  50. package/lib/typescript/core/AnalyserNode.d.ts +4 -4
  51. package/lib/typescript/core/AnalyserNode.d.ts.map +1 -1
  52. package/lib/typescript/core/AudioBuffer.d.ts +3 -3
  53. package/lib/typescript/core/AudioBuffer.d.ts.map +1 -1
  54. package/lib/typescript/core/AudioBufferSourceNode.d.ts +0 -3
  55. package/lib/typescript/core/AudioBufferSourceNode.d.ts.map +1 -1
  56. package/lib/typescript/core/AudioParam.d.ts +1 -1
  57. package/lib/typescript/core/AudioParam.d.ts.map +1 -1
  58. package/lib/typescript/core/BaseAudioContext.d.ts +3 -3
  59. package/lib/typescript/core/BaseAudioContext.d.ts.map +1 -1
  60. package/lib/typescript/core/BiquadFilterNode.d.ts +1 -1
  61. package/lib/typescript/core/BiquadFilterNode.d.ts.map +1 -1
  62. package/lib/typescript/interfaces.d.ts +12 -13
  63. package/lib/typescript/interfaces.d.ts.map +1 -1
  64. package/lib/typescript/types.d.ts +3 -1
  65. package/lib/typescript/types.d.ts.map +1 -1
  66. package/lib/typescript/utils/index.d.ts +2 -0
  67. package/lib/typescript/utils/index.d.ts.map +1 -0
  68. package/lib/typescript/web-core/AnalyserNode.d.ts +4 -4
  69. package/lib/typescript/web-core/AnalyserNode.d.ts.map +1 -1
  70. package/lib/typescript/web-core/AudioBuffer.d.ts +2 -2
  71. package/lib/typescript/web-core/AudioBuffer.d.ts.map +1 -1
  72. package/lib/typescript/web-core/AudioBufferSourceNode.d.ts +58 -6
  73. package/lib/typescript/web-core/AudioBufferSourceNode.d.ts.map +1 -1
  74. package/lib/typescript/web-core/AudioContext.d.ts +3 -5
  75. package/lib/typescript/web-core/AudioContext.d.ts.map +1 -1
  76. package/lib/typescript/web-core/AudioParam.d.ts +1 -1
  77. package/lib/typescript/web-core/AudioParam.d.ts.map +1 -1
  78. package/lib/typescript/web-core/BaseAudioContext.d.ts +2 -2
  79. package/lib/typescript/web-core/BaseAudioContext.d.ts.map +1 -1
  80. package/lib/typescript/web-core/BiquadFilterNode.d.ts +1 -1
  81. package/lib/typescript/web-core/BiquadFilterNode.d.ts.map +1 -1
  82. package/package.json +6 -6
  83. package/src/api.ts +0 -1
  84. package/src/api.web.ts +0 -2
  85. package/src/core/AnalyserNode.ts +4 -4
  86. package/src/core/AudioBuffer.ts +3 -3
  87. package/src/core/AudioBufferSourceNode.ts +0 -9
  88. package/src/core/AudioParam.ts +1 -1
  89. package/src/core/BaseAudioContext.ts +16 -5
  90. package/src/core/BiquadFilterNode.ts +3 -3
  91. package/src/interfaces.ts +14 -16
  92. package/src/types.ts +3 -1
  93. package/src/utils/index.ts +3 -0
  94. package/src/web-core/AnalyserNode.tsx +8 -30
  95. package/src/web-core/AudioBuffer.tsx +4 -14
  96. package/src/web-core/AudioBufferSourceNode.tsx +357 -31
  97. package/src/web-core/AudioContext.tsx +19 -13
  98. package/src/web-core/AudioParam.tsx +2 -6
  99. package/src/web-core/BaseAudioContext.tsx +3 -3
  100. package/src/web-core/BiquadFilterNode.tsx +6 -16
  101. package/src/web-core/custom/signalsmithStretch/SignalsmithStretch.mjs +4 -3
  102. package/common/cpp/audioapi/core/types/TimeStretchType.h +0 -7
  103. package/lib/module/web-core/StretcherNode.js +0 -81
  104. package/lib/module/web-core/StretcherNode.js.map +0 -1
  105. package/lib/module/web-core/custom/signalsmithStretch/SignalsmithStretch.js +0 -823
  106. package/lib/module/web-core/custom/signalsmithStretch/SignalsmithStretch.js.map +0 -1
  107. package/lib/typescript/web-core/StretcherNode.d.ts +0 -48
  108. package/lib/typescript/web-core/StretcherNode.d.ts.map +0 -1
  109. package/src/web-core/StretcherNode.tsx +0 -145
  110. package/src/web-core/custom/signalsmithStretch/SignalsmithStretch.js +0 -946
@@ -1,26 +1,274 @@
1
- import AudioScheduledSourceNode from './AudioScheduledSourceNode';
1
+ import { InvalidStateError, RangeError } from '../errors';
2
+
2
3
  import AudioParam from './AudioParam';
3
4
  import AudioBuffer from './AudioBuffer';
4
- import { InvalidStateError, RangeError } from '../errors';
5
5
  import BaseAudioContext from './BaseAudioContext';
6
- import { TimeStretchType } from '../types';
6
+ import AudioScheduledSourceNode from './AudioScheduledSourceNode';
7
7
 
8
- export default class AudioBufferSourceNode extends AudioScheduledSourceNode {
9
- readonly playbackRate: AudioParam;
10
- readonly detune: AudioParam;
8
+ import { clamp } from '../utils';
9
+ import { globalTag } from './custom/LoadCustomWasm';
10
+
11
+ interface ScheduleOptions {
12
+ rate?: number;
13
+ active?: boolean;
14
+ output?: number;
15
+ input?: number;
16
+ semitones?: number;
17
+ loopStart?: number;
18
+ loopEnd?: number;
19
+ }
20
+
21
+ interface IStretcherNode extends globalThis.AudioNode {
22
+ channelCount: number;
23
+ channelCountMode: globalThis.ChannelCountMode;
24
+ channelInterpretation: globalThis.ChannelInterpretation;
25
+ context: globalThis.BaseAudioContext;
26
+ numberOfInputs: number;
27
+ numberOfOutputs: number;
28
+
29
+ onended:
30
+ | ((this: globalThis.AudioScheduledSourceNode, ev: Event) => unknown)
31
+ | null;
32
+ addEventListener: (
33
+ type: string,
34
+ listener: EventListenerOrEventListenerObject | null,
35
+ options?: boolean | AddEventListenerOptions | undefined
36
+ ) => void;
37
+ dispatchEvent: (event: Event) => boolean;
38
+ removeEventListener: (
39
+ type: string,
40
+ callback: EventListenerOrEventListenerObject | null,
41
+ options?: boolean | EventListenerOptions | undefined
42
+ ) => void;
43
+
44
+ addBuffers(channels: Float32Array[]): void;
45
+ dropBuffers(): void;
46
+
47
+ schedule(options: ScheduleOptions): void;
48
+
49
+ start(
50
+ when?: number,
51
+ offset?: number,
52
+ duration?: number,
53
+ rate?: number,
54
+ semitones?: number
55
+ ): void;
56
+
57
+ stop(when?: number): void;
58
+
59
+ connect(
60
+ destination: globalThis.AudioNode,
61
+ output?: number,
62
+ input?: number
63
+ ): globalThis.AudioNode;
64
+ connect(destination: globalThis.AudioParam, output?: number): void;
65
+
66
+ disconnect(): void;
67
+ disconnect(output: number): void;
68
+
69
+ disconnect(destination: globalThis.AudioNode): globalThis.AudioNode;
70
+ disconnect(destination: globalThis.AudioNode, output: number): void;
71
+ disconnect(
72
+ destination: globalThis.AudioNode,
73
+ output: number,
74
+ input: number
75
+ ): void;
76
+
77
+ disconnect(destination: globalThis.AudioParam): void;
78
+ disconnect(destination: globalThis.AudioParam, output: number): void;
79
+ }
80
+
81
+ class IStretcherNodeAudioParam implements globalThis.AudioParam {
82
+ private _value: number;
83
+ private _setter: (value: number, when?: number) => void;
84
+
85
+ public automationRate: AutomationRate;
86
+ public defaultValue: number;
87
+ public maxValue: number;
88
+ public minValue: number;
11
89
 
12
90
  constructor(
13
- context: BaseAudioContext,
14
- node: globalThis.AudioBufferSourceNode
91
+ value: number,
92
+ setter: (value: number, when?: number) => void,
93
+ automationRate: AutomationRate,
94
+ minValue: number,
95
+ maxValue: number,
96
+ defaultValue: number
15
97
  ) {
98
+ this._value = value;
99
+ this.automationRate = automationRate;
100
+ this.minValue = minValue;
101
+ this.maxValue = maxValue;
102
+ this.defaultValue = defaultValue;
103
+ this._setter = setter;
104
+ }
105
+
106
+ public get value(): number {
107
+ return this._value;
108
+ }
109
+
110
+ public set value(value: number) {
111
+ this._value = value;
112
+
113
+ this._setter(value);
114
+ }
115
+
116
+ cancelAndHoldAtTime(cancelTime: number): globalThis.AudioParam {
117
+ this._setter(this.defaultValue, cancelTime);
118
+ return this;
119
+ }
120
+
121
+ cancelScheduledValues(cancelTime: number): globalThis.AudioParam {
122
+ this._setter(this.defaultValue, cancelTime);
123
+ return this;
124
+ }
125
+
126
+ exponentialRampToValueAtTime(
127
+ _value: number,
128
+ _endTime: number
129
+ ): globalThis.AudioParam {
130
+ console.warn(
131
+ 'exponentialRampToValueAtTime is not implemented for pitch correction mode'
132
+ );
133
+ return this;
134
+ }
135
+
136
+ linearRampToValueAtTime(
137
+ _value: number,
138
+ _endTime: number
139
+ ): globalThis.AudioParam {
140
+ console.warn(
141
+ 'linearRampToValueAtTime is not implemented for pitch correction mode'
142
+ );
143
+ return this;
144
+ }
145
+
146
+ setTargetAtTime(
147
+ _target: number,
148
+ _startTime: number,
149
+ _timeConstant: number
150
+ ): globalThis.AudioParam {
151
+ console.warn(
152
+ 'setTargetAtTime is not implemented for pitch correction mode'
153
+ );
154
+ return this;
155
+ }
156
+
157
+ setValueAtTime(value: number, startTime: number): globalThis.AudioParam {
158
+ this._setter(value, startTime);
159
+ return this;
160
+ }
161
+
162
+ setValueCurveAtTime(
163
+ _values: Float32Array,
164
+ _startTime: number,
165
+ _duration: number
166
+ ): globalThis.AudioParam {
167
+ console.warn(
168
+ 'setValueCurveAtTime is not implemented for pitch correction mode'
169
+ );
170
+ return this;
171
+ }
172
+ }
173
+
174
+ type DefaultSource = globalThis.AudioBufferSourceNode;
175
+
176
+ type IAudioBufferSourceNode = DefaultSource | IStretcherNode;
177
+
178
+ declare global {
179
+ interface Window {
180
+ [globalTag]: (
181
+ audioContext: globalThis.BaseAudioContext
182
+ ) => Promise<IStretcherNode>;
183
+ }
184
+ }
185
+
186
+ export default class AudioBufferSourceNode<
187
+ T extends IAudioBufferSourceNode = DefaultSource,
188
+ > extends AudioScheduledSourceNode {
189
+ private _pitchCorrection: boolean;
190
+ readonly playbackRate: AudioParam;
191
+ readonly detune: AudioParam;
192
+
193
+ private _loop: boolean = false;
194
+ private _loopStart: number = -1;
195
+ private _loopEnd: number = -1;
196
+
197
+ private _buffer: AudioBuffer | null = null;
198
+
199
+ constructor(context: BaseAudioContext, node: T, pitchCorrection: boolean) {
16
200
  super(context, node);
17
201
 
18
- this.detune = new AudioParam(node.detune);
19
- this.playbackRate = new AudioParam(node.playbackRate);
202
+ this._pitchCorrection = pitchCorrection;
203
+
204
+ if (pitchCorrection) {
205
+ this.detune = new AudioParam(
206
+ new IStretcherNodeAudioParam(
207
+ 0,
208
+ this.setDetune.bind(this),
209
+ 'a-rate',
210
+ -1200,
211
+ 1200,
212
+ 0
213
+ )
214
+ );
215
+
216
+ this.playbackRate = new AudioParam(
217
+ new IStretcherNodeAudioParam(
218
+ 1,
219
+ this.setPlaybackRate.bind(this),
220
+ 'a-rate',
221
+ 0,
222
+ Infinity,
223
+ 1
224
+ )
225
+ );
226
+ } else {
227
+ this.detune = new AudioParam((node as DefaultSource).detune);
228
+ this.playbackRate = new AudioParam((node as DefaultSource).playbackRate);
229
+ }
230
+ }
231
+
232
+ private isStretcherNode() {
233
+ return this._pitchCorrection;
234
+ }
235
+
236
+ private asStretcher(): IStretcherNode {
237
+ return this.node as IStretcherNode;
238
+ }
239
+
240
+ private asBufferSource(): DefaultSource {
241
+ return this.node as DefaultSource;
242
+ }
243
+
244
+ public setDetune(value: number, when: number = 0): void {
245
+ if (!this.isStretcherNode() || !this.hasBeenStarted) {
246
+ return;
247
+ }
248
+
249
+ this.asStretcher().schedule({
250
+ semitones: Math.floor(clamp(value / 100, -12, 12)),
251
+ output: when,
252
+ });
253
+ }
254
+
255
+ public setPlaybackRate(value: number, when: number = 0): void {
256
+ if (!this.isStretcherNode() || !this.hasBeenStarted) {
257
+ return;
258
+ }
259
+
260
+ this.asStretcher().schedule({
261
+ rate: value,
262
+ output: when,
263
+ });
20
264
  }
21
265
 
22
266
  public get buffer(): AudioBuffer | null {
23
- const buffer = (this.node as globalThis.AudioBufferSourceNode).buffer;
267
+ if (this.isStretcherNode()) {
268
+ return this._buffer;
269
+ }
270
+
271
+ const buffer = this.asBufferSource().buffer;
24
272
 
25
273
  if (!buffer) {
26
274
  return null;
@@ -30,46 +278,83 @@ export default class AudioBufferSourceNode extends AudioScheduledSourceNode {
30
278
  }
31
279
 
32
280
  public set buffer(buffer: AudioBuffer | null) {
281
+ if (this.isStretcherNode()) {
282
+ this._buffer = buffer;
283
+
284
+ const stretcher = this.asStretcher();
285
+ stretcher.dropBuffers();
286
+
287
+ if (!buffer) {
288
+ return;
289
+ }
290
+
291
+ const channelArrays: Float32Array[] = [];
292
+
293
+ for (let i = 0; i < buffer.numberOfChannels; i++) {
294
+ channelArrays.push(buffer.getChannelData(i));
295
+ }
296
+
297
+ stretcher.addBuffers(channelArrays);
298
+ return;
299
+ }
300
+
33
301
  if (!buffer) {
34
- (this.node as globalThis.AudioBufferSourceNode | null) = null;
302
+ this.asBufferSource().buffer = null;
35
303
  return;
36
304
  }
37
305
 
38
- (this.node as globalThis.AudioBufferSourceNode).buffer = buffer.buffer;
306
+ this.asBufferSource().buffer = buffer.buffer;
39
307
  }
40
308
 
41
309
  public get loop(): boolean {
42
- return (this.node as globalThis.AudioBufferSourceNode).loop;
310
+ if (this.isStretcherNode()) {
311
+ return this._loop;
312
+ }
313
+
314
+ return this.asBufferSource().loop;
43
315
  }
44
316
 
45
317
  public set loop(value: boolean) {
46
- (this.node as globalThis.AudioBufferSourceNode).loop = value;
318
+ if (this.isStretcherNode()) {
319
+ this._loop = value;
320
+ return;
321
+ }
322
+
323
+ this.asBufferSource().loop = value;
47
324
  }
48
325
 
49
326
  public get loopStart(): number {
50
- return (this.node as globalThis.AudioBufferSourceNode).loopStart;
327
+ if (this.isStretcherNode()) {
328
+ return this._loopStart;
329
+ }
330
+
331
+ return this.asBufferSource().loopStart;
51
332
  }
52
333
 
53
334
  public set loopStart(value: number) {
54
- (this.node as globalThis.AudioBufferSourceNode).loopStart = value;
335
+ if (this.isStretcherNode()) {
336
+ this._loopStart = value;
337
+ return;
338
+ }
339
+
340
+ this.asBufferSource().loopStart = value;
55
341
  }
56
342
 
57
343
  public get loopEnd(): number {
58
- return (this.node as globalThis.AudioBufferSourceNode).loopEnd;
59
- }
344
+ if (this.isStretcherNode()) {
345
+ return this._loopEnd;
346
+ }
60
347
 
61
- public set loopEnd(value: number) {
62
- (this.node as globalThis.AudioBufferSourceNode).loopEnd = value;
348
+ return this.asBufferSource().loopEnd;
63
349
  }
64
350
 
65
- public get timeStretch(): TimeStretchType {
66
- return 'linear';
67
- }
351
+ public set loopEnd(value: number) {
352
+ if (this.isStretcherNode()) {
353
+ this._loopEnd = value;
354
+ return;
355
+ }
68
356
 
69
- public set timeStretch(value: TimeStretchType) {
70
- console.log(
71
- 'React Native Audio API: setting timeStretch is not supported on web'
72
- );
357
+ this.asBufferSource().loopEnd = value;
73
358
  }
74
359
 
75
360
  public start(when?: number, offset?: number, duration?: number): void {
@@ -96,10 +381,51 @@ export default class AudioBufferSourceNode extends AudioScheduledSourceNode {
96
381
  }
97
382
 
98
383
  this.hasBeenStarted = true;
99
- (this.node as globalThis.AudioBufferSourceNode).start(
100
- when,
384
+
385
+ if (!this.isStretcherNode()) {
386
+ this.asBufferSource().start(when, offset, duration);
387
+ return;
388
+ }
389
+
390
+ const startAt =
391
+ !when || when < this.context.currentTime
392
+ ? this.context.currentTime
393
+ : when;
394
+
395
+ if (this.loop && this._loopStart !== -1 && this._loopEnd !== -1) {
396
+ this.asStretcher().schedule({
397
+ loopStart: this._loopStart,
398
+ loopEnd: this._loopEnd,
399
+ });
400
+ }
401
+
402
+ this.asStretcher().start(
403
+ startAt,
101
404
  offset,
102
- duration
405
+ duration,
406
+ this.playbackRate.value,
407
+ Math.floor(clamp(this.detune.value / 100, -12, 12))
103
408
  );
104
409
  }
410
+
411
+ public stop(when: number = 0): void {
412
+ if (when < 0) {
413
+ throw new RangeError(
414
+ `when must be a finite non-negative number: ${when}`
415
+ );
416
+ }
417
+
418
+ if (!this.hasBeenStarted) {
419
+ throw new InvalidStateError(
420
+ 'Cannot call stop without calling start first'
421
+ );
422
+ }
423
+
424
+ if (!this.isStretcherNode()) {
425
+ this.asBufferSource().stop(when);
426
+ return;
427
+ }
428
+
429
+ this.asStretcher().stop(when);
430
+ }
105
431
  }
@@ -2,6 +2,7 @@ import {
2
2
  ContextState,
3
3
  PeriodicWaveConstraints,
4
4
  AudioContextOptions,
5
+ AudioBufferSourceNodeOptions,
5
6
  } from '../types';
6
7
  import { InvalidAccessError, NotSupportedError } from '../errors';
7
8
  import BaseAudioContext from './BaseAudioContext';
@@ -14,7 +15,6 @@ import GainNode from './GainNode';
14
15
  import OscillatorNode from './OscillatorNode';
15
16
  import PeriodicWave from './PeriodicWave';
16
17
  import StereoPannerNode from './StereoPannerNode';
17
- import StretcherNode from './StretcherNode';
18
18
 
19
19
  import { globalWasmPromise, globalTag } from './custom/LoadCustomWasm';
20
20
 
@@ -61,8 +61,22 @@ export default class AudioContext implements BaseAudioContext {
61
61
  return new BiquadFilterNode(this, this.context.createBiquadFilter());
62
62
  }
63
63
 
64
- createBufferSource(): AudioBufferSourceNode {
65
- return new AudioBufferSourceNode(this, this.context.createBufferSource());
64
+ async createBufferSource(
65
+ options?: AudioBufferSourceNodeOptions
66
+ ): Promise<AudioBufferSourceNode> {
67
+ if (!options || !options.pitchCorrection) {
68
+ return new AudioBufferSourceNode(
69
+ this,
70
+ this.context.createBufferSource(),
71
+ false
72
+ );
73
+ }
74
+
75
+ await globalWasmPromise;
76
+
77
+ const wasmStretch = await window[globalTag](this.context);
78
+
79
+ return new AudioBufferSourceNode(this, wasmStretch, true);
66
80
  }
67
81
 
68
82
  createBuffer(
@@ -94,8 +108,8 @@ export default class AudioContext implements BaseAudioContext {
94
108
  }
95
109
 
96
110
  createPeriodicWave(
97
- real: number[],
98
- imag: number[],
111
+ real: Float32Array,
112
+ imag: Float32Array,
99
113
  constraints?: PeriodicWaveConstraints
100
114
  ): PeriodicWave {
101
115
  if (real.length !== imag.length) {
@@ -113,14 +127,6 @@ export default class AudioContext implements BaseAudioContext {
113
127
  return new AnalyserNode(this, this.context.createAnalyser());
114
128
  }
115
129
 
116
- async createStretcher(): Promise<StretcherNode> {
117
- await globalWasmPromise;
118
-
119
- const wasmStretch = await window[globalTag](this.context);
120
-
121
- return new StretcherNode(this, wasmStretch);
122
- }
123
-
124
130
  async decodeAudioDataSource(source: string): Promise<AudioBuffer> {
125
131
  const arrayBuffer = await fetch(source).then((response) =>
126
132
  response.arrayBuffer()
@@ -84,7 +84,7 @@ export default class AudioParam {
84
84
  }
85
85
 
86
86
  public setValueCurveAtTime(
87
- values: number[],
87
+ values: Float32Array,
88
88
  startTime: number,
89
89
  duration: number
90
90
  ): AudioParam {
@@ -104,11 +104,7 @@ export default class AudioParam {
104
104
  throw new InvalidStateError(`values must contain at least two values`);
105
105
  }
106
106
 
107
- this.param.setValueCurveAtTime(
108
- new Float32Array(values),
109
- startTime,
110
- duration
111
- );
107
+ this.param.setValueCurveAtTime(values, startTime, duration);
112
108
 
113
109
  return this;
114
110
  }
@@ -21,15 +21,15 @@ export default interface BaseAudioContext {
21
21
  createGain(): GainNode;
22
22
  createStereoPanner(): StereoPannerNode;
23
23
  createBiquadFilter(): BiquadFilterNode;
24
- createBufferSource(): AudioBufferSourceNode;
24
+ createBufferSource(): Promise<AudioBufferSourceNode>;
25
25
  createBuffer(
26
26
  numOfChannels: number,
27
27
  length: number,
28
28
  sampleRate: number
29
29
  ): AudioBuffer;
30
30
  createPeriodicWave(
31
- real: number[],
32
- imag: number[],
31
+ real: Float32Array,
32
+ imag: Float32Array,
33
33
  constraints?: PeriodicWaveConstraints
34
34
  ): PeriodicWave;
35
35
  createAnalyser(): AnalyserNode;
@@ -30,9 +30,9 @@ export default class BiquadFilterNode extends AudioNode {
30
30
  }
31
31
 
32
32
  public getFrequencyResponse(
33
- frequencyArray: number[],
34
- magResponseOutput: number[],
35
- phaseResponseOutput: number[]
33
+ frequencyArray: Float32Array,
34
+ magResponseOutput: Float32Array,
35
+ phaseResponseOutput: Float32Array
36
36
  ) {
37
37
  if (
38
38
  frequencyArray.length !== magResponseOutput.length ||
@@ -42,21 +42,11 @@ export default class BiquadFilterNode extends AudioNode {
42
42
  `The lengths of the arrays are not the same frequencyArray: ${frequencyArray.length}, magResponseOutput: ${magResponseOutput.length}, phaseResponseOutput: ${phaseResponseOutput.length}`
43
43
  );
44
44
  }
45
- const magData = new Float32Array(magResponseOutput);
46
- const phaseData = new Float32Array(phaseResponseOutput);
47
45
 
48
46
  (this.node as globalThis.BiquadFilterNode).getFrequencyResponse(
49
- new Float32Array(frequencyArray),
50
- magData,
51
- phaseData
47
+ frequencyArray,
48
+ magResponseOutput,
49
+ phaseResponseOutput
52
50
  );
53
-
54
- for (let i = 0; i < magData.length; i++) {
55
- magResponseOutput[i] = magData[i];
56
- }
57
-
58
- for (let i = 0; i < phaseData.length; i++) {
59
- phaseResponseOutput[i] = phaseData[i];
60
- }
61
51
  }
62
52
  }
@@ -510,8 +510,7 @@ function registerWorkletProcessor(Module, audioNodeKey) {
510
510
  return result;
511
511
  },
512
512
  schedule: (objIn, adjustPrevious) => {
513
- let outputTime =
514
- 'outputTime' in objIn ? objIn.outputTime : currentTime;
513
+ let outputTime = 'output' in objIn ? objIn.output : currentTime;
515
514
 
516
515
  let latestSegment = this.timeMap[this.timeMap.length - 1];
517
516
  while (
@@ -524,13 +523,15 @@ function registerWorkletProcessor(Module, audioNodeKey) {
524
523
  let obj = {
525
524
  active: latestSegment.active,
526
525
  input: null,
527
- output: outputTime,
528
526
  rate: latestSegment.rate,
529
527
  semitones: latestSegment.semitones,
530
528
  loopStart: latestSegment.loopStart,
531
529
  loopEnd: latestSegment.loopEnd,
532
530
  };
531
+
533
532
  Object.assign(obj, objIn);
533
+ obj.output = outputTime;
534
+
534
535
  if (obj.input === null) {
535
536
  let rate = latestSegment.active ? latestSegment.rate : 0;
536
537
  obj.input =
@@ -1,7 +0,0 @@
1
- #pragma once
2
-
3
- namespace audioapi {
4
-
5
- enum class TimeStretchType { LINEAR, SPEECH_MUSIC };
6
-
7
- }
@@ -1,81 +0,0 @@
1
- "use strict";
2
-
3
- import AudioNode from "./AudioNode.js";
4
- import { globalTag } from "./custom/LoadCustomWasm.js";
5
- export default class StretcherNode extends AudioNode {
6
- _buffer = null;
7
- _playbackRate = 1;
8
- _loopStart = -1;
9
- _loopEnd = -1;
10
- _loop = false;
11
- _isPlaying = false;
12
- constructor(context, node) {
13
- super(context, node);
14
- this._buffer = null;
15
- }
16
- get buffer() {
17
- return this._buffer;
18
- }
19
- set buffer(buffer) {
20
- this._buffer = buffer;
21
- const channelArrays = [];
22
- for (let i = 0; i < buffer.numberOfChannels; i += 1) {
23
- channelArrays.push(buffer.getChannelData(i));
24
- }
25
- this.node.addBuffers(channelArrays);
26
- }
27
- get playbackRate() {
28
- return this._playbackRate;
29
- }
30
- set playbackRate(value) {
31
- this._playbackRate = value;
32
- if (this._isPlaying) {
33
- this.node.schedule({
34
- rate: value
35
- });
36
- }
37
- }
38
- get loopStart() {
39
- return this._loopStart;
40
- }
41
- set loopStart(value) {
42
- this._loopStart = value;
43
- if (this._isPlaying) {
44
- this.node.schedule({
45
- loopStart: value
46
- });
47
- }
48
- }
49
- get loopEnd() {
50
- return this._loopEnd;
51
- }
52
- set loopEnd(value) {
53
- this._loopEnd = value;
54
- if (this._isPlaying) {
55
- this.node.schedule({
56
- loopEnd: value
57
- });
58
- }
59
- }
60
- get loop() {
61
- return this._loop;
62
- }
63
- set loop(value) {
64
- this._loop = value;
65
- }
66
- start(when, offset, duration, rate, semitones) {
67
- this._isPlaying = true;
68
- if (this.loop && this._loopStart !== -1 && this._loopEnd !== -1) {
69
- this.node.schedule({
70
- loopStart: this._loopStart,
71
- loopEnd: this._loopEnd
72
- });
73
- }
74
- this.node.start(when ?? 0, offset ?? 0, duration ?? this._buffer?.duration ?? 0, rate ?? this._playbackRate ?? 0, semitones ?? 0);
75
- }
76
- stop(when) {
77
- this._isPlaying = false;
78
- this.node.stop(when);
79
- }
80
- }
81
- //# sourceMappingURL=StretcherNode.js.map