timed-audio-buffer-source-node-audio-worklet 1.0.16 → 2.0.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.
- package/build/es2019/factories/convert-to-context-frame.d.ts +4 -0
- package/build/es2019/factories/convert-to-context-frame.d.ts.map +1 -0
- package/build/es2019/factories/convert-to-context-frame.js +7 -0
- package/build/es2019/factories/convert-to-context-frame.js.map +1 -0
- package/build/es2019/factories/performance.d.ts +2 -0
- package/build/es2019/factories/performance.d.ts.map +1 -0
- package/build/es2019/factories/performance.js +2 -0
- package/build/es2019/factories/performance.js.map +1 -0
- package/build/es2019/factories/schedule-audio-buffer-source-node.d.ts +5 -0
- package/build/es2019/factories/schedule-audio-buffer-source-node.d.ts.map +1 -0
- package/build/es2019/factories/schedule-audio-buffer-source-node.js +12 -0
- package/build/es2019/factories/schedule-audio-buffer-source-node.js.map +1 -0
- package/build/es2019/factories/subscribe-to-timing-object.d.ts +5 -0
- package/build/es2019/factories/subscribe-to-timing-object.d.ts.map +1 -0
- package/build/es2019/factories/subscribe-to-timing-object.js +27 -0
- package/build/es2019/factories/subscribe-to-timing-object.js.map +1 -0
- package/build/es2019/interfaces/timed-audio-buffer-source-node-audio-worklet-node.d.ts +2 -0
- package/build/es2019/interfaces/timed-audio-buffer-source-node-audio-worklet-node.d.ts.map +1 -1
- package/build/es2019/module.d.ts +2 -2
- package/build/es2019/module.d.ts.map +1 -1
- package/build/es2019/module.js +32 -7
- package/build/es2019/module.js.map +1 -1
- package/build/es2019/types/native-timed-audio-buffer-source-node-audio-worklet-node.d.ts +4 -1
- package/build/es2019/types/native-timed-audio-buffer-source-node-audio-worklet-node.d.ts.map +1 -1
- package/build/es2019/worklet/worklet.d.ts +1 -1
- package/build/es2019/worklet/worklet.d.ts.map +1 -1
- package/build/es2019/worklet/worklet.js +1 -1
- package/build/es2019/worklet/worklet.js.map +1 -1
- package/build/es5/bundle.js +105 -17
- package/package.json +15 -15
- package/src/factories/convert-to-context-frame.ts +11 -0
- package/src/factories/performance.ts +2 -0
- package/src/factories/schedule-audio-buffer-source-node.ts +36 -0
- package/src/factories/subscribe-to-timing-object.ts +49 -0
- package/src/interfaces/timed-audio-buffer-source-node-audio-worklet-node.ts +4 -1
- package/src/module.ts +43 -6
- package/src/types/native-timed-audio-buffer-source-node-audio-worklet-node.ts +4 -1
- package/src/worklet/worklet.ts +1 -1
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { TContext, TNativeContext } from 'standardized-audio-context';
|
|
2
|
+
import type { createPerformance } from './performance';
|
|
3
|
+
export declare const createConvertToContextFrame: (performance: ReturnType<typeof createPerformance>) => (context: TContext | TNativeContext, timestamp: number) => number;
|
|
4
|
+
//# sourceMappingURL=convert-to-context-frame.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convert-to-context-frame.d.ts","sourceRoot":"","sources":["../../../src/factories/convert-to-context-frame.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEvD,eAAO,MAAM,2BAA2B,gBACtB,WAAW,wBAAwB,CAAC,eAAe,QAAQ,GAAG,cAAc,aAAa,MAAM,WAM5G,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export const createConvertToContextFrame = (performance) => (context, timestamp) => {
|
|
2
|
+
if (performance === null) {
|
|
3
|
+
throw new Error('Performance is not available.');
|
|
4
|
+
}
|
|
5
|
+
return Math.round((context.currentTime - performance.now() / 1000 + timestamp) * context.sampleRate);
|
|
6
|
+
};
|
|
7
|
+
//# sourceMappingURL=convert-to-context-frame.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convert-to-context-frame.js","sourceRoot":"","sources":["../../../src/factories/convert-to-context-frame.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,2BAA2B,GACpC,CAAC,WAAiD,EAAE,EAAE,CAAC,CAAC,OAAkC,EAAE,SAAiB,EAAE,EAAE;IAC7G,IAAI,WAAW,KAAK,IAAI,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACrD,CAAC;IAED,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,WAAW,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AACzG,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"performance.d.ts","sourceRoot":"","sources":["../../../src/factories/performance.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,0BACkF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"performance.js","sourceRoot":"","sources":["../../../src/factories/performance.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,EAAE,CAClC,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,MAAM,CAAC,WAAW,KAAK,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { IAudioBufferSourceNode, IAudioWorkletNode, TContext, TNativeAudioBufferSourceNode, TNativeAudioWorkletNode, TNativeContext } from 'standardized-audio-context';
|
|
2
|
+
import { ITimingObject } from 'timing-object';
|
|
3
|
+
import type { createConvertToContextFrame } from './convert-to-context-frame';
|
|
4
|
+
export declare const createScheduleAudioBufferSourceNode: (convertToContextFrame: ReturnType<typeof createConvertToContextFrame>) => <T extends TContext | TNativeContext>(audioWorkletNode: T extends TContext ? IAudioWorkletNode<T> : AudioWorkletNode, context: T, createAudioBufferSourceNode: T extends TContext ? (context: TContext) => IAudioBufferSourceNode<TContext> : (context: TNativeContext) => TNativeAudioBufferSourceNode, timingObject: ITimingObject) => Promise<void>;
|
|
5
|
+
//# sourceMappingURL=schedule-audio-buffer-source-node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schedule-audio-buffer-source-node.d.ts","sourceRoot":"","sources":["../../../src/factories/schedule-audio-buffer-source-node.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,sBAAsB,EACtB,iBAAiB,EACjB,QAAQ,EACR,4BAA4B,EAC5B,uBAAuB,EACvB,cAAc,EACjB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AAE9E,eAAO,MAAM,mCAAmC,0BACpB,WAAW,kCAAkC,CAAC,mMAKlD,QAAQ,KAAK,uBAAuB,QAAQ,CAAC,aAC7C,cAAc,KAAK,4BAA4B,gBACjD,aAAa,KAC5B,QAAQ,IAAI,CAed,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const createScheduleAudioBufferSourceNode = (convertToContextFrame) => (audioWorkletNode, context, createAudioBufferSourceNode, timingObject) => {
|
|
2
|
+
const audioBuffer = new AudioBuffer({ length: 2, sampleRate: context.sampleRate });
|
|
3
|
+
const audioBufferSourceNode = createAudioBufferSourceNode(context);
|
|
4
|
+
const { position, timestamp } = timingObject.query();
|
|
5
|
+
audioBuffer.copyToChannel(new Float32Array([position, convertToContextFrame(context, timestamp)]), 0);
|
|
6
|
+
audioBufferSourceNode.buffer = audioBuffer;
|
|
7
|
+
const promise = new Promise((resolve) => audioBufferSourceNode.addEventListener('ended', () => resolve(), { once: true }));
|
|
8
|
+
audioBufferSourceNode.connect(audioWorkletNode);
|
|
9
|
+
audioBufferSourceNode.start();
|
|
10
|
+
return promise;
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=schedule-audio-buffer-source-node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schedule-audio-buffer-source-node.js","sourceRoot":"","sources":["../../../src/factories/schedule-audio-buffer-source-node.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,mCAAmC,GAC5C,CAAC,qBAAqE,EAAE,EAAE,CAC1E,CACI,gBAAqF,EACrF,OAAU,EACV,2BAE+D,EAC/D,YAA2B,EACd,EAAE;IACf,MAAM,WAAW,GAAG,IAAI,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;IACnF,MAAM,qBAAqB,GAAG,2BAA2B,CAAM,OAAO,CAAC,CAAC;IACxE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC;IAErD,WAAW,CAAC,aAAa,CAAC,IAAI,YAAY,CAAC,CAAC,QAAQ,EAAE,qBAAqB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAEtG,qBAAqB,CAAC,MAAM,GAAG,WAAW,CAAC;IAE3C,MAAM,OAAO,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC,qBAAqB,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAEjI,qBAAqB,CAAC,OAAO,CAAM,gBAAgB,CAAC,CAAC;IACrD,qBAAqB,CAAC,KAAK,EAAE,CAAC;IAE9B,OAAO,OAAO,CAAC;AACnB,CAAC,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { IAudioBufferSourceNode, IAudioWorkletNode, TContext, TNativeAudioBufferSourceNode, TNativeAudioWorkletNode, TNativeContext } from 'standardized-audio-context';
|
|
2
|
+
import { ITimingObject } from 'timing-object';
|
|
3
|
+
import type { createScheduleAudioBufferSourceNode } from './schedule-audio-buffer-source-node';
|
|
4
|
+
export declare const createSubscribeToTimingObject: (scheduleAudioBufferSourceNode: ReturnType<typeof createScheduleAudioBufferSourceNode>) => <T extends TContext | TNativeContext>(audioWorkletNode: T extends TContext ? IAudioWorkletNode<T> : AudioWorkletNode, context: T, createAudioBufferSourceNode: T extends TContext ? (context: TContext) => IAudioBufferSourceNode<TContext> : (context: TNativeContext) => TNativeAudioBufferSourceNode, timingObject: ITimingObject) => () => void;
|
|
5
|
+
//# sourceMappingURL=subscribe-to-timing-object.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscribe-to-timing-object.d.ts","sourceRoot":"","sources":["../../../src/factories/subscribe-to-timing-object.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,sBAAsB,EACtB,iBAAiB,EACjB,QAAQ,EACR,4BAA4B,EAC5B,uBAAuB,EACvB,cAAc,EACjB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,mCAAmC,EAAE,MAAM,qCAAqC,CAAC;AAE/F,eAAO,MAAM,6BAA6B,kCACN,WAAW,0CAA0C,CAAC,mMAKlE,QAAQ,KAAK,uBAAuB,QAAQ,CAAC,aAC7C,cAAc,KAAK,4BAA4B,gBACjD,aAAa,eA6B9B,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const createSubscribeToTimingObject = (scheduleAudioBufferSourceNode) => (audioWorkletNode, context, createAudioBufferSourceNode, timingObject) => {
|
|
2
|
+
let hasPendingUpdate = false;
|
|
3
|
+
let isSendingUpdate = false;
|
|
4
|
+
const scheduleUpdate = () => {
|
|
5
|
+
hasPendingUpdate = false;
|
|
6
|
+
scheduleAudioBufferSourceNode(audioWorkletNode, context, createAudioBufferSourceNode, timingObject).then(() => {
|
|
7
|
+
if (hasPendingUpdate) {
|
|
8
|
+
scheduleUpdate();
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
isSendingUpdate = false;
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
const listener = () => {
|
|
16
|
+
if (isSendingUpdate) {
|
|
17
|
+
hasPendingUpdate = true;
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
isSendingUpdate = true;
|
|
21
|
+
scheduleUpdate();
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
timingObject.addEventListener('change', listener);
|
|
25
|
+
return () => timingObject.removeEventListener('change', listener);
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=subscribe-to-timing-object.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscribe-to-timing-object.js","sourceRoot":"","sources":["../../../src/factories/subscribe-to-timing-object.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,6BAA6B,GACtC,CAAC,6BAAqF,EAAE,EAAE,CAC1F,CACI,gBAAqF,EACrF,OAAU,EACV,2BAE+D,EAC/D,YAA2B,EAC7B,EAAE;IACA,IAAI,gBAAgB,GAAG,KAAK,CAAC;IAC7B,IAAI,eAAe,GAAG,KAAK,CAAC;IAE5B,MAAM,cAAc,GAAG,GAAG,EAAE;QACxB,gBAAgB,GAAG,KAAK,CAAC;QAEzB,6BAA6B,CAAC,gBAAgB,EAAE,OAAO,EAAE,2BAA2B,EAAE,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;YAC1G,IAAI,gBAAgB,EAAE,CAAC;gBACnB,cAAc,EAAE,CAAC;YACrB,CAAC;iBAAM,CAAC;gBACJ,eAAe,GAAG,KAAK,CAAC;YAC5B,CAAC;QACL,CAAC,CAAC,CAAC;IACP,CAAC,CAAC;IACF,MAAM,QAAQ,GAAG,GAAG,EAAE;QAClB,IAAI,eAAe,EAAE,CAAC;YAClB,gBAAgB,GAAG,IAAI,CAAC;QAC5B,CAAC;aAAM,CAAC;YACJ,eAAe,GAAG,IAAI,CAAC;YAEvB,cAAc,EAAE,CAAC;QACrB,CAAC;IACL,CAAC,CAAC;IAEF,YAAY,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAElD,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AACtE,CAAC,CAAC"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { IAudioWorkletNode, TContext } from 'standardized-audio-context';
|
|
2
|
+
import { ITimingObject } from 'timing-object';
|
|
2
3
|
export interface ITimedAudioBufferSourceNodeAudioWorkletNode<T extends TContext> extends IAudioWorkletNode<T> {
|
|
4
|
+
timingObject: null | ITimingObject;
|
|
3
5
|
}
|
|
4
6
|
//# sourceMappingURL=timed-audio-buffer-source-node-audio-worklet-node.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timed-audio-buffer-source-node-audio-worklet-node.d.ts","sourceRoot":"","sources":["../../../src/interfaces/timed-audio-buffer-source-node-audio-worklet-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"timed-audio-buffer-source-node-audio-worklet-node.d.ts","sourceRoot":"","sources":["../../../src/interfaces/timed-audio-buffer-source-node-audio-worklet-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,WAAW,2CAA2C,CAAC,CAAC,SAAS,QAAQ,CAAE,SAAQ,iBAAiB,CAAC,CAAC,CAAC;IACzG,YAAY,EAAE,IAAI,GAAG,aAAa,CAAC;CACtC"}
|
package/build/es2019/module.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { TAudioWorkletNodeConstructor, TContext, TNativeAudioWorkletNodeConstructor, TNativeContext } from 'standardized-audio-context';
|
|
1
|
+
import { IAudioBufferSourceNode, TAudioWorkletNodeConstructor, TContext, TNativeAudioBufferSourceNode, TNativeAudioWorkletNodeConstructor, TNativeContext } from 'standardized-audio-context';
|
|
2
2
|
import { ITimedAudioBufferSourceNodeAudioWorkletNode } from './interfaces';
|
|
3
3
|
import { TAnyTimedAudioBufferSourceNodeAudioWorkletNodeOptions, TNativeTimedAudioBufferSourceNodeAudioWorkletNode } from './types';
|
|
4
4
|
export * from './interfaces/index';
|
|
5
5
|
export * from './types/index';
|
|
6
6
|
export declare const addTimedAudioBufferSourceNodeAudioWorkletModule: (addAudioWorkletModule: (url: string) => Promise<void>) => Promise<void>;
|
|
7
|
-
export declare function createTimedAudioBufferSourceNodeAudioWorkletNode<T extends TContext | TNativeContext>(audioWorkletNodeConstructor: T extends TContext ? TAudioWorkletNodeConstructor : TNativeAudioWorkletNodeConstructor, context: T, options?: Partial<TAnyTimedAudioBufferSourceNodeAudioWorkletNodeOptions<T>>): T extends TContext ? ITimedAudioBufferSourceNodeAudioWorkletNode<T> : TNativeTimedAudioBufferSourceNodeAudioWorkletNode;
|
|
7
|
+
export declare function createTimedAudioBufferSourceNodeAudioWorkletNode<T extends TContext | TNativeContext>(audioWorkletNodeConstructor: T extends TContext ? TAudioWorkletNodeConstructor : TNativeAudioWorkletNodeConstructor, context: T, createAudioBufferSourceNode: T extends TContext ? (context: TContext) => IAudioBufferSourceNode<TContext> : (context: TNativeContext) => TNativeAudioBufferSourceNode, options?: Partial<TAnyTimedAudioBufferSourceNodeAudioWorkletNodeOptions<T>>): T extends TContext ? ITimedAudioBufferSourceNodeAudioWorkletNode<T> : TNativeTimedAudioBufferSourceNodeAudioWorkletNode;
|
|
8
8
|
//# sourceMappingURL=module.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../src/module.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../src/module.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,sBAAsB,EAEtB,4BAA4B,EAC5B,QAAQ,EACR,4BAA4B,EAE5B,kCAAkC,EAClC,cAAc,EACjB,MAAM,4BAA4B,CAAC;AAKpC,OAAO,EAAE,2CAA2C,EAAE,MAAM,cAAc,CAAC;AAC3E,OAAO,EAAE,qDAAqD,EAAE,iDAAiD,EAAE,MAAM,SAAS,CAAC;AAOnI,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAI9B,eAAO,MAAM,+CAA+C,gCAAuC,MAAM,KAAK,QAAQ,IAAI,CAAC,kBAQ1H,CAAC;AAKF,wBAAgB,gDAAgD,CAAC,CAAC,SAAS,QAAQ,GAAG,cAAc,EAChG,2BAA2B,EAAE,CAAC,SAAS,QAAQ,GAAG,4BAA4B,GAAG,kCAAkC,EACnH,OAAO,EAAE,CAAC,EACV,2BAA2B,EAAE,CAAC,SAAS,QAAQ,GACzC,CAAC,OAAO,EAAE,QAAQ,KAAK,sBAAsB,CAAC,QAAQ,CAAC,GACvD,CAAC,OAAO,EAAE,cAAc,KAAK,4BAA4B,EAC/D,OAAO,GAAE,OAAO,CAAC,qDAAqD,CAAC,CAAC,CAAC,CAAM,GAChF,CAAC,SAAS,QAAQ,GAAG,2CAA2C,CAAC,CAAC,CAAC,GAAG,iDAAiD,CA8DzH"}
|
package/build/es2019/module.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createConvertToContextFrame } from './factories/convert-to-context-frame';
|
|
2
|
+
import { createPerformance } from './factories/performance';
|
|
3
|
+
import { createScheduleAudioBufferSourceNode } from './factories/schedule-audio-buffer-source-node';
|
|
4
|
+
import { createSubscribeToTimingObject } from './factories/subscribe-to-timing-object';
|
|
2
5
|
import { worklet } from './worklet/worklet';
|
|
3
6
|
/*
|
|
4
7
|
* @todo Explicitly referencing the barrel file seems to be necessary when enabling the
|
|
@@ -16,30 +19,52 @@ export const addTimedAudioBufferSourceNodeAudioWorkletModule = async (addAudioWo
|
|
|
16
19
|
URL.revokeObjectURL(url);
|
|
17
20
|
}
|
|
18
21
|
};
|
|
19
|
-
|
|
22
|
+
const convertToContextFrame = createConvertToContextFrame(createPerformance());
|
|
23
|
+
const subscribeToTimingObject = createSubscribeToTimingObject(createScheduleAudioBufferSourceNode(convertToContextFrame));
|
|
24
|
+
export function createTimedAudioBufferSourceNodeAudioWorkletNode(audioWorkletNodeConstructor, context, createAudioBufferSourceNode, options = {}) {
|
|
20
25
|
var _a, _b;
|
|
21
|
-
const { buffer = null
|
|
26
|
+
const { buffer = null } = options;
|
|
27
|
+
if (buffer instanceof AudioBuffer && buffer.sampleRate !== context.sampleRate) {
|
|
28
|
+
throw new TypeError('The AudioBuffer must have the same sampleRate as the AudioContext.');
|
|
29
|
+
}
|
|
30
|
+
let { timingObject = null } = options;
|
|
22
31
|
const { position = 0, timestamp = 0 } = (_a = timingObject === null || timingObject === void 0 ? void 0 : timingObject.query()) !== null && _a !== void 0 ? _a : {};
|
|
23
32
|
const audioWorkletNode = new audioWorkletNodeConstructor(context, 'timed-audio-buffer-source-node-audio-worklet-processor', {
|
|
24
|
-
|
|
25
|
-
numberOfInputs: 0,
|
|
33
|
+
numberOfInputs: 1,
|
|
26
34
|
numberOfOutputs: 1,
|
|
27
35
|
outputChannelCount: [(_b = buffer === null || buffer === void 0 ? void 0 : buffer.numberOfChannels) !== null && _b !== void 0 ? _b : 1],
|
|
28
|
-
|
|
36
|
+
processorOptions: {
|
|
29
37
|
buffer: buffer instanceof AudioBuffer
|
|
30
38
|
? Array.from({ length: buffer.numberOfChannels }, (_, channel) => buffer.getChannelData(channel))
|
|
31
39
|
: null,
|
|
32
40
|
position,
|
|
33
|
-
timestamp
|
|
41
|
+
timestamp: convertToContextFrame(context, timestamp)
|
|
34
42
|
}
|
|
35
43
|
});
|
|
44
|
+
let removeListener = null;
|
|
36
45
|
Object.defineProperties(audioWorkletNode, {
|
|
37
46
|
port: {
|
|
38
47
|
get() {
|
|
39
48
|
throw new Error("The port of a TimedAudioBufferSourceNodeAudioWorkletNode can't be accessed.");
|
|
40
49
|
}
|
|
50
|
+
},
|
|
51
|
+
timingObject: {
|
|
52
|
+
get: () => timingObject,
|
|
53
|
+
set: (value) => {
|
|
54
|
+
removeListener === null || removeListener === void 0 ? void 0 : removeListener();
|
|
55
|
+
removeListener = null;
|
|
56
|
+
if (value === null) {
|
|
57
|
+
timingObject = value;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
throw new TypeError('A TimingObject can only be set in the constructor.');
|
|
61
|
+
}
|
|
62
|
+
}
|
|
41
63
|
}
|
|
42
64
|
});
|
|
65
|
+
if (timingObject !== null) {
|
|
66
|
+
removeListener = subscribeToTimingObject(audioWorkletNode, context, createAudioBufferSourceNode, timingObject);
|
|
67
|
+
}
|
|
43
68
|
return audioWorkletNode;
|
|
44
69
|
}
|
|
45
70
|
//# sourceMappingURL=module.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"module.js","sourceRoot":"","sources":["../../src/module.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"module.js","sourceRoot":"","sources":["../../src/module.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,2BAA2B,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,mCAAmC,EAAE,MAAM,+CAA+C,CAAC;AACpG,OAAO,EAAE,6BAA6B,EAAE,MAAM,wCAAwC,CAAC;AAGvF,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAE5C;;;GAGG;AACH,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAE9B,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,uCAAuC,EAAE,CAAC,CAAC;AAEpF,MAAM,CAAC,MAAM,+CAA+C,GAAG,KAAK,EAAE,qBAAqD,EAAE,EAAE;IAC3H,MAAM,GAAG,GAAG,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;IAEtC,IAAI,CAAC;QACD,MAAM,qBAAqB,CAAC,GAAG,CAAC,CAAC;IACrC,CAAC;YAAS,CAAC;QACP,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;AACL,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,2BAA2B,CAAC,iBAAiB,EAAE,CAAC,CAAC;AAC/E,MAAM,uBAAuB,GAAG,6BAA6B,CAAC,mCAAmC,CAAC,qBAAqB,CAAC,CAAC,CAAC;AAE1H,MAAM,UAAU,gDAAgD,CAC5D,2BAAmH,EACnH,OAAU,EACV,2BAE+D,EAC/D,UAA6E,EAAE;;IAO/E,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IAElC,IAAI,MAAM,YAAY,WAAW,IAAI,MAAM,CAAC,UAAU,KAAK,OAAO,CAAC,UAAU,EAAE,CAAC;QAC5E,MAAM,IAAI,SAAS,CAAC,oEAAoE,CAAC,CAAC;IAC9F,CAAC;IAED,IAAI,EAAE,YAAY,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IAEtC,MAAM,EAAE,QAAQ,GAAG,CAAC,EAAE,SAAS,GAAG,CAAC,EAAE,GAAG,MAAA,YAAY,aAAZ,YAAY,uBAAZ,YAAY,CAAE,KAAK,EAAE,mCAAI,EAAE,CAAC;IACpE,MAAM,gBAAgB,GAAyB,IAAU,2BAA4B,CACjF,OAAO,EACP,wDAAwD,EACxD;QACI,cAAc,EAAE,CAAC;QACjB,eAAe,EAAE,CAAC;QAClB,kBAAkB,EAAE,CAAC,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,gBAAgB,mCAAI,CAAC,CAAC;QACnD,gBAAgB,EAAE;YACd,MAAM,EACF,MAAM,YAAY,WAAW;gBACzB,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;gBACjG,CAAC,CAAC,IAAI;YACd,QAAQ;YACR,SAAS,EAAE,qBAAqB,CAAC,OAAO,EAAE,SAAS,CAAC;SACvD;KACJ,CACJ,CAAC;IAEF,IAAI,cAAc,GAAwB,IAAI,CAAC;IAE/C,MAAM,CAAC,gBAAgB,CAAC,gBAAgB,EAAE;QACtC,IAAI,EAAE;YACF,GAAG;gBACC,MAAM,IAAI,KAAK,CAAC,6EAA6E,CAAC,CAAC;YACnG,CAAC;SACJ;QACD,YAAY,EAAE;YACV,GAAG,EAAE,GAAG,EAAE,CAAC,YAAY;YACvB,GAAG,EAAE,CAAC,KAAqE,EAAE,EAAE;gBAC3E,cAAc,aAAd,cAAc,uBAAd,cAAc,EAAI,CAAC;gBAEnB,cAAc,GAAG,IAAI,CAAC;gBAEtB,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;oBACjB,YAAY,GAAG,KAAK,CAAC;gBACzB,CAAC;qBAAM,CAAC;oBACJ,MAAM,IAAI,SAAS,CAAC,oDAAoD,CAAC,CAAC;gBAC9E,CAAC;YACL,CAAC;SACJ;KACJ,CAAC,CAAC;IAEH,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;QACxB,cAAc,GAAG,uBAAuB,CAAC,gBAAgB,EAAE,OAAO,EAAE,2BAA2B,EAAE,YAAY,CAAC,CAAC;IACnH,CAAC;IAED,OAAuD,gBAAgB,CAAC;AAC5E,CAAC"}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
import { TNativeAudioWorkletNode } from 'standardized-audio-context';
|
|
2
|
-
|
|
2
|
+
import { ITimingObject } from 'timing-object';
|
|
3
|
+
export type TNativeTimedAudioBufferSourceNodeAudioWorkletNode = TNativeAudioWorkletNode & {
|
|
4
|
+
timingObject: null | ITimingObject;
|
|
5
|
+
};
|
|
3
6
|
//# sourceMappingURL=native-timed-audio-buffer-source-node-audio-worklet-node.d.ts.map
|
package/build/es2019/types/native-timed-audio-buffer-source-node-audio-worklet-node.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native-timed-audio-buffer-source-node-audio-worklet-node.d.ts","sourceRoot":"","sources":["../../../src/types/native-timed-audio-buffer-source-node-audio-worklet-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;
|
|
1
|
+
{"version":3,"file":"native-timed-audio-buffer-source-node-audio-worklet-node.d.ts","sourceRoot":"","sources":["../../../src/types/native-timed-audio-buffer-source-node-audio-worklet-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,MAAM,MAAM,iDAAiD,GAAG,uBAAuB,GAAG;IACtF,YAAY,EAAE,IAAI,GAAG,aAAa,CAAC;CACtC,CAAC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const worklet = "(()=>{\"use strict\";class e extends AudioWorkletProcessor{constructor(e){let{numberOfInputs:t,numberOfOutputs:r,outputChannelCount:o,processorOptions:n}=e;var s;const
|
|
1
|
+
export declare const worklet = "(()=>{\"use strict\";class e extends AudioWorkletProcessor{constructor(e){let{numberOfInputs:t,numberOfOutputs:r,outputChannelCount:o,processorOptions:n}=e;var s;const i=\"object\"==typeof n&&null!==n&&\"buffer\"in n?n.buffer:null;if(!(null===i||Array.isArray(i)&&i.every((e=>e instanceof Float32Array))))throw new Error(\"The buffer needs to be either null or an array with where each element is a Float32Array.\");if(1!==t)throw new Error(\"The numberOfInputs must be 1.\");if(1!==r)throw new Error(\"The numberOfOutputs must be 1.\");const u=null!==(s=null==i?void 0:i.length)&&void 0!==s?s:1;if(void 0===o||1!==o.length||u!==o[0])throw new Error(\"The outputChannelCount must match the number of channels of the buffer.\");const f=\"object\"==typeof n&&null!==n&&\"position\"in n?n.position:0;if(\"number\"!=typeof f)throw new Error('The position needs to be of type \"number\".');const h=\"object\"==typeof n&&null!==n&&\"timestamp\"in n?n.timestamp:0;if(\"number\"!=typeof h)throw new Error('The timestamp needs to be of type \"number\".');super(),this._buffer=i,this._position=f,this._timestamp=h}process(e,t){let[r]=e,[o]=t;if(r.length>0){const[e]=r;e.length>1&&(this._position=Math.round(e[0]),this._timestamp=Math.round(e[1]))}if(null!==this._buffer){const e=this._buffer.length;for(let t=0;t<e;t+=1){const e=this._buffer[t],r=o[t];for(let t=0;t<128;t+=1){const o=this._position+currentFrame-this._timestamp+t;o>=0&&o<e.length&&(r[t]=e[o])}}}return!0}}e.parameterDescriptors=[],registerProcessor(\"timed-audio-buffer-source-node-audio-worklet-processor\",e)})();";
|
|
2
2
|
//# sourceMappingURL=worklet.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worklet.d.ts","sourceRoot":"","sources":["../../../src/worklet/worklet.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,OAAO,
|
|
1
|
+
{"version":3,"file":"worklet.d.ts","sourceRoot":"","sources":["../../../src/worklet/worklet.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,OAAO,yiDAAygD,CAAC"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// This is the minified and stringified code of the timed-audio-buffer-source-node-audio-worklet-processor package.
|
|
2
|
-
export const worklet = `(()=>{"use strict";class e extends AudioWorkletProcessor{constructor(e){let{numberOfInputs:t,numberOfOutputs:r,outputChannelCount:o,processorOptions:n}=e;var s;const
|
|
2
|
+
export const worklet = `(()=>{"use strict";class e extends AudioWorkletProcessor{constructor(e){let{numberOfInputs:t,numberOfOutputs:r,outputChannelCount:o,processorOptions:n}=e;var s;const i="object"==typeof n&&null!==n&&"buffer"in n?n.buffer:null;if(!(null===i||Array.isArray(i)&&i.every((e=>e instanceof Float32Array))))throw new Error("The buffer needs to be either null or an array with where each element is a Float32Array.");if(1!==t)throw new Error("The numberOfInputs must be 1.");if(1!==r)throw new Error("The numberOfOutputs must be 1.");const u=null!==(s=null==i?void 0:i.length)&&void 0!==s?s:1;if(void 0===o||1!==o.length||u!==o[0])throw new Error("The outputChannelCount must match the number of channels of the buffer.");const f="object"==typeof n&&null!==n&&"position"in n?n.position:0;if("number"!=typeof f)throw new Error('The position needs to be of type "number".');const h="object"==typeof n&&null!==n&&"timestamp"in n?n.timestamp:0;if("number"!=typeof h)throw new Error('The timestamp needs to be of type "number".');super(),this._buffer=i,this._position=f,this._timestamp=h}process(e,t){let[r]=e,[o]=t;if(r.length>0){const[e]=r;e.length>1&&(this._position=Math.round(e[0]),this._timestamp=Math.round(e[1]))}if(null!==this._buffer){const e=this._buffer.length;for(let t=0;t<e;t+=1){const e=this._buffer[t],r=o[t];for(let t=0;t<128;t+=1){const o=this._position+currentFrame-this._timestamp+t;o>=0&&o<e.length&&(r[t]=e[o])}}}return!0}}e.parameterDescriptors=[],registerProcessor("timed-audio-buffer-source-node-audio-worklet-processor",e)})();`; // tslint:disable-line:max-line-length
|
|
3
3
|
//# sourceMappingURL=worklet.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worklet.js","sourceRoot":"","sources":["../../../src/worklet/worklet.ts"],"names":[],"mappings":"AAAA,mHAAmH;AACnH,MAAM,CAAC,MAAM,OAAO,GAAG,
|
|
1
|
+
{"version":3,"file":"worklet.js","sourceRoot":"","sources":["../../../src/worklet/worklet.ts"],"names":[],"mappings":"AAAA,mHAAmH;AACnH,MAAM,CAAC,MAAM,OAAO,GAAG,sgDAAsgD,CAAC,CAAC,sCAAsC"}
|
package/build/es5/bundle.js
CHANGED
|
@@ -1,14 +1,79 @@
|
|
|
1
1
|
(function (global, factory) {
|
|
2
|
-
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@babel/runtime/helpers/
|
|
3
|
-
typeof define === 'function' && define.amd ? define(['exports', '@babel/runtime/helpers/
|
|
4
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.timedAudioBufferSourceNodeAudioWorklet = {}, global.
|
|
5
|
-
})(this, (function (exports,
|
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@babel/runtime/helpers/asyncToGenerator'), require('@babel/runtime/regenerator')) :
|
|
3
|
+
typeof define === 'function' && define.amd ? define(['exports', '@babel/runtime/helpers/asyncToGenerator', '@babel/runtime/regenerator'], factory) :
|
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.timedAudioBufferSourceNodeAudioWorklet = {}, global._asyncToGenerator, global._regeneratorRuntime));
|
|
5
|
+
})(this, (function (exports, _asyncToGenerator, _regeneratorRuntime) { 'use strict';
|
|
6
|
+
|
|
7
|
+
var createConvertToContextFrame = function createConvertToContextFrame(performance) {
|
|
8
|
+
return function (context, timestamp) {
|
|
9
|
+
if (performance === null) {
|
|
10
|
+
throw new Error('Performance is not available.');
|
|
11
|
+
}
|
|
12
|
+
return Math.round((context.currentTime - performance.now() / 1000 + timestamp) * context.sampleRate);
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
var createPerformance = function createPerformance() {
|
|
17
|
+
return typeof window === 'undefined' ? null : typeof window.performance === 'undefined' ? null : window.performance;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
var createScheduleAudioBufferSourceNode = function createScheduleAudioBufferSourceNode(convertToContextFrame) {
|
|
21
|
+
return function (audioWorkletNode, context, createAudioBufferSourceNode, timingObject) {
|
|
22
|
+
var audioBuffer = new AudioBuffer({
|
|
23
|
+
length: 2,
|
|
24
|
+
sampleRate: context.sampleRate
|
|
25
|
+
});
|
|
26
|
+
var audioBufferSourceNode = createAudioBufferSourceNode(context);
|
|
27
|
+
var _timingObject$query = timingObject.query(),
|
|
28
|
+
position = _timingObject$query.position,
|
|
29
|
+
timestamp = _timingObject$query.timestamp;
|
|
30
|
+
audioBuffer.copyToChannel(new Float32Array([position, convertToContextFrame(context, timestamp)]), 0);
|
|
31
|
+
audioBufferSourceNode.buffer = audioBuffer;
|
|
32
|
+
var promise = new Promise(function (resolve) {
|
|
33
|
+
return audioBufferSourceNode.addEventListener('ended', function () {
|
|
34
|
+
return resolve();
|
|
35
|
+
}, {
|
|
36
|
+
once: true
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
audioBufferSourceNode.connect(audioWorkletNode);
|
|
40
|
+
audioBufferSourceNode.start();
|
|
41
|
+
return promise;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
var createSubscribeToTimingObject = function createSubscribeToTimingObject(scheduleAudioBufferSourceNode) {
|
|
46
|
+
return function (audioWorkletNode, context, createAudioBufferSourceNode, timingObject) {
|
|
47
|
+
var hasPendingUpdate = false;
|
|
48
|
+
var isSendingUpdate = false;
|
|
49
|
+
var scheduleUpdate = function scheduleUpdate() {
|
|
50
|
+
hasPendingUpdate = false;
|
|
51
|
+
scheduleAudioBufferSourceNode(audioWorkletNode, context, createAudioBufferSourceNode, timingObject).then(function () {
|
|
52
|
+
if (hasPendingUpdate) {
|
|
53
|
+
scheduleUpdate();
|
|
54
|
+
} else {
|
|
55
|
+
isSendingUpdate = false;
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
var listener = function listener() {
|
|
60
|
+
if (isSendingUpdate) {
|
|
61
|
+
hasPendingUpdate = true;
|
|
62
|
+
} else {
|
|
63
|
+
isSendingUpdate = true;
|
|
64
|
+
scheduleUpdate();
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
timingObject.addEventListener('change', listener);
|
|
68
|
+
return function () {
|
|
69
|
+
return timingObject.removeEventListener('change', listener);
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
};
|
|
6
73
|
|
|
7
74
|
// This is the minified and stringified code of the timed-audio-buffer-source-node-audio-worklet-processor package.
|
|
8
|
-
var worklet = "(()=>{var e={31:function(e,t,r){!function(e,t,r,o,n,u,s,p){\"use strict\";function i(e){var t=
|
|
75
|
+
var worklet = "(()=>{var e={31:function(e,t,r){!function(e,t,r,o,n,u,s,p){\"use strict\";function i(e){var t=f();return function(){var r,o=s(e);if(t){var n=s(this).constructor;r=Reflect.construct(o,arguments,n)}else r=o.apply(this,arguments);return u(this,r)}}function f(){if(\"undefined\"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if(\"function\"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){}))),!0}catch(e){return!1}}var l=function(u){n(p,u);var s=i(p);function p(e){var o,n,u=e.numberOfInputs,i=e.numberOfOutputs,f=e.outputChannelCount,l=e.processorOptions;r(this,p);var a=\"object\"===t(l)&&null!==l&&\"buffer\"in l?l.buffer:null;if(!(null===a||Array.isArray(a)&&a.every((function(e){return e instanceof Float32Array}))))throw new Error(\"The buffer needs to be either null or an array with where each element is a Float32Array.\");if(1!==u)throw new Error(\"The numberOfInputs must be 1.\");if(1!==i)throw new Error(\"The numberOfOutputs must be 1.\");var c=null!==(n=null==a?void 0:a.length)&&void 0!==n?n:1;if(void 0===f||1!==f.length||c!==f[0])throw new Error(\"The outputChannelCount must match the number of channels of the buffer.\");var x=\"object\"===t(l)&&null!==l&&\"position\"in l?l.position:0;if(\"number\"!=typeof x)throw new Error('The position needs to be of type \"number\".');var d=\"object\"===t(l)&&null!==l&&\"timestamp\"in l?l.timestamp:0;if(\"number\"!=typeof d)throw new Error('The timestamp needs to be of type \"number\".');return(o=s.call(this))._buffer=a,o._position=x,o._timestamp=d,o}return o(p,[{key:\"process\",value:function(t,r){var o=e(t,1)[0],n=e(r,1)[0];if(o.length>0){var u=e(o,1)[0];u.length>1&&(this._position=Math.round(u[0]),this._timestamp=Math.round(u[1]))}if(null!==this._buffer)for(var s=this._buffer.length,p=0;p<s;p+=1)for(var i=this._buffer[p],f=n[p],l=0;l<128;l+=1){var a=this._position+currentFrame-this._timestamp+l;a>=0&&a<i.length&&(f[l]=i[a])}return!0}}]),p}(p(AudioWorkletProcessor));l.parameterDescriptors=[],registerProcessor(\"timed-audio-buffer-source-node-audio-worklet-processor\",l)}(r(424),r(698),r(690),r(728),r(655),r(993),r(808),r(496))},897:e=>{e.exports=function(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,o=new Array(t);r<t;r++)o[r]=e[r];return o},e.exports.__esModule=!0,e.exports.default=e.exports},372:e=>{e.exports=function(e){if(Array.isArray(e))return e},e.exports.__esModule=!0,e.exports.default=e.exports},115:e=>{e.exports=function(e){if(void 0===e)throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");return e},e.exports.__esModule=!0,e.exports.default=e.exports},690:e=>{e.exports=function(e,t){if(!(e instanceof t))throw new TypeError(\"Cannot call a class as a function\")},e.exports.__esModule=!0,e.exports.default=e.exports},515:(e,t,r)=>{var o=r(15),n=r(617);function u(t,r,s){return n()?(e.exports=u=Reflect.construct.bind(),e.exports.__esModule=!0,e.exports.default=e.exports):(e.exports=u=function(e,t,r){var n=[null];n.push.apply(n,t);var u=new(Function.bind.apply(e,n));return r&&o(u,r.prototype),u},e.exports.__esModule=!0,e.exports.default=e.exports),u.apply(null,arguments)}e.exports=u,e.exports.__esModule=!0,e.exports.default=e.exports},728:(e,t,r)=>{var o=r(62);function n(e,t){for(var r=0;r<t.length;r++){var n=t[r];n.enumerable=n.enumerable||!1,n.configurable=!0,\"value\"in n&&(n.writable=!0),Object.defineProperty(e,o(n.key),n)}}e.exports=function(e,t,r){return t&&n(e.prototype,t),r&&n(e,r),Object.defineProperty(e,\"prototype\",{writable:!1}),e},e.exports.__esModule=!0,e.exports.default=e.exports},808:e=>{function t(r){return e.exports=t=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(e){return e.__proto__||Object.getPrototypeOf(e)},e.exports.__esModule=!0,e.exports.default=e.exports,t(r)}e.exports=t,e.exports.__esModule=!0,e.exports.default=e.exports},655:(e,t,r)=>{var o=r(15);e.exports=function(e,t){if(\"function\"!=typeof t&&null!==t)throw new TypeError(\"Super expression must either be null or a function\");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),Object.defineProperty(e,\"prototype\",{writable:!1}),t&&o(e,t)},e.exports.__esModule=!0,e.exports.default=e.exports},35:e=>{e.exports=function(e){try{return-1!==Function.toString.call(e).indexOf(\"[native code]\")}catch(t){return\"function\"==typeof e}},e.exports.__esModule=!0,e.exports.default=e.exports},617:e=>{e.exports=function(){if(\"undefined\"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if(\"function\"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){}))),!0}catch(e){return!1}},e.exports.__esModule=!0,e.exports.default=e.exports},872:e=>{e.exports=function(e,t){var r=null==e?null:\"undefined\"!=typeof Symbol&&e[Symbol.iterator]||e[\"@@iterator\"];if(null!=r){var o,n,u,s,p=[],i=!0,f=!1;try{if(u=(r=r.call(e)).next,0===t){if(Object(r)!==r)return;i=!1}else for(;!(i=(o=u.call(r)).done)&&(p.push(o.value),p.length!==t);i=!0);}catch(e){f=!0,n=e}finally{try{if(!i&&null!=r.return&&(s=r.return(),Object(s)!==s))return}finally{if(f)throw n}}return p}},e.exports.__esModule=!0,e.exports.default=e.exports},218:e=>{e.exports=function(){throw new TypeError(\"Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\")},e.exports.__esModule=!0,e.exports.default=e.exports},993:(e,t,r)=>{var o=r(698).default,n=r(115);e.exports=function(e,t){if(t&&(\"object\"===o(t)||\"function\"==typeof t))return t;if(void 0!==t)throw new TypeError(\"Derived constructors may only return object or undefined\");return n(e)},e.exports.__esModule=!0,e.exports.default=e.exports},15:e=>{function t(r,o){return e.exports=t=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(e,t){return e.__proto__=t,e},e.exports.__esModule=!0,e.exports.default=e.exports,t(r,o)}e.exports=t,e.exports.__esModule=!0,e.exports.default=e.exports},424:(e,t,r)=>{var o=r(372),n=r(872),u=r(116),s=r(218);e.exports=function(e,t){return o(e)||n(e,t)||u(e,t)||s()},e.exports.__esModule=!0,e.exports.default=e.exports},36:(e,t,r)=>{var o=r(698).default;e.exports=function(e,t){if(\"object\"!=o(e)||!e)return e;var r=e[Symbol.toPrimitive];if(void 0!==r){var n=r.call(e,t||\"default\");if(\"object\"!=o(n))return n;throw new TypeError(\"@@toPrimitive must return a primitive value.\")}return(\"string\"===t?String:Number)(e)},e.exports.__esModule=!0,e.exports.default=e.exports},62:(e,t,r)=>{var o=r(698).default,n=r(36);e.exports=function(e){var t=n(e,\"string\");return\"symbol\"==o(t)?t:String(t)},e.exports.__esModule=!0,e.exports.default=e.exports},698:e=>{function t(r){return e.exports=t=\"function\"==typeof Symbol&&\"symbol\"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&\"function\"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?\"symbol\":typeof e},e.exports.__esModule=!0,e.exports.default=e.exports,t(r)}e.exports=t,e.exports.__esModule=!0,e.exports.default=e.exports},116:(e,t,r)=>{var o=r(897);e.exports=function(e,t){if(e){if(\"string\"==typeof e)return o(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);return\"Object\"===r&&e.constructor&&(r=e.constructor.name),\"Map\"===r||\"Set\"===r?Array.from(e):\"Arguments\"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?o(e,t):void 0}},e.exports.__esModule=!0,e.exports.default=e.exports},496:(e,t,r)=>{var o=r(808),n=r(15),u=r(35),s=r(515);function p(t){var r=\"function\"==typeof Map?new Map:void 0;return e.exports=p=function(e){if(null===e||!u(e))return e;if(\"function\"!=typeof e)throw new TypeError(\"Super expression must either be null or a function\");if(void 0!==r){if(r.has(e))return r.get(e);r.set(e,t)}function t(){return s(e,arguments,o(this).constructor)}return t.prototype=Object.create(e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),n(t,e)},e.exports.__esModule=!0,e.exports.default=e.exports,p(t)}e.exports=p,e.exports.__esModule=!0,e.exports.default=e.exports}},t={};function r(o){var n=t[o];if(void 0!==n)return n.exports;var u=t[o]={exports:{}};return e[o].call(u.exports,u,u.exports,r),u.exports}r.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return r.d(t,{a:t}),t},r.d=(e,t)=>{for(var o in t)r.o(t,o)&&!r.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{\"use strict\";r(31)})()})();"; // tslint:disable-line:max-line-length
|
|
9
76
|
|
|
10
|
-
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
11
|
-
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
12
77
|
var blob = new Blob([worklet], {
|
|
13
78
|
type: 'application/javascript; charset=utf-8'
|
|
14
79
|
});
|
|
@@ -36,39 +101,62 @@
|
|
|
36
101
|
return _ref.apply(this, arguments);
|
|
37
102
|
};
|
|
38
103
|
}();
|
|
39
|
-
|
|
40
|
-
|
|
104
|
+
var convertToContextFrame = createConvertToContextFrame(createPerformance());
|
|
105
|
+
var subscribeToTimingObject = createSubscribeToTimingObject(createScheduleAudioBufferSourceNode(convertToContextFrame));
|
|
106
|
+
function createTimedAudioBufferSourceNodeAudioWorkletNode(audioWorkletNodeConstructor, context, createAudioBufferSourceNode) {
|
|
107
|
+
var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
41
108
|
var _a, _b;
|
|
42
109
|
var _options$buffer = options.buffer,
|
|
43
|
-
buffer = _options$buffer === void 0 ? null : _options$buffer
|
|
44
|
-
|
|
110
|
+
buffer = _options$buffer === void 0 ? null : _options$buffer;
|
|
111
|
+
if (buffer instanceof AudioBuffer && buffer.sampleRate !== context.sampleRate) {
|
|
112
|
+
throw new TypeError('The AudioBuffer must have the same sampleRate as the AudioContext.');
|
|
113
|
+
}
|
|
114
|
+
var _options$timingObject = options.timingObject,
|
|
45
115
|
timingObject = _options$timingObject === void 0 ? null : _options$timingObject;
|
|
46
116
|
var _ref2 = (_a = timingObject === null || timingObject === void 0 ? void 0 : timingObject.query()) !== null && _a !== void 0 ? _a : {},
|
|
47
117
|
_ref2$position = _ref2.position,
|
|
48
118
|
position = _ref2$position === void 0 ? 0 : _ref2$position,
|
|
49
119
|
_ref2$timestamp = _ref2.timestamp,
|
|
50
120
|
timestamp = _ref2$timestamp === void 0 ? 0 : _ref2$timestamp;
|
|
51
|
-
var audioWorkletNode = new audioWorkletNodeConstructor(context, 'timed-audio-buffer-source-node-audio-worklet-processor',
|
|
52
|
-
numberOfInputs:
|
|
121
|
+
var audioWorkletNode = new audioWorkletNodeConstructor(context, 'timed-audio-buffer-source-node-audio-worklet-processor', {
|
|
122
|
+
numberOfInputs: 1,
|
|
53
123
|
numberOfOutputs: 1,
|
|
54
124
|
outputChannelCount: [(_b = buffer === null || buffer === void 0 ? void 0 : buffer.numberOfChannels) !== null && _b !== void 0 ? _b : 1],
|
|
55
|
-
|
|
56
|
-
buffer: buffer instanceof
|
|
125
|
+
processorOptions: {
|
|
126
|
+
buffer: buffer instanceof AudioBuffer ? Array.from({
|
|
57
127
|
length: buffer.numberOfChannels
|
|
58
128
|
}, function (_, channel) {
|
|
59
129
|
return buffer.getChannelData(channel);
|
|
60
130
|
}) : null,
|
|
61
131
|
position: position,
|
|
62
|
-
timestamp: timestamp
|
|
132
|
+
timestamp: convertToContextFrame(context, timestamp)
|
|
63
133
|
}
|
|
64
|
-
})
|
|
134
|
+
});
|
|
135
|
+
var removeListener = null;
|
|
65
136
|
Object.defineProperties(audioWorkletNode, {
|
|
66
137
|
port: {
|
|
67
138
|
get: function get() {
|
|
68
139
|
throw new Error("The port of a TimedAudioBufferSourceNodeAudioWorkletNode can't be accessed.");
|
|
69
140
|
}
|
|
141
|
+
},
|
|
142
|
+
timingObject: {
|
|
143
|
+
get: function get() {
|
|
144
|
+
return timingObject;
|
|
145
|
+
},
|
|
146
|
+
set: function set(value) {
|
|
147
|
+
removeListener === null || removeListener === void 0 ? void 0 : removeListener();
|
|
148
|
+
removeListener = null;
|
|
149
|
+
if (value === null) {
|
|
150
|
+
timingObject = value;
|
|
151
|
+
} else {
|
|
152
|
+
throw new TypeError('A TimingObject can only be set in the constructor.');
|
|
153
|
+
}
|
|
154
|
+
}
|
|
70
155
|
}
|
|
71
156
|
});
|
|
157
|
+
if (timingObject !== null) {
|
|
158
|
+
removeListener = subscribeToTimingObject(audioWorkletNode, context, createAudioBufferSourceNode, timingObject);
|
|
159
|
+
}
|
|
72
160
|
return audioWorkletNode;
|
|
73
161
|
}
|
|
74
162
|
|
package/package.json
CHANGED
|
@@ -9,18 +9,18 @@
|
|
|
9
9
|
}
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@babel/runtime": "^7.23.
|
|
13
|
-
"standardized-audio-context": "^25.3.
|
|
14
|
-
"timed-audio-buffer-source-node-audio-worklet-processor": "^
|
|
15
|
-
"timing-object": "^3.1.
|
|
12
|
+
"@babel/runtime": "^7.23.6",
|
|
13
|
+
"standardized-audio-context": "^25.3.60",
|
|
14
|
+
"timed-audio-buffer-source-node-audio-worklet-processor": "^2.0.0",
|
|
15
|
+
"timing-object": "^3.1.70",
|
|
16
16
|
"tslib": "^2.6.2"
|
|
17
17
|
},
|
|
18
18
|
"description": "This module provides a loader for the TimedAudioBufferSourceNodeAudioWorkletProcessor and the corresponding TimedAudioBufferSourceNodeAudioWorkletNode.",
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"@babel/core": "^7.23.
|
|
20
|
+
"@babel/core": "^7.23.6",
|
|
21
21
|
"@babel/plugin-external-helpers": "^7.23.3",
|
|
22
|
-
"@babel/plugin-transform-runtime": "^7.23.
|
|
23
|
-
"@babel/preset-env": "^7.23.
|
|
22
|
+
"@babel/plugin-transform-runtime": "^7.23.6",
|
|
23
|
+
"@babel/preset-env": "^7.23.6",
|
|
24
24
|
"@commitlint/cli": "^17.8.0",
|
|
25
25
|
"@commitlint/config-angular": "^17.8.0",
|
|
26
26
|
"@rollup/plugin-babel": "^6.0.4",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"chai": "^4.3.10",
|
|
30
30
|
"commitizen": "^4.3.0",
|
|
31
31
|
"cz-conventional-changelog": "^3.3.0",
|
|
32
|
-
"eslint": "^8.
|
|
33
|
-
"eslint-config-holy-grail": "^57.2.
|
|
32
|
+
"eslint": "^8.56.0",
|
|
33
|
+
"eslint-config-holy-grail": "^57.2.26",
|
|
34
34
|
"grunt": "^1.6.1",
|
|
35
35
|
"grunt-cli": "^1.4.3",
|
|
36
36
|
"grunt-sh": "^0.2.1",
|
|
@@ -41,15 +41,15 @@
|
|
|
41
41
|
"karma-mocha": "^2.0.1",
|
|
42
42
|
"karma-sauce-launcher": "^4.3.6",
|
|
43
43
|
"karma-sinon-chai": "^2.0.2",
|
|
44
|
-
"karma-webkit-launcher": "^2.
|
|
44
|
+
"karma-webkit-launcher": "^2.4.0",
|
|
45
45
|
"karma-webpack": "^5.0.0",
|
|
46
|
-
"lint-staged": "^15.
|
|
46
|
+
"lint-staged": "^15.2.0",
|
|
47
47
|
"load-grunt-config": "^4.0.1",
|
|
48
48
|
"memfs": "^4.6.0",
|
|
49
49
|
"mocha": "^10.2.0",
|
|
50
|
-
"prettier": "^3.1.
|
|
50
|
+
"prettier": "^3.1.1",
|
|
51
51
|
"rimraf": "^5.0.5",
|
|
52
|
-
"rollup": "^4.
|
|
52
|
+
"rollup": "^4.9.1",
|
|
53
53
|
"sinon": "^17.0.1",
|
|
54
54
|
"sinon-chai": "^3.7.0",
|
|
55
55
|
"terser-webpack-plugin": "^5.3.9",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"tsconfig-holy-grail": "^14.0.8",
|
|
58
58
|
"tslint": "^6.1.3",
|
|
59
59
|
"tslint-config-holy-grail": "^55.0.5",
|
|
60
|
-
"typescript": "^5.3.
|
|
60
|
+
"typescript": "^5.3.3",
|
|
61
61
|
"webpack": "^5.89.0",
|
|
62
62
|
"webpack-cli": "^5.1.4"
|
|
63
63
|
},
|
|
@@ -86,5 +86,5 @@
|
|
|
86
86
|
"test": "grunt lint && grunt test"
|
|
87
87
|
},
|
|
88
88
|
"types": "build/es2019/module.d.ts",
|
|
89
|
-
"version": "
|
|
89
|
+
"version": "2.0.0"
|
|
90
90
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { TContext, TNativeContext } from 'standardized-audio-context';
|
|
2
|
+
import type { createPerformance } from './performance';
|
|
3
|
+
|
|
4
|
+
export const createConvertToContextFrame =
|
|
5
|
+
(performance: ReturnType<typeof createPerformance>) => (context: TContext | TNativeContext, timestamp: number) => {
|
|
6
|
+
if (performance === null) {
|
|
7
|
+
throw new Error('Performance is not available.');
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return Math.round((context.currentTime - performance.now() / 1000 + timestamp) * context.sampleRate);
|
|
11
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IAudioBufferSourceNode,
|
|
3
|
+
IAudioWorkletNode,
|
|
4
|
+
TContext,
|
|
5
|
+
TNativeAudioBufferSourceNode,
|
|
6
|
+
TNativeAudioWorkletNode,
|
|
7
|
+
TNativeContext
|
|
8
|
+
} from 'standardized-audio-context';
|
|
9
|
+
import { ITimingObject } from 'timing-object';
|
|
10
|
+
import type { createConvertToContextFrame } from './convert-to-context-frame';
|
|
11
|
+
|
|
12
|
+
export const createScheduleAudioBufferSourceNode =
|
|
13
|
+
(convertToContextFrame: ReturnType<typeof createConvertToContextFrame>) =>
|
|
14
|
+
<T extends TContext | TNativeContext>(
|
|
15
|
+
audioWorkletNode: T extends TContext ? IAudioWorkletNode<T> : TNativeAudioWorkletNode,
|
|
16
|
+
context: T,
|
|
17
|
+
createAudioBufferSourceNode: T extends TContext
|
|
18
|
+
? (context: TContext) => IAudioBufferSourceNode<TContext>
|
|
19
|
+
: (context: TNativeContext) => TNativeAudioBufferSourceNode,
|
|
20
|
+
timingObject: ITimingObject
|
|
21
|
+
): Promise<void> => {
|
|
22
|
+
const audioBuffer = new AudioBuffer({ length: 2, sampleRate: context.sampleRate });
|
|
23
|
+
const audioBufferSourceNode = createAudioBufferSourceNode(<any>context);
|
|
24
|
+
const { position, timestamp } = timingObject.query();
|
|
25
|
+
|
|
26
|
+
audioBuffer.copyToChannel(new Float32Array([position, convertToContextFrame(context, timestamp)]), 0);
|
|
27
|
+
|
|
28
|
+
audioBufferSourceNode.buffer = audioBuffer;
|
|
29
|
+
|
|
30
|
+
const promise = new Promise<void>((resolve) => audioBufferSourceNode.addEventListener('ended', () => resolve(), { once: true }));
|
|
31
|
+
|
|
32
|
+
audioBufferSourceNode.connect(<any>audioWorkletNode);
|
|
33
|
+
audioBufferSourceNode.start();
|
|
34
|
+
|
|
35
|
+
return promise;
|
|
36
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IAudioBufferSourceNode,
|
|
3
|
+
IAudioWorkletNode,
|
|
4
|
+
TContext,
|
|
5
|
+
TNativeAudioBufferSourceNode,
|
|
6
|
+
TNativeAudioWorkletNode,
|
|
7
|
+
TNativeContext
|
|
8
|
+
} from 'standardized-audio-context';
|
|
9
|
+
import { ITimingObject } from 'timing-object';
|
|
10
|
+
import type { createScheduleAudioBufferSourceNode } from './schedule-audio-buffer-source-node';
|
|
11
|
+
|
|
12
|
+
export const createSubscribeToTimingObject =
|
|
13
|
+
(scheduleAudioBufferSourceNode: ReturnType<typeof createScheduleAudioBufferSourceNode>) =>
|
|
14
|
+
<T extends TContext | TNativeContext>(
|
|
15
|
+
audioWorkletNode: T extends TContext ? IAudioWorkletNode<T> : TNativeAudioWorkletNode,
|
|
16
|
+
context: T,
|
|
17
|
+
createAudioBufferSourceNode: T extends TContext
|
|
18
|
+
? (context: TContext) => IAudioBufferSourceNode<TContext>
|
|
19
|
+
: (context: TNativeContext) => TNativeAudioBufferSourceNode,
|
|
20
|
+
timingObject: ITimingObject
|
|
21
|
+
) => {
|
|
22
|
+
let hasPendingUpdate = false;
|
|
23
|
+
let isSendingUpdate = false;
|
|
24
|
+
|
|
25
|
+
const scheduleUpdate = () => {
|
|
26
|
+
hasPendingUpdate = false;
|
|
27
|
+
|
|
28
|
+
scheduleAudioBufferSourceNode(audioWorkletNode, context, createAudioBufferSourceNode, timingObject).then(() => {
|
|
29
|
+
if (hasPendingUpdate) {
|
|
30
|
+
scheduleUpdate();
|
|
31
|
+
} else {
|
|
32
|
+
isSendingUpdate = false;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
const listener = () => {
|
|
37
|
+
if (isSendingUpdate) {
|
|
38
|
+
hasPendingUpdate = true;
|
|
39
|
+
} else {
|
|
40
|
+
isSendingUpdate = true;
|
|
41
|
+
|
|
42
|
+
scheduleUpdate();
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
timingObject.addEventListener('change', listener);
|
|
47
|
+
|
|
48
|
+
return () => timingObject.removeEventListener('change', listener);
|
|
49
|
+
};
|
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
import { IAudioWorkletNode, TContext } from 'standardized-audio-context';
|
|
2
|
+
import { ITimingObject } from 'timing-object';
|
|
2
3
|
|
|
3
|
-
export interface ITimedAudioBufferSourceNodeAudioWorkletNode<T extends TContext> extends IAudioWorkletNode<T> {
|
|
4
|
+
export interface ITimedAudioBufferSourceNodeAudioWorkletNode<T extends TContext> extends IAudioWorkletNode<T> {
|
|
5
|
+
timingObject: null | ITimingObject;
|
|
6
|
+
}
|
package/src/module.ts
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
IAudioBufferSourceNode,
|
|
3
3
|
IAudioWorkletNode,
|
|
4
4
|
TAudioWorkletNodeConstructor,
|
|
5
5
|
TContext,
|
|
6
|
+
TNativeAudioBufferSourceNode,
|
|
6
7
|
TNativeAudioWorkletNode,
|
|
7
8
|
TNativeAudioWorkletNodeConstructor,
|
|
8
9
|
TNativeContext
|
|
9
10
|
} from 'standardized-audio-context';
|
|
11
|
+
import { createConvertToContextFrame } from './factories/convert-to-context-frame';
|
|
12
|
+
import { createPerformance } from './factories/performance';
|
|
13
|
+
import { createScheduleAudioBufferSourceNode } from './factories/schedule-audio-buffer-source-node';
|
|
14
|
+
import { createSubscribeToTimingObject } from './factories/subscribe-to-timing-object';
|
|
10
15
|
import { ITimedAudioBufferSourceNodeAudioWorkletNode } from './interfaces';
|
|
11
16
|
import { TAnyTimedAudioBufferSourceNodeAudioWorkletNodeOptions, TNativeTimedAudioBufferSourceNodeAudioWorkletNode } from './types';
|
|
12
17
|
import { worklet } from './worklet/worklet';
|
|
@@ -30,9 +35,15 @@ export const addTimedAudioBufferSourceNodeAudioWorkletModule = async (addAudioWo
|
|
|
30
35
|
}
|
|
31
36
|
};
|
|
32
37
|
|
|
38
|
+
const convertToContextFrame = createConvertToContextFrame(createPerformance());
|
|
39
|
+
const subscribeToTimingObject = createSubscribeToTimingObject(createScheduleAudioBufferSourceNode(convertToContextFrame));
|
|
40
|
+
|
|
33
41
|
export function createTimedAudioBufferSourceNodeAudioWorkletNode<T extends TContext | TNativeContext>(
|
|
34
42
|
audioWorkletNodeConstructor: T extends TContext ? TAudioWorkletNodeConstructor : TNativeAudioWorkletNodeConstructor,
|
|
35
43
|
context: T,
|
|
44
|
+
createAudioBufferSourceNode: T extends TContext
|
|
45
|
+
? (context: TContext) => IAudioBufferSourceNode<TContext>
|
|
46
|
+
: (context: TNativeContext) => TNativeAudioBufferSourceNode,
|
|
36
47
|
options: Partial<TAnyTimedAudioBufferSourceNodeAudioWorkletNodeOptions<T>> = {}
|
|
37
48
|
): T extends TContext ? ITimedAudioBufferSourceNodeAudioWorkletNode<T> : TNativeTimedAudioBufferSourceNodeAudioWorkletNode {
|
|
38
49
|
type TAnyAudioWorkletNode = T extends TContext ? IAudioWorkletNode<T> : TNativeAudioWorkletNode;
|
|
@@ -40,34 +51,60 @@ export function createTimedAudioBufferSourceNodeAudioWorkletNode<T extends TCont
|
|
|
40
51
|
? ITimedAudioBufferSourceNodeAudioWorkletNode<T>
|
|
41
52
|
: TNativeTimedAudioBufferSourceNodeAudioWorkletNode;
|
|
42
53
|
|
|
43
|
-
const { buffer = null
|
|
54
|
+
const { buffer = null } = options;
|
|
55
|
+
|
|
56
|
+
if (buffer instanceof AudioBuffer && buffer.sampleRate !== context.sampleRate) {
|
|
57
|
+
throw new TypeError('The AudioBuffer must have the same sampleRate as the AudioContext.');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let { timingObject = null } = options;
|
|
61
|
+
|
|
44
62
|
const { position = 0, timestamp = 0 } = timingObject?.query() ?? {};
|
|
45
63
|
const audioWorkletNode: TAnyAudioWorkletNode = new (<any>audioWorkletNodeConstructor)(
|
|
46
64
|
context,
|
|
47
65
|
'timed-audio-buffer-source-node-audio-worklet-processor',
|
|
48
66
|
{
|
|
49
|
-
|
|
50
|
-
numberOfInputs: 0,
|
|
67
|
+
numberOfInputs: 1,
|
|
51
68
|
numberOfOutputs: 1,
|
|
52
69
|
outputChannelCount: [buffer?.numberOfChannels ?? 1],
|
|
53
|
-
|
|
70
|
+
processorOptions: {
|
|
54
71
|
buffer:
|
|
55
72
|
buffer instanceof AudioBuffer
|
|
56
73
|
? Array.from({ length: buffer.numberOfChannels }, (_, channel) => buffer.getChannelData(channel))
|
|
57
74
|
: null,
|
|
58
75
|
position,
|
|
59
|
-
timestamp
|
|
76
|
+
timestamp: convertToContextFrame(context, timestamp)
|
|
60
77
|
}
|
|
61
78
|
}
|
|
62
79
|
);
|
|
63
80
|
|
|
81
|
+
let removeListener: null | (() => void) = null;
|
|
82
|
+
|
|
64
83
|
Object.defineProperties(audioWorkletNode, {
|
|
65
84
|
port: {
|
|
66
85
|
get(): TAnyTimedAudioBufferSourceNodeAudioWorkletNode['port'] {
|
|
67
86
|
throw new Error("The port of a TimedAudioBufferSourceNodeAudioWorkletNode can't be accessed.");
|
|
68
87
|
}
|
|
88
|
+
},
|
|
89
|
+
timingObject: {
|
|
90
|
+
get: () => timingObject,
|
|
91
|
+
set: (value: TAnyTimedAudioBufferSourceNodeAudioWorkletNode['timingObject']) => {
|
|
92
|
+
removeListener?.();
|
|
93
|
+
|
|
94
|
+
removeListener = null;
|
|
95
|
+
|
|
96
|
+
if (value === null) {
|
|
97
|
+
timingObject = value;
|
|
98
|
+
} else {
|
|
99
|
+
throw new TypeError('A TimingObject can only be set in the constructor.');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
69
102
|
}
|
|
70
103
|
});
|
|
71
104
|
|
|
105
|
+
if (timingObject !== null) {
|
|
106
|
+
removeListener = subscribeToTimingObject(audioWorkletNode, context, createAudioBufferSourceNode, timingObject);
|
|
107
|
+
}
|
|
108
|
+
|
|
72
109
|
return <TAnyTimedAudioBufferSourceNodeAudioWorkletNode>audioWorkletNode;
|
|
73
110
|
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
import { TNativeAudioWorkletNode } from 'standardized-audio-context';
|
|
2
|
+
import { ITimingObject } from 'timing-object';
|
|
2
3
|
|
|
3
|
-
export type TNativeTimedAudioBufferSourceNodeAudioWorkletNode = TNativeAudioWorkletNode
|
|
4
|
+
export type TNativeTimedAudioBufferSourceNodeAudioWorkletNode = TNativeAudioWorkletNode & {
|
|
5
|
+
timingObject: null | ITimingObject;
|
|
6
|
+
};
|
package/src/worklet/worklet.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// This is the minified and stringified code of the timed-audio-buffer-source-node-audio-worklet-processor package.
|
|
2
|
-
export const worklet = `(()=>{"use strict";class e extends AudioWorkletProcessor{constructor(e){let{numberOfInputs:t,numberOfOutputs:r,outputChannelCount:o,processorOptions:n}=e;var s;const
|
|
2
|
+
export const worklet = `(()=>{"use strict";class e extends AudioWorkletProcessor{constructor(e){let{numberOfInputs:t,numberOfOutputs:r,outputChannelCount:o,processorOptions:n}=e;var s;const i="object"==typeof n&&null!==n&&"buffer"in n?n.buffer:null;if(!(null===i||Array.isArray(i)&&i.every((e=>e instanceof Float32Array))))throw new Error("The buffer needs to be either null or an array with where each element is a Float32Array.");if(1!==t)throw new Error("The numberOfInputs must be 1.");if(1!==r)throw new Error("The numberOfOutputs must be 1.");const u=null!==(s=null==i?void 0:i.length)&&void 0!==s?s:1;if(void 0===o||1!==o.length||u!==o[0])throw new Error("The outputChannelCount must match the number of channels of the buffer.");const f="object"==typeof n&&null!==n&&"position"in n?n.position:0;if("number"!=typeof f)throw new Error('The position needs to be of type "number".');const h="object"==typeof n&&null!==n&&"timestamp"in n?n.timestamp:0;if("number"!=typeof h)throw new Error('The timestamp needs to be of type "number".');super(),this._buffer=i,this._position=f,this._timestamp=h}process(e,t){let[r]=e,[o]=t;if(r.length>0){const[e]=r;e.length>1&&(this._position=Math.round(e[0]),this._timestamp=Math.round(e[1]))}if(null!==this._buffer){const e=this._buffer.length;for(let t=0;t<e;t+=1){const e=this._buffer[t],r=o[t];for(let t=0;t<128;t+=1){const o=this._position+currentFrame-this._timestamp+t;o>=0&&o<e.length&&(r[t]=e[o])}}}return!0}}e.parameterDescriptors=[],registerProcessor("timed-audio-buffer-source-node-audio-worklet-processor",e)})();`; // tslint:disable-line:max-line-length
|