@webaudiomodules/sdk-parammgr
Version:
Parameter Manager SDK for WebAudioModules Plugin
336 lines (318 loc) • 15.8 kB
TypeScript
import { WamNodeOptions, WamParameterInfoMap, WamNode, WamParameterConfiguration, WamEvent, WebAudioModule, WamEventMap, WamParameter, WamProcessor, WamParameterInfo } from '@webaudiomodules/api';
import { TypedAudioWorkletNode, TypedAudioWorkletNodeOptions } from './TypedAudioWorklet';
export class AudioWorkletRegister {
/**
* Register a AudioWorklet processor in a closure,
* sending to AudioWorkletProcessor with an unique identifier
* avoiding double registration
*
* @param {string} moduleId if duplicated, the processor will not be readded.
* @param {(id: string, ...injections: any[]) => void} processor a serializable function that contains an AudioWorkletProcessor
* with its registration in the AudioWorkletGlobalScope
* @param {AudioWorklet} audioWorklet AudioWorklet instance
* @param {...any[]} injection this will be serialized and injected to the `processor` function
* @returns {Promise<void>} a Promise<void>
*/
static register(moduleId: string, processor: (id: string, ...injections: any[]) => void, audioWorklet: AudioWorklet, ...injection: any[]): Promise<void>;
}
export interface InternalParameterDescriptor {
/** `0` by default */
defaultValue?: number;
/** `0` by default */
minValue?: number;
/** `1` by default */
maxValue?: number;
/** `30` (1/30s for each change check) by default */
automationRate?: number;
/** The default event listener, the event will be fired when the param get changed */
onChange?: (value: number, previousValue: number) => any;
}
export type InternalParametersDescriptor<InternalParams extends string = string> = Record<InternalParams, AudioParam | InternalParameterDescriptor>;
export interface ParameterMappingTarget {
/** Source param's `[minValue, maxValue]` by default */
sourceRange?: [number, number];
/** Source param's `[minValue, maxValue]` by default */
targetRange?: [number, number];
}
export type ParametersMapping<Params extends string = string, InternalParams extends string = string> = Record<Params, Record<InternalParams, ParameterMappingTarget>>;
export interface ParametersMappingConfiguratorOptions<Params extends string = string, InternalParams extends string = string> {
paramsConfig?: Record<Params, WamParameterConfiguration>;
paramsMapping?: ParametersMapping<Params, InternalParams>;
internalParamsConfig?: InternalParametersDescriptor<InternalParams>;
groupId?: string;
instanceId?: string;
}
export type PromisifiedFunction<F extends (...args: any[]) => any> = (...args: Parameters<F>) => PromiseLike<ReturnType<F>>;
export type UnPromisifiedFunction<F extends (...args: any[]) => any> = (...args: Parameters<F>) => ReturnType<F> extends PromiseLike<infer P> ? P : ReturnType<F>;
export type PromisifiedFunctionMap<T> = {
[K in keyof T]: T[K] extends (...args: any[]) => any ? PromisifiedFunction<T[K]> : T[K];
};
export type UnPromisifiedFunctionMap<T> = {
[K in keyof T]: T[K] extends (...args: any[]) => any ? UnPromisifiedFunction<T[K]> : T[K];
};
export interface MessagePortRequest<M = Record<string, (...args: any[]) => any>, K extends keyof M = keyof M> {
id: number;
call: K;
args?: M[K] extends (...args: any[]) => any ? Parameters<M[K]> : M[K];
}
export interface MessagePortResponse<M = Record<string, any>, K extends keyof M = keyof M> {
id: number;
value?: M[K] extends (...args: any[]) => any ? ReturnType<M[K]> : M[K];
error?: Error;
}
export interface ParamMgrCallToProcessor extends UnPromisifiedFunctionMap<Pick<WamNode, 'destroy' | 'getCompensationDelay' | 'getParameterInfo' | 'getParameterValues' | 'scheduleEvents' | 'clearEvents'>> {
connectEvents(wamInstanceId: string, from: number): void;
disconnectEvents(wamInstanceId: string, from: number): void;
emitEvents(...events: WamEvent[]): void;
setParamsMapping(mapping: ParametersMapping): void;
getBuffer(): { lock: Int32Array, paramsBuffer: Float32Array };
}
export interface ParamMgrCallFromProcessor {
setBuffer(buffer: { lock: Int32Array, paramsBuffer: Float32Array }): void;
dispatchWamEvent(event: WamEvent): void;
}
export interface ParamMgrAudioWorkletOptions extends WamNodeOptions {
paramsConfig: WamParameterInfoMap;
paramsMapping: ParametersMapping;
internalParamsMinValues: number[];
internalParams: string[];
}
export interface ParamMgrOptions extends TypedAudioWorkletNodeOptions<ParamMgrAudioWorkletOptions> {
internalParamsConfig: InternalParametersDescriptor;
}
/**
* A `WamParameter` API-compatible `AudioParam` class/interface.
* All `AudioParam`s generated from the `ParamMgr` will inherit this class
*/
export interface MgrAudioParam extends AudioParam, WamParameter {
_info: WamParameterInfo;
// normalized version of methods
cancelAndHoldAtTime(cancelTime: number): MgrAudioParam;
cancelScheduledValues(cancelTime: number): MgrAudioParam;
exponentialRampToValueAtTime(value: number, endTime: number): MgrAudioParam;
exponentialRampToNormalizedValueAtTime(value: number, endTime: number): MgrAudioParam;
linearRampToValueAtTime(value: number, endTime: number): MgrAudioParam;
linearRampToNormalizedValueAtTime(value: number, endTime: number): MgrAudioParam;
setTargetAtTime(target: number, startTime: number, timeConstant: number): MgrAudioParam;
setNormalizedTargetAtTime(target: number, startTime: number, timeConstant: number): MgrAudioParam;
setValueAtTime(value: number, startTime: number): MgrAudioParam;
setNormalizedValueAtTime(value: number, startTime: number): MgrAudioParam;
setValueCurveAtTime(values: number[] | Float32Array | Iterable<number>, startTime: number, duration: number): MgrAudioParam;
setNormalizedValueCurveAtTime(values: number[] | Float32Array | Iterable<number>, startTime: number, duration: number): MgrAudioParam;
}
export const MgrAudioParam: {
prototype: MgrAudioParam;
};
// ParamMgrNode
export interface ParamMgrNodeMsgIn extends MessagePortResponse<ParamMgrCallToProcessor>, MessagePortRequest<ParamMgrCallFromProcessor> {}
export interface ParamMgrNodeMsgOut extends MessagePortRequest<ParamMgrCallToProcessor>, MessagePortResponse<ParamMgrCallFromProcessor> {}
/**
* Parameter Manager is an implementation of `WamNode`,
* it uses native `WebAudio` `AudioParam` to adapt `WamParameter` API for automations.
* It can be used to create automatable values that will be changed with two methods:
*
* 1. if the automated value is an `AudioParam`:
*
* According to the `WebAudio` [Spec](https://webaudio.github.io/web-audio-api/#computation-of-value),
* the `computedValue` of the automated `AudioParam` is the sum of its `paramIntrinsicValue` (`value` attribute) and its audio input.
* The `ParamMgr` uses this property to automate `AudioParam`s.
* It will create corresponding audio output that is connected to the automated `AudioParam`.
*
* Meanwhile, the `paramIntrinsicValue` will be set to its `minValue`.
*
* Note: as the automated `AudioParam` value is fixed, to get its actual value, please use `getIParamValue()` method.
* `BiquadFilterNode.getFrequencyResponse()` will not work if its `AudioParam`s are automated in this case.
*
* 2. if the automated value is not an `AudioParam`
*
* While setting up the `ParamMgr`, user can provide an `onChange` callback for any furthur opertion
* along with an `automationRate` in milliseconds as the frequency of calling the callback if the value has been changed.
*
* The rate cannot succeed `k-rate` as the function call on the main thread.
*/
export interface ParamMgrNode<Params extends string = string, InternalParams extends string = Params> extends TypedAudioWorkletNode<ParamMgrNodeMsgIn, ParamMgrNodeMsgOut, Params, WamEventMap>, Omit<WamNode, keyof AudioWorkletNode>, ParamMgrCallFromProcessor {
readonly module: WebAudioModule;
/**
* The state of the initialization.
*/
readonly initialized: boolean;
/**
* An array that contains ordered internal params names.
* The order is important for the output connections and for the parameters' values buffer
* @deprecated
*/
readonly internalParams: InternalParams[];
/**
* The plugin's internal parameters description.
* Used for denormalize normalized exposed parameters values
*/
readonly internalParamsConfig: InternalParametersDescriptor<InternalParams>;
/**
* The lock will be true if the `$paramsBuffer` is changing by the processor.
* This is a view of a `SharedArrayBuffer`
* @deprecated
*/
readonly $lock: Int32Array;
/**
* The values of internal parameters,
* contains one value for each param,
* will be updated each `AudioWorklet` buffer.
* This is a view of a `SharedArrayBuffer`
* @deprecated
*/
readonly $paramsBuffer: Float32Array;
/**
* Previous params value since last event dispatch of any
* non-AudioParam internal parameters
* @deprecated
*/
readonly $prevParamsBuffer: Float32Array;
/**
* Event dispatch callbacks reference of the `setTimeout` calls.
* Used to clear the callbacks while destroying the plugin.
* @deprecated
*/
readonly paramsUpdateCheckFnRef: number[];
/**
* Event dispatch callback functions bound to specific values for the parameter.
* @deprecated
*/
readonly paramsUpdateCheckFn: number[];
/**
* waiting for the processor that gives the `paramsBuffer` `SharedArrayBuffer`
*/
initialize(): Promise<ParamMgrNode>;
/**
* convert an WebAudio time stamp to frame index
*/
convertTimeToFrame(time: number): number;
/**
* convert a frame index to WebAudio time stamp
*/
convertFrameToTime(frame: number): number;
/**
* Force to check if an internal param is updated to dispatch immediately value change event if necessary.
* Note that the event will also be throttled to the automation rate.
*/
requestDispatchIParamChange(name: InternalParams): void;
/**
* get the output index of an internal parameter from its name,
* null if not exist
*/
getIParamIndex(name: InternalParams): number | null;
/**
* connect an internal parameter audio output to an AudioParam or an AudioNode.
* Note that if the destination is declared in the `internalParamsConfig`,
* there is no need to reconnect it.
*/
connectIParam(name: InternalParams, dest: AudioParam | AudioNode, index?: number): void;
/**
* disonnect an internal parameter audio output to an AudioParam or an AudioNode.
*/
disconnectIParam(name: InternalParams, dest?: AudioParam | AudioNode, index?: number): void;
/**
* get the current value of an internal parameter
*/
getIParamValue(name: InternalParams): number;
/**
* get the current value of every internal parameters
*/
getIParamsValues(): Record<InternalParams, number>;
/**
* get the `AudioParam` instance of an exposed parameter
*/
getParam(name: Params): AudioParam;
/**
* get the `AudioParam` instance of every exposed parameters
*/
getParams(): Record<Params, AudioParam>;
/**
* get the current value of an exposed parameter,
* shorthand for `AudioParam.prototype.value`
*/
getParamValue(name: Params): number;
/**
* get the current value of an exposed parameter,
* shorthand for `AudioParam.prototype.value = value`
*/
setParamValue(name: Params, value: number): void;
/**
* get the current value of every exposed parameters
*/
getParamsValues(): Record<Params, number>;
/**
* set the current value of every exposed parameters
*/
setParamsValues(values: Partial<Record<Params, number>>): void;
/**
* normalized value version of `getParamValue()`
*/
getNormalizedParamValue(name: Params): number;
/**
* normalized value version of `setParamValue()`
*/
setNormalizedParamValue(name: Params, value: number): void;
/**
* normalized value version of `getParamsValues()`
*/
getNormalizedParamsValues(): Partial<Record<Params, number>>;
/**
* normalized value version of `setParamsValues()`
*/
setNormalizedParamsValues(values: Record<Params, number>): void;
// `AudioParam.prototype` methods with there normlized value version
setParamValueAtTime(name: Params, value: number, startTime: number): AudioParam;
setNormalizedParamValueAtTime(name: Params, value: number, startTime: number): AudioParam;
linearRampToParamValueAtTime(name: Params, value: number, endTime: number): AudioParam;
linearRampToNormalizedParamValueAtTime(name: Params, value: number, endTime: number): AudioParam;
exponentialRampToParamValueAtTime(name: Params, value: number, endTime: number): AudioParam;
exponentialRampToNormalizedParamValueAtTime(name: Params, value: number, endTime: number): AudioParam;
setParamTargetAtTime(name: Params, target: number, startTime: number, timeConstant: number): AudioParam;
setNormalizedParamTargetAtTime(name: Params, target: number, startTime: number, timeConstant: number): AudioParam;
setParamValueCurveAtTime(name: Params, values: Iterable<number> | number[] | Float32Array, startTime: number, duration: number): AudioParam;
setNormalizedParamValueCurveAtTime(name: Params, values: Iterable<number> | number[] | Float32Array, startTime: number, duration: number): AudioParam;
cancelScheduledParamValues(name: Params, cancelTime: number): AudioParam;
cancelAndHoldParamAtTime(name: Params, cancelTime: number): AudioParam;
}
export const ParamMgrNode: {
prototype: ParamMgrNode;
/**
* Creates an instance of ParamMgrNode.
*
* @param {WebAudioModule} module WebAudioModule
* @param {ParamMgrOptions} options AudioWorkletNode options
*/
new <Params extends string = string, InternalParams extends string = string>(
module: WebAudioModule,
options: ParamMgrOptions
): ParamMgrNode<Params, InternalParams>;
};
export interface ParamMgrProcessor extends WamProcessor {
handleEvent?: (event: WamEvent) => any;
}
/**
* Use `create` static method to create a new `ParamMgr` instance
*/
export const ParamMgrFactory: {
/**
* Get a ParamManager as an AudioWorkletNode instance
*
* The second argument `optionsIn` decides how `ParamMgr` should automate parameters and generate `WamParameter`-compatible `AudioParam`s.
*
* The option could have three possible properties: `paramsConfig`, `paramsMapping` and `internalParamsConfig`.
*
* If you do not have to configure one-to-many parameters, please declare `internalParamsConfig` only,
* where you can put an `AudioParam` or an object that contains default, min, max values, automation rate with the `onChange` callback.
* The factory will generate automatically automatable `AudioParam`s for you.
*
* Else, you can declare `paramsConfig` with exposed parameters' configs.
* The omitted properties will be filled according the internal parameter with the same name.
* In the `paramsMapping`, you can declare how one-to-many parameters maps values to the internal parameters.
* @param {WebAudioModule} module the module instance
* @param {ParametersMappingConfiguratorOptions} [optionsIn = {}] config of the parameters
*/
create<Params extends string = string, InternalParams extends string = string>(module: WebAudioModule, optionsIn?: ParametersMappingConfiguratorOptions<Params, InternalParams>): Promise<ParamMgrNode<Params, InternalParams>>;
};
export interface WamParamMgrSDKBaseModuleScope {
paramMgrProcessors?: { [instanceId: string]: ParamMgrProcessor };
}