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( (v) => plugin.setParameter(paramId, v), [plugin, paramId] ); const curve = useCallback( (c) => plugin.setParameterCurve(paramId, c), [plugin, paramId] ); const scheduleAt = useCallback( (v, t) => plugin.setParameterAt(paramId, v, t), [plugin, paramId] ); return { value, set, curve, scheduleAt }; }