Initial Commit
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
import type {
|
||||
AudioFxPlugin,
|
||||
ParameterCurve,
|
||||
} from "@suaveplan/audio-fx-plugin-base";
|
||||
import { useCallback, useSyncExternalStore } from "react";
|
||||
import {
|
||||
REACT_AUDIO_CODES,
|
||||
ReactAudioError,
|
||||
} from "../../error-codes/error-codes.js";
|
||||
import { useProviderStateOrThrow } from "../use-provider-state.js";
|
||||
|
||||
export interface UseParameterResult {
|
||||
readonly value: number;
|
||||
set(value: number): void;
|
||||
curve(curve: ParameterCurve): void;
|
||||
scheduleAt(value: number, transportTimeSec: number): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads, writes, curves, and schedules a single plugin parameter.
|
||||
*
|
||||
* - `value` is sampled at the provider's `sampleRateHz` (default 60),
|
||||
* matching the per-block parameter automation cadence to the UI's
|
||||
* frame budget.
|
||||
* - `set` calls `plugin.setParameter`.
|
||||
* - `curve` calls `plugin.setParameterCurve`.
|
||||
* - `scheduleAt` calls `plugin.setParameterAt`.
|
||||
*
|
||||
* Throws `REACT_AUDIO.UNKNOWN_PARAMETER` synchronously on first
|
||||
* render when the supplied `paramId` is not present in the plugin's
|
||||
* `parameterIndex`.
|
||||
*/
|
||||
export function useParameter(
|
||||
plugin: AudioFxPlugin,
|
||||
paramId: string
|
||||
): UseParameterResult {
|
||||
const { sampleRateHz } = useProviderStateOrThrow();
|
||||
|
||||
if (!plugin.parameterIndex.has(paramId)) {
|
||||
throw new ReactAudioError(
|
||||
REACT_AUDIO_CODES.UNKNOWN_PARAMETER,
|
||||
"react-audio.unknown-parameter",
|
||||
{
|
||||
context: {
|
||||
paramId,
|
||||
pluginId: plugin.metadata.id,
|
||||
available: Array.from(plugin.parameterIndex.keys()),
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const subscribe = useCallback(
|
||||
(listener: () => void) => {
|
||||
const interval = Math.max(1, Math.floor(1000 / sampleRateHz));
|
||||
const id = setInterval(() => {
|
||||
listener();
|
||||
}, interval);
|
||||
return () => {
|
||||
clearInterval(id);
|
||||
};
|
||||
},
|
||||
[sampleRateHz]
|
||||
);
|
||||
|
||||
const getSnapshot = useCallback(
|
||||
() => plugin.getParameter(paramId),
|
||||
[plugin, paramId]
|
||||
);
|
||||
|
||||
const value = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
||||
|
||||
const set = useCallback<UseParameterResult["set"]>(
|
||||
(v) => plugin.setParameter(paramId, v),
|
||||
[plugin, paramId]
|
||||
);
|
||||
const curve = useCallback<UseParameterResult["curve"]>(
|
||||
(c) => plugin.setParameterCurve(paramId, c),
|
||||
[plugin, paramId]
|
||||
);
|
||||
const scheduleAt = useCallback<UseParameterResult["scheduleAt"]>(
|
||||
(v, t) => plugin.setParameterAt(paramId, v, t),
|
||||
[plugin, paramId]
|
||||
);
|
||||
|
||||
return { value, set, curve, scheduleAt };
|
||||
}
|
||||
Reference in New Issue
Block a user