@jadujoel/web-audio-clip-node 0.1.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.
Files changed (38) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +91 -0
  3. package/dist/audio/ClipNode.d.ts +86 -0
  4. package/dist/audio/processor-code.d.ts +1 -0
  5. package/dist/audio/processor-kernel.d.ts +43 -0
  6. package/dist/audio/processor.d.ts +1 -0
  7. package/dist/audio/types.d.ts +192 -0
  8. package/dist/audio/utils.d.ts +22 -0
  9. package/dist/audio/workletUrl.d.ts +6 -0
  10. package/dist/components/AudioControl.d.ts +28 -0
  11. package/dist/components/ContextMenu.d.ts +17 -0
  12. package/dist/components/ControlSection.d.ts +26 -0
  13. package/dist/components/DetuneControl.d.ts +10 -0
  14. package/dist/components/DisplayPanel.d.ts +14 -0
  15. package/dist/components/FilterControl.d.ts +12 -0
  16. package/dist/components/GainControl.d.ts +10 -0
  17. package/dist/components/PanControl.d.ts +10 -0
  18. package/dist/components/PlaybackRateControl.d.ts +10 -0
  19. package/dist/components/PlayheadSlider.d.ts +13 -0
  20. package/dist/components/SnappableSlider.d.ts +18 -0
  21. package/dist/components/TransportButtons.d.ts +14 -0
  22. package/dist/controls/controlDefs.d.ts +31 -0
  23. package/dist/controls/formatValueText.d.ts +2 -0
  24. package/dist/controls/linkedControlPairs.d.ts +20 -0
  25. package/dist/data/cache.d.ts +1 -0
  26. package/dist/data/fileStore.d.ts +6 -0
  27. package/dist/hooks/useClipNode.d.ts +31 -0
  28. package/dist/lib-react.d.ts +15 -0
  29. package/dist/lib-react.js +19 -0
  30. package/dist/lib-react.js.map +9 -0
  31. package/dist/lib.d.ts +16 -0
  32. package/dist/lib.js +44 -0
  33. package/dist/lib.js.map +9 -0
  34. package/dist/processor.js +4 -0
  35. package/dist/processor.js.map +12 -0
  36. package/dist/store/clipStore.d.ts +63 -0
  37. package/dist/styles.css +739 -0
  38. package/package.json +87 -0
@@ -0,0 +1,13 @@
1
+ export interface PlayheadSliderProps {
2
+ /** Current playhead position in samples. */
3
+ value: number;
4
+ /** Audio duration in seconds (null when no audio loaded). */
5
+ audioDuration: number | null;
6
+ /** Whether playback is active (started/paused). */
7
+ disabled?: boolean;
8
+ /** Called when the user seeks to a new position (value in samples). */
9
+ onChange: (samplePosition: number) => void;
10
+ }
11
+ declare function PlayheadSliderInner({ value, audioDuration, disabled, onChange, }: PlayheadSliderProps): import("react/jsx-runtime").JSX.Element;
12
+ export declare const PlayheadSlider: import("react").MemoExoticComponent<typeof PlayheadSliderInner>;
13
+ export {};
@@ -0,0 +1,18 @@
1
+ export interface SnappableSliderProps {
2
+ min: number;
3
+ max: number;
4
+ value: number;
5
+ skew?: number;
6
+ step?: number;
7
+ defaultValue?: number;
8
+ enableSnap?: boolean;
9
+ snaps?: number[];
10
+ ticks?: number[];
11
+ logarithmic?: boolean;
12
+ disabled?: boolean;
13
+ labelId?: string;
14
+ valueText?: string;
15
+ formatTick?: (value: number) => string;
16
+ onChange?: (value: number) => void;
17
+ }
18
+ export declare function SnappableSlider({ min, max, value, skew, step, defaultValue, enableSnap, snaps, ticks, logarithmic, disabled, labelId, valueText, formatTick, onChange, }: SnappableSliderProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,14 @@
1
+ import type { ClipNodeState } from "../audio/types";
2
+ interface TransportButtonsProps {
3
+ nodeState: ClipNodeState;
4
+ onStart: () => void;
5
+ onStop: () => void;
6
+ onPause: () => void;
7
+ onResume: () => void;
8
+ onDispose: () => void;
9
+ onLog: () => void;
10
+ onLoadSound: () => void;
11
+ }
12
+ declare function TransportButtonsInner({ nodeState, onStart, onStop, onPause, onResume, onDispose, onLog, onLoadSound, }: TransportButtonsProps): import("react/jsx-runtime").JSX.Element;
13
+ export declare const TransportButtons: import("react").MemoExoticComponent<typeof TransportButtonsInner>;
14
+ export {};
@@ -0,0 +1,31 @@
1
+ export type ControlKey = "playhead" | "offset" | "duration" | "startDelay" | "stopDelay" | "fadeIn" | "fadeOut" | "loopStart" | "loopEnd" | "loopCrossfade" | "playbackRate" | "detune" | "gain" | "pan" | "lowpass" | "highpass";
2
+ export interface ControlDef {
3
+ key: ControlKey;
4
+ label: string;
5
+ min: number;
6
+ max: number;
7
+ defaultValue: number;
8
+ precision?: number;
9
+ snap?: string;
10
+ preset?: string;
11
+ title?: string;
12
+ hasToggle?: boolean;
13
+ hasSnap?: boolean;
14
+ hasMaxLock?: boolean;
15
+ /** When true, max defaults to audio file duration. */
16
+ maxLockedByDefault?: boolean;
17
+ }
18
+ export declare const DEFAULT_TEMPO = 120;
19
+ export declare const SAMPLE_RATE = 48000;
20
+ export declare const controlDefs: ControlDef[];
21
+ export declare const loopControlDefs: ControlDef[];
22
+ export declare const paramDefs: ControlDef[];
23
+ export declare const allDefs: ControlDef[];
24
+ export declare function buildDefaults(): {
25
+ values: Record<ControlKey, number>;
26
+ snaps: Record<ControlKey, string>;
27
+ enabled: Record<ControlKey, boolean>;
28
+ mins: Record<ControlKey, number>;
29
+ maxs: Record<ControlKey, number>;
30
+ maxLocked: Record<ControlKey, boolean>;
31
+ };
@@ -0,0 +1,2 @@
1
+ export declare function formatValueText(value: number, key: string | undefined, snap: string, tempo: number): string;
2
+ export declare function formatTickLabel(value: number, key: string | undefined, snap: string, tempo: number): string;
@@ -0,0 +1,20 @@
1
+ import type { ControlKey } from "./controlDefs";
2
+ export type LinkedControlPairKey = "fadeOutStopDelay" | "loopStartEnd";
3
+ export interface LinkedControlPairDef {
4
+ key: LinkedControlPairKey;
5
+ label: string;
6
+ controls: readonly [ControlKey, ControlKey];
7
+ }
8
+ export declare const transportLinkedControlPairs: readonly LinkedControlPairDef[];
9
+ export declare const loopLinkedControlPairs: readonly LinkedControlPairDef[];
10
+ export declare function buildLinkedControlPairDefaults(): Record<LinkedControlPairKey, boolean>;
11
+ export declare function getLinkedControlPairForControl(controlKey: ControlKey): LinkedControlPairDef | undefined;
12
+ export declare function getActiveLinkedControls(controlKey: ControlKey, linkedPairs: Record<LinkedControlPairKey, boolean>): readonly ControlKey[];
13
+ export declare function getLinkedControlUpdates({ pair, changedKey, nextValue, values, mins, maxs, }: {
14
+ pair: LinkedControlPairDef;
15
+ changedKey: ControlKey;
16
+ nextValue: number;
17
+ values: Record<ControlKey, number>;
18
+ mins: Record<ControlKey, number>;
19
+ maxs: Record<ControlKey, number>;
20
+ }): Partial<Record<ControlKey, number>>;
@@ -0,0 +1 @@
1
+ export declare function loadFromCache(url: string): Promise<ArrayBuffer | undefined>;
@@ -0,0 +1,6 @@
1
+ export interface StoredFile {
2
+ name: string;
3
+ arrayBuffer: ArrayBuffer;
4
+ }
5
+ export declare function saveUploadedFile(name: string, arrayBuffer: ArrayBuffer): Promise<void>;
6
+ export declare function loadUploadedFile(): Promise<StoredFile | null>;
@@ -0,0 +1,31 @@
1
+ import type { ClipNodeState } from "../audio/types";
2
+ import type { ControlKey } from "../controls/controlDefs";
3
+ interface UseClipNodeParams {
4
+ values: Record<ControlKey, number>;
5
+ enabled: Record<ControlKey, boolean>;
6
+ loop: boolean;
7
+ setValue: (key: ControlKey, val: number) => void;
8
+ }
9
+ export declare function useClipNode({ values, enabled, loop, setValue, }: UseClipNodeParams): {
10
+ nodeState: ClipNodeState;
11
+ statusMessage: string | null;
12
+ soundName: string | null;
13
+ audioDuration: number | null;
14
+ infoCurrentTime: string;
15
+ infoCurrentFrame: string;
16
+ infoTimesLooped: string;
17
+ infoLatency: string;
18
+ infoTimeTaken: string;
19
+ start: () => Promise<void>;
20
+ stop: () => void;
21
+ pause: () => void;
22
+ resume: () => void;
23
+ dispose: () => void;
24
+ logState: () => void;
25
+ loadSound: () => void;
26
+ applyValue: (key: ControlKey, val: number) => void;
27
+ applyValues: (valuesToApply: Partial<Record<ControlKey, number>>) => void;
28
+ applyToggle: (key: ControlKey, on: boolean) => void;
29
+ setLoopOnNode: (checked: boolean) => void;
30
+ };
31
+ export {};
@@ -0,0 +1,15 @@
1
+ export { AudioControl } from "./components/AudioControl";
2
+ export { ContextMenu } from "./components/ContextMenu";
3
+ export { ControlSection } from "./components/ControlSection";
4
+ export { DetuneControl } from "./components/DetuneControl";
5
+ export { DisplayPanel } from "./components/DisplayPanel";
6
+ export { FilterControl } from "./components/FilterControl";
7
+ export { GainControl } from "./components/GainControl";
8
+ export { PanControl } from "./components/PanControl";
9
+ export { PlaybackRateControl } from "./components/PlaybackRateControl";
10
+ export { PlayheadSlider } from "./components/PlayheadSlider";
11
+ export { SnappableSlider } from "./components/SnappableSlider";
12
+ export { TransportButtons } from "./components/TransportButtons";
13
+ export { useClipNode } from "./hooks/useClipNode";
14
+ export type { ClipControlsState } from "./store/clipStore";
15
+ export { useClipControls } from "./store/clipStore";
@@ -0,0 +1,19 @@
1
+ export {
2
+ useClipNode,
3
+ useClipControls,
4
+ TransportButtons,
5
+ SnappableSlider,
6
+ PlayheadSlider,
7
+ PlaybackRateControl,
8
+ PanControl,
9
+ GainControl,
10
+ FilterControl,
11
+ DisplayPanel,
12
+ DetuneControl,
13
+ ControlSection,
14
+ ContextMenu,
15
+ AudioControl
16
+ };
17
+
18
+ //# debugId=030B87E04A0B95F064756E2164756E21
19
+ //# sourceMappingURL=lib-react.js.map
@@ -0,0 +1,9 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [
5
+ ],
6
+ "mappings": "",
7
+ "debugId": "030B87E04A0B95F064756E2164756E21",
8
+ "names": []
9
+ }
package/dist/lib.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ export { ClipNode } from "./audio/ClipNode";
2
+ export { processorCode } from "./audio/processor-code";
3
+ export { createFilterState, getProperties, handleProcessorMessage, processBlock, SAMPLE_BLOCK_SIZE, } from "./audio/processor-kernel";
4
+ export type { BufferRangeWrite, ClipNodeState, ClipProcessorOptions, ClipProcessorState, ClipProcessorToggleMessageType, ClipWorkletOptions, FrameData, StreamBufferSpan, StreamBufferState, } from "./audio/types";
5
+ export { State } from "./audio/types";
6
+ export type { SliderPreset, TempoRelativeSnap } from "./audio/utils";
7
+ export { audioBufferFromFloat32Array, dbFromLin, float32ArrayFromAudioBuffer, generateSnapPoints, getSnappedValue, getTempoSnapInterval, isTempoRelativeSnap, linFromDb, presets, remapTempoRelativeValue, } from "./audio/utils";
8
+ export { getProcessorBlobUrl, getProcessorCdnUrl, getProcessorModuleUrl, } from "./audio/workletUrl";
9
+ export type { ControlDef, ControlKey } from "./controls/controlDefs";
10
+ export { allDefs, buildDefaults, controlDefs, DEFAULT_TEMPO, loopControlDefs, paramDefs, SAMPLE_RATE, } from "./controls/controlDefs";
11
+ export { formatTickLabel, formatValueText } from "./controls/formatValueText";
12
+ export type { LinkedControlPairDef, LinkedControlPairKey, } from "./controls/linkedControlPairs";
13
+ export { buildLinkedControlPairDefaults, getActiveLinkedControls, getLinkedControlPairForControl, getLinkedControlUpdates, loopLinkedControlPairs, transportLinkedControlPairs, } from "./controls/linkedControlPairs";
14
+ export { loadFromCache } from "./data/cache";
15
+ export type { StoredFile } from "./data/fileStore";
16
+ export { loadUploadedFile, saveUploadedFile } from "./data/fileStore";
package/dist/lib.js ADDED
@@ -0,0 +1,44 @@
1
+ export {
2
+ transportLinkedControlPairs,
3
+ saveUploadedFile,
4
+ remapTempoRelativeValue,
5
+ processorCode,
6
+ processBlock,
7
+ presets,
8
+ paramDefs,
9
+ loopLinkedControlPairs,
10
+ loopControlDefs,
11
+ loadUploadedFile,
12
+ loadFromCache,
13
+ linFromDb,
14
+ isTempoRelativeSnap,
15
+ handleProcessorMessage,
16
+ getTempoSnapInterval,
17
+ getSnappedValue,
18
+ getProperties,
19
+ getProcessorModuleUrl,
20
+ getProcessorCdnUrl,
21
+ getProcessorBlobUrl,
22
+ getLinkedControlUpdates,
23
+ getLinkedControlPairForControl,
24
+ getActiveLinkedControls,
25
+ generateSnapPoints,
26
+ formatValueText,
27
+ formatTickLabel,
28
+ float32ArrayFromAudioBuffer,
29
+ dbFromLin,
30
+ createFilterState,
31
+ controlDefs,
32
+ buildLinkedControlPairDefaults,
33
+ buildDefaults,
34
+ audioBufferFromFloat32Array,
35
+ allDefs,
36
+ State,
37
+ SAMPLE_RATE,
38
+ SAMPLE_BLOCK_SIZE,
39
+ DEFAULT_TEMPO,
40
+ ClipNode
41
+ };
42
+
43
+ //# debugId=9B64F311A83C9C3D64756E2164756E21
44
+ //# sourceMappingURL=lib.js.map
@@ -0,0 +1,9 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [
5
+ ],
6
+ "mappings": "",
7
+ "debugId": "9B64F311A83C9C3D64756E2164756E21",
8
+ "names": []
9
+ }
@@ -0,0 +1,4 @@
1
+ var z={Initial:0,Started:1,Stopped:2,Paused:3,Scheduled:4,Ended:5,Disposed:6};var y=128;function i(V=[]){let A=V[0]?.length??0,F=A>0;return{totalLength:F?A:null,committedLength:F?A:0,streamEnded:F,streaming:!1,writtenSpans:F?[{startSample:0,endSample:A}]:[],pendingWrites:[],lowWaterThreshold:y*4,lowWaterNotified:!1,lastUnderrunSample:null}}function M0(V){return V[0]?.length??0}function o(V){return V.streamBuffer.totalLength??M0(V.buffer)}function G0(V,A){return Array.from({length:V},()=>new Float32Array(A))}function E0(V,A){let F=[...V,A].sort((Q,J)=>Q.startSample-J.startSample),T=[];for(let Q of F){let J=T[T.length-1];if(!J||Q.startSample>J.endSample){T.push({...Q});continue}J.endSample=Math.max(J.endSample,Q.endSample)}return T}function I0(V){let A=0;for(let F of V){if(F.startSample>A)break;A=Math.max(A,F.endSample)}return A}function w0(V,A){if(V.committedLength-Math.floor(A)>=V.lowWaterThreshold)V.lowWaterNotified=!1}function R0(V,A,F){let T=M0(V.buffer),Q=V.buffer.length;if(T>=F&&Q>=A)return;let J=Math.max(T,F),U=Math.max(Q,A),Y=G0(U,J);for(let X=0;X<Q;X++)Y[X].set(V.buffer[X].subarray(0,T));if(V.buffer=Y,V.streamBuffer.totalLength==null||V.streamBuffer.totalLength<J)V.streamBuffer.totalLength=J}function B0(V,A){let F=Math.max(Math.floor(A.startSample),0),T=A.channelData[0]?.length??0,Q=A.totalLength??null,J=Math.max(F+T,Q??0);R0(V,Math.max(A.channelData.length,V.buffer.length,1),J);for(let U=0;U<A.channelData.length;U++)V.buffer[U].set(A.channelData[U],F);if(Q!=null)V.streamBuffer.totalLength=Q;if(T>0)V.streamBuffer.writtenSpans=E0(V.streamBuffer.writtenSpans,{startSample:F,endSample:F+T}),V.streamBuffer.committedLength=I0(V.streamBuffer.writtenSpans);if(A.streamEnded===!0)V.streamBuffer.streamEnded=!0;w0(V.streamBuffer,V.playhead)}function _0(V){if(V.streamBuffer.pendingWrites.length===0)return;for(let A of V.streamBuffer.pendingWrites)B0(V,A);V.streamBuffer.pendingWrites=[]}function y0(V,A){V.buffer=A,V.streamBuffer=i(A)}function v0(V={},A){let{buffer:F=[],streamBuffer:T=i(F),duration:Q=-1,loop:J=!1,loopStart:U=0,loopEnd:Y=(F[0]?.length??0)/A,loopCrossfade:X=0,playhead:k=0,offset:H=0,startWhen:$=0,stopWhen:j=0,pauseWhen:P=0,resumeWhen:C=0,playedSamples:N=0,state:K=z.Initial,timesLooped:w=0,fadeInDuration:v=0,fadeOutDuration:Z=0,enableFadeIn:E=v>0,enableFadeOut:O=Z>0,enableLoopStart:R=!0,enableLoopEnd:h=!0,enableLoopCrossfade:b=X>0,enableHighpass:c=!0,enableLowpass:g=!0,enableGain:s=!0,enablePan:r=!0,enableDetune:t=!0,enablePlaybackRate:p=!0}=V;return{buffer:F,streamBuffer:T,loop:J,loopStart:U,loopEnd:Y,loopCrossfade:X,duration:Q,playhead:k,offset:H,startWhen:$,stopWhen:j,pauseWhen:P,resumeWhen:C,playedSamples:N,state:K,timesLooped:w,fadeInDuration:v,fadeOutDuration:Z,enableFadeIn:E,enableFadeOut:O,enableLoopStart:R,enableLoopEnd:h,enableHighpass:c,enableLowpass:g,enableGain:s,enablePan:r,enableDetune:t,enablePlaybackRate:p,enableLoopCrossfade:b}}function b0(V,A){return o(V)/A}function n(V,A){let F=b0(V,A);if(F<=0){V.loopStart=0,V.loopEnd=0;return}if(!Number.isFinite(V.loopStart)||V.loopStart<0)V.loopStart=0;if(V.loopStart>=F)V.loopStart=0;if(!Number.isFinite(V.loopEnd)||V.loopEnd<=V.loopStart||V.loopEnd>F)V.loopEnd=F}function e(V,A,F){if(A===void 0)return V.offset=0,0;if(A<0)return e(V,o(V)+A,F);if(A>(o(V)||1)-1)return e(V,o(V)%A,F);let T=Math.floor(A*F);return V.offset=T,T}function L0(V){let{playhead:A,bufferLength:F,loop:T,loopStartSamples:Q,loopEndSamples:J}=V,U=128;if(!T&&A+128>F)U=Math.max(F-A,0);let Y=Array(U);if(!T){for(let $=0,j=A;$<U;$++,j++)Y[$]=j;let H=A+U;return{playhead:H,indexes:Y,looped:!1,ended:H>=F}}let X=A,k=!1;for(let H=0;H<U;H++,X++){if(X>=J)X=Q+(X-J),k=!0;Y[H]=X}return{indexes:Y,looped:k,ended:!1,playhead:X}}function x0(V){let{playhead:A,bufferLength:F,loop:T,loopStartSamples:Q,loopEndSamples:J,playbackRates:U}=V,Y=128;if(!T&&A+128>F)Y=Math.max(F-A,0);let X=Array(Y),k=A,H=!1;if(T){for(let $=0;$<Y;$++){X[$]=Math.min(Math.max(Math.floor(k),0),F-1);let j=U[$]??U[0]??1;if(k+=j,j>=0&&(k>J||k>F))k=Q,H=!0;else if(j<0&&(k<Q||k<0))k=J,H=!0}return{playhead:k,indexes:X,looped:H,ended:!1}}for(let $=0;$<Y;$++)X[$]=Math.min(Math.max(Math.floor(k),0),F-1),k+=U[$]??U[0]??1;return{playhead:k,indexes:X,looped:!1,ended:k>=F||k<0}}function m0(V,A,F){for(let T=0;T<F.length;T++)for(let Q=0;Q<V.length;Q++)V[Q][T]=A[Q][F[T]];for(let T=F.length;T<V[0].length;T++)for(let Q=0;Q<V.length;Q++)V[Q][T]=0}function d(V){for(let A=0;A<V.length;A++)for(let F=0;F<V[A].length;F++)V[A][F]=0}function S0(V){let A=new Float32Array(V[0].length);for(let F=0;F<V[0].length;F++)A[F]=V[0][F];V.push(A)}function H0(V,A){for(let F=A.length;F<V.length;F++)A[F]=new Float32Array(V[F].length);for(let F=0;F<V.length;F++)for(let T=0;T<V[F].length;T++)A[F][T]=V[F][T]}function c0(V){let A=0;for(let F=0;F<V.length;F++)for(let T=0;T<V[F].length;T++)if(Number.isNaN(V[F][T]))A++,V[F][T]=0;return A}function V0(){return[{x_1:0,x_2:0,y_1:0,y_2:0},{x_1:0,x_2:0,y_1:0,y_2:0}]}function g0(V,A){if(A.length===1){let T=A[0];if(T===1)return;for(let Q of V)for(let J=0;J<Q.length;J++)Q[J]*=T;return}let F=A[0];for(let T of V)for(let Q=0;Q<T.length;Q++)F=A[Q]??F,T[Q]*=F}function d0(V,A){let F=A[0];for(let T=0;T<V[0].length;T++){F=A[T]??F;let Q=F<=0?1:1-F,J=F>=0?1:1+F;V[0][T]*=Q,V[1][T]*=J}}function h0(V,A,F,T){for(let Q=0;Q<V.length;Q++){let J=V[Q],{x_1:U,x_2:Y,y_1:X,y_2:k}=T[Q]??{x_1:0,x_2:0,y_1:0,y_2:0};if(A.length===1){let H=A[0];if(H>=20000)return;let $=2*Math.PI*H/F,j=Math.sin($)/2,P=(1-Math.cos($))/2,C=1-Math.cos($),N=(1-Math.cos($))/2,K=1+j,w=-2*Math.cos($),v=1-j,Z=P/K,E=C/K,O=N/K,R=w/K,h=v/K;for(let b=0;b<J.length;b++){let c=J[b],g=Z*c+E*U+O*Y-R*X-h*k;Y=U,U=c,k=X,X=g,J[b]=g}}else{let H=A[0];for(let $=0;$<J.length;$++){let j=A[$]??H,P=2*Math.PI*j/F,C=Math.sin(P)/2,N=(1-Math.cos(P))/2,K=1-Math.cos(P),w=(1-Math.cos(P))/2,v=1+C,Z=-2*Math.cos(P),E=1-C,O=J[$],R=N/v*O+K/v*U+w/v*Y-Z/v*X-E/v*k;Y=U,U=O,k=X,X=R,J[$]=R}}T[Q]={x_1:U,x_2:Y,y_1:X,y_2:k}}}function l0(V,A,F,T){for(let Q=0;Q<V.length;Q++){let J=V[Q],{x_1:U,x_2:Y,y_1:X,y_2:k}=T[Q]??{x_1:0,x_2:0,y_1:0,y_2:0};if(A.length===1){let H=A[0];if(H<=20)return;let $=2*Math.PI*H/F,j=Math.sin($)/2,P=(1+Math.cos($))/2,C=-(1+Math.cos($)),N=(1+Math.cos($))/2,K=1+j,w=-2*Math.cos($),v=1-j;for(let Z=0;Z<J.length;Z++){let E=J[Z],O=P/K*E+C/K*U+N/K*Y-w/K*X-v/K*k;Y=U,U=E,k=X,X=O,J[Z]=O}}else{let H=A[0];for(let $=0;$<J.length;$++){let j=A[$]??H,P=2*Math.PI*j/F,C=Math.sin(P)/2,N=(1+Math.cos(P))/2,K=-(1+Math.cos(P)),w=(1+Math.cos(P))/2,v=1+C,Z=-2*Math.cos(P),E=1-C,O=J[$],R=N/v*O+K/v*U+w/v*Y-Z/v*X-E/v*k;Y=U,U=O,k=X,X=R,J[$]=R}}T[Q]={x_1:U,x_2:Y,y_1:X,y_2:k}}}function z0(V,A,F,T){let{type:Q,data:J}=A;switch(Q){case"buffer":return y0(V,J),n(V,T),[];case"bufferInit":{let U=J;return V.buffer=G0(U.channels,U.totalLength),V.streamBuffer={...i(),totalLength:U.totalLength,streamEnded:!1,streaming:U.streaming??!0},n(V,T),[]}case"bufferRange":return V.streamBuffer.pendingWrites.push(J),[];case"bufferEnd":{let U=J;if(U?.totalLength!=null)V.streamBuffer.totalLength=U.totalLength;return V.streamBuffer.streamEnded=!0,[]}case"bufferReset":return V.buffer=[],V.streamBuffer=i(),n(V,T),[];case"start":V.timesLooped=0;{let U=J;if(V.duration=U?.duration??-1,V.duration===-1)V.duration=V.loop?Number.MAX_SAFE_INTEGER:(V.buffer[0]?.length??0)/T;e(V,U?.offset,T),n(V,T),V.playhead=V.offset,V.startWhen=U?.when??F,V.stopWhen=V.startWhen+V.duration,V.playedSamples=0,V.state=z.Scheduled}return[{type:"scheduled"}];case"stop":if(V.state===z.Ended||V.state===z.Initial)return[];return V.stopWhen=J??V.stopWhen,V.state=z.Stopped,[{type:"stopped"}];case"pause":return V.state=z.Paused,V.pauseWhen=J??F,[{type:"paused"}];case"resume":return V.state=z.Started,V.startWhen=J??F,[{type:"resume"}];case"dispose":return V.state=z.Disposed,V.buffer=[],V.streamBuffer=i(),[{type:"disposed"}];case"loop":{let U=J,Y=V.state;if(U&&(Y===z.Scheduled||Y===z.Started))V.stopWhen=Number.MAX_SAFE_INTEGER,V.duration=Number.MAX_SAFE_INTEGER;if(V.loop=U,U)n(V,T);return[]}case"loopStart":return V.loopStart=J,[];case"loopEnd":return V.loopEnd=J,[];case"loopCrossfade":return V.loopCrossfade=J,[];case"playhead":return V.playhead=Math.floor(J),[];case"fadeIn":return V.fadeInDuration=J,[];case"fadeOut":return V.fadeOutDuration=J,[];case"toggleGain":return V.enableGain=J??!V.enableGain,[];case"togglePan":return V.enablePan=J??!V.enablePan,[];case"toggleLowpass":return V.enableLowpass=J??!V.enableLowpass,[];case"toggleHighpass":return V.enableHighpass=J??!V.enableHighpass,[];case"toggleDetune":return V.enableDetune=J??!V.enableDetune,[];case"togglePlaybackRate":return V.enablePlaybackRate=J??!V.enablePlaybackRate,[];case"toggleFadeIn":return V.enableFadeIn=J??!V.enableFadeIn,[];case"toggleFadeOut":return V.enableFadeOut=J??!V.enableFadeOut,[];case"toggleLoopStart":return V.enableLoopStart=J??!V.enableLoopStart,[];case"toggleLoopEnd":return V.enableLoopEnd=J??!V.enableLoopEnd,[];case"toggleLoopCrossfade":return V.enableLoopCrossfade=J??!V.enableLoopCrossfade,[];case"logState":return[]}return[]}function j0(V,A,F,T,Q){let J=[],U=V.state;if(U===z.Disposed)return{keepAlive:!1,messages:J};if(_0(V),U===z.Initial)return{keepAlive:!0,messages:J};if(U===z.Ended)return d(A[0]),{keepAlive:!0,messages:J};if(U===z.Scheduled)if(T.currentTime>=V.startWhen)U=V.state=z.Started,J.push({type:"started"});else return d(A[0]),{keepAlive:!0,messages:J};else if(U===z.Paused){if(T.currentTime>V.pauseWhen)return d(A[0]),{keepAlive:!0,messages:J}}if(T.currentTime>V.stopWhen)return d(A[0]),V.state=z.Ended,J.push({type:"ended"}),V.playedSamples=0,{keepAlive:!0,messages:J};let Y=A[0],X=o(V);if(X===0)return d(Y),{keepAlive:!0,messages:J};let{playbackRate:k,detune:H,lowpass:$,highpass:j,gain:P,pan:C}=F,{buffer:N,loopStart:K,loopEnd:w,loopCrossfade:v,stopWhen:Z,playedSamples:E,enableLowpass:O,enableHighpass:R,enableGain:h,enablePan:b,enableDetune:c,enableFadeOut:g,enableFadeIn:s,enableLoopStart:r,enableLoopEnd:t,enableLoopCrossfade:p,playhead:D,fadeInDuration:A0,fadeOutDuration:F0}=V,K0=V.streamBuffer.streaming&&V.streamBuffer.committedLength<X,T0=V.loop&&!K0,l=Math.min(N.length,Y.length),W0=V.duration*T.sampleRate,Z0=Math.floor(T.sampleRate*v),q0=Math.max(X-y,0),L=r?Math.min(Math.floor(K*T.sampleRate),q0):0,x=t?Math.min(Math.floor(w*T.sampleRate),X):X,N0=x-L,J0=c&&H.length>0&&H[0]!==0,u=k;if(J0){let M=Math.max(k.length,H.length,y);u=new Float32Array(M);for(let W=0;W<M;W++){let I=k[W]??k[k.length-1],G=H[W]??H[H.length-1];u[W]=I*2**(G/1200)}}let Q0=V.enablePlaybackRate||J0,O0=Q0&&u.length>0&&u.every((M)=>M===0);if(V.streamBuffer.streaming&&!V.streamBuffer.streamEnded&&!V.streamBuffer.lowWaterNotified&&V.streamBuffer.committedLength-Math.floor(D)<V.streamBuffer.lowWaterThreshold)J.push({type:"bufferLowWater",data:{playhead:Math.floor(D),committedLength:V.streamBuffer.committedLength}}),V.streamBuffer.lowWaterNotified=!0;if(O0){d(Y);for(let M=1;M<A.length;M++)H0(Y,A[M]);return{keepAlive:!0,messages:J}}let U0={bufferLength:X,loop:T0,playhead:D,loopStartSamples:L,loopEndSamples:x,durationSamples:W0,playbackRates:u},{indexes:a,ended:X0,looped:Y0,playhead:$0}=Q0?x0(U0):L0(U0),f=a.find((M)=>M>=V.streamBuffer.committedLength&&M<X);if(f!==void 0&&!V.streamBuffer.streamEnded&&V.streamBuffer.lastUnderrunSample!==f)J.push({type:"bufferUnderrun",data:{playhead:Math.floor(D),committedLength:V.streamBuffer.committedLength,requestedSample:f}}),V.streamBuffer.lastUnderrunSample=f;else if(f===void 0)V.streamBuffer.lastUnderrunSample=null;m0(Y,N,a);let m=Math.min(Math.floor(v*T.sampleRate),N0),D0=T0&&D>L&&D<x,C0=p&&Z0>0&&X>y;if(D0&&C0){{let M=L+m;if(m>0&&D>L&&D<M){let W=D-L,I=Math.min(Math.floor(M-D),y);for(let G=0;G<I;G++){let B=(W+G)/m,S=Math.cos(Math.PI*B/2),q=Math.floor(x-m+W+G);if(q>=0&&q<X)for(let _=0;_<l;_++)Y[_][G]+=N[_][q]*S}}}{let M=x-m;if(m>0&&D>M&&D<x){let W=D-M,I=Math.min(Math.floor(x-D),y);for(let G=0;G<I;G++){let B=(W+G)/m,S=Math.sin(Math.PI*B/2),q=Math.floor(L+W+G);if(q>=0&&q<X)for(let _=0;_<l;_++)Y[_][G]+=N[_][q]*S}}}}if(s&&A0>0){let M=Math.floor(A0*T.sampleRate),W=M-E;if(W>0){let I=Math.min(W,y);for(let G=0;G<I;G++){let B=(E+G)/M,S=B*B*B;for(let q=0;q<l;q++)Y[q][G]*=S}}}if(g&&F0>0){let M=Math.floor(F0*T.sampleRate),W=Math.floor(T.sampleRate*(Z-T.currentTime));if(W<M+y)for(let I=0;I<y;I++){let G=W-I;if(G>=M)continue;let B=G<=0?0:G/M,S=B*B*B;for(let q=0;q<l;q++)Y[q][I]*=S}}if(O)h0(Y,$,T.sampleRate,Q.lowpass);if(R)l0(Y,j,T.sampleRate,Q.highpass);if(h)g0(Y,P);if(l===1)S0(Y);if(b)d0(Y,C);if(Y0)V.timesLooped++,J.push({type:"looped",data:V.timesLooped});if(X0)V.state=z.Ended,J.push({type:"ended"});V.playedSamples+=a.length,V.playhead=$0;let k0=c0(Y);if(k0>0)return console.log({numNans:k0,indexes:a,playhead:$0,ended:X0,looped:Y0,sourceLength:X}),{keepAlive:!0,messages:J};for(let M=1;M<A.length;M++)H0(Y,A[M]);return{keepAlive:!0,messages:J}}class P0 extends AudioWorkletProcessor{static get parameterDescriptors(){return[{name:"playbackRate",automationRate:"a-rate",defaultValue:1},{name:"detune",automationRate:"a-rate",defaultValue:0},{name:"gain",automationRate:"a-rate",defaultValue:1,minValue:0},{name:"pan",automationRate:"a-rate",defaultValue:0},{name:"highpass",automationRate:"a-rate",defaultValue:20,minValue:20,maxValue:20000},{name:"lowpass",automationRate:"a-rate",defaultValue:20000,minValue:20,maxValue:20000}]}properties;filterState={lowpass:V0(),highpass:V0()};lastFrameTime=0;constructor(V){super(V);this.properties=v0(V?.processorOptions,sampleRate),this.port.onmessage=(A)=>{let F=z0(this.properties,A.data,currentTime,sampleRate);for(let T of F)this.port.postMessage(T);if(this.properties.state===z.Disposed)this.port.close()}}process(V,A,F){try{let T=j0(this.properties,A,F,{currentTime,currentFrame,sampleRate},this.filterState);for(let J of T.messages)this.port.postMessage(J);let Q=currentTime-this.lastFrameTime;return this.lastFrameTime=currentTime,this.port.postMessage({type:"frame",data:[currentTime,currentFrame,Math.floor(this.properties.playhead),Q*1000]}),T.keepAlive}catch(T){return console.log(T),!0}}}registerProcessor("ClipProcessor",P0);
2
+
3
+ //# debugId=5101232AAE128B1064756E2164756E21
4
+ //# sourceMappingURL=processor.js.map
@@ -0,0 +1,12 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/audio/types.ts", "../src/audio/processor-kernel.ts", "../src/audio/processor.ts"],
4
+ "sourcesContent": [
5
+ "export const State = {\n\tInitial: 0,\n\tStarted: 1,\n\tStopped: 2,\n\tPaused: 3,\n\tScheduled: 4,\n\tEnded: 5,\n\tDisposed: 6,\n} as const;\n\nexport type ClipProcessorState = (typeof State)[keyof typeof State];\n\nexport interface ClipProcessorOptions {\n\tbuffer?: Float32Array[];\n\tstreamBuffer?: StreamBufferState;\n\tloop?: boolean;\n\tloopStart?: number;\n\tloopEnd?: number;\n\tloopCrossfade?: number;\n\toffset?: number;\n\tduration?: number;\n\tplayhead?: number;\n\tstate?: ClipProcessorState;\n\tstartWhen?: number;\n\tstopWhen?: number;\n\tpauseWhen?: number;\n\tresumeWhen?: number;\n\tplayedSamples?: number;\n\ttimesLooped?: number;\n\tfadeInDuration?: number;\n\tfadeOutDuration?: number;\n\tenableFadeIn?: boolean;\n\tenableFadeOut?: boolean;\n\tenableLoopStart?: boolean;\n\tenableLoopEnd?: boolean;\n\tenableLoopCrossfade?: boolean;\n\tenableGain?: boolean;\n\tenablePan?: boolean;\n\tenableHighpass?: boolean;\n\tenableLowpass?: boolean;\n\tenableDetune?: boolean;\n\tenablePlaybackRate?: boolean;\n}\n\nexport interface ClipWorkletOptions extends AudioWorkletNodeOptions {\n\tprocessorOptions?: ClipProcessorOptions;\n}\n\nexport type ClipNodeState =\n\t| \"initial\"\n\t| \"scheduled\"\n\t| \"started\"\n\t| \"stopped\"\n\t| \"paused\"\n\t| \"resumed\"\n\t| \"ended\"\n\t| \"disposed\";\n\nexport type FrameData = readonly [\n\tcurrentTime: number,\n\tcurrentFrame: number,\n\tplayhead: number,\n\ttimeTaken: number,\n];\n\nexport type ClipProcessorToggleMessageType =\n\t| \"toggleFadeIn\"\n\t| \"toggleFadeOut\"\n\t| \"toggleLoopStart\"\n\t| \"toggleLoopEnd\"\n\t| \"toggleLoopCrossfade\"\n\t| \"toggleGain\"\n\t| \"togglePan\"\n\t| \"toggleHighpass\"\n\t| \"toggleLowpass\"\n\t| \"toggleDetune\"\n\t| \"togglePlaybackRate\";\n\n// ---------------------------------------------------------------------------\n// Processor message types (moved from processor.ts)\n// ---------------------------------------------------------------------------\n\nexport interface ClipProcessorOnmessageEvent {\n\treadonly data: ClipProcessorMessageRx;\n}\n\nexport type ClipProcessorOnmessage = (ev: ClipProcessorOnmessageEvent) => void;\n\nexport interface ProcessorWorkletOptions extends AudioWorkletNodeOptions {\n\treadonly processorOptions?: ClipProcessorOptions;\n}\n\nexport interface ClipProcessorStateMap {\n\treadonly Initial: 0;\n\treadonly Started: 1;\n\treadonly Stopped: 2;\n\treadonly Paused: 3;\n\treadonly Scheduled: 4;\n\treadonly Ended: 5;\n\treadonly Disposed: 6;\n}\n\nexport type ClipProcessorMessageRx =\n\t| ClipProcessorBufferMessageRx\n\t| ClipProcessorBufferInitMessageRx\n\t| ClipProcessorBufferRangeMessageRx\n\t| ClipProcessorBufferEndMessageRx\n\t| ClipProcessorBufferResetMessageRx\n\t| ClipProcessorStartMessageRx\n\t| ClipProcessorStopMessageRx\n\t| ClipProcessorPauseMessageRx\n\t| ClipProcessorResumeMessageRx\n\t| ClipProcessorDisposeMessageRx\n\t| ClipProcessorLoopMessageRx\n\t| ClipProcessorLoopStartMessageRx\n\t| ClipProcessorLoopEndMessageRx\n\t| ClipProcessorPlayheadMessageRx\n\t| ClipProcessorFadeInMessageRx\n\t| ClipProcessorFadeOutMessageRx\n\t| ClipProcessorLoopCrossfadeMessageRx\n\t| ClipProcessorToggleMessageRx\n\t| ClipProcessorLogStateMessageRx;\n\nexport type ClipProcessorMessageType =\n\t| \"buffer\"\n\t| \"bufferInit\"\n\t| \"bufferRange\"\n\t| \"bufferEnd\"\n\t| \"bufferReset\"\n\t| \"start\"\n\t| \"stop\"\n\t| \"pause\"\n\t| \"resume\"\n\t| \"dispose\"\n\t| \"loop\"\n\t| \"loopStart\"\n\t| \"loopEnd\"\n\t| \"playhead\"\n\t| \"playbackRate\"\n\t| \"offset\"\n\t| \"fadeIn\"\n\t| \"fadeOut\"\n\t| \"loopCrossfade\"\n\t| ClipProcessorToggleMessageType\n\t| \"logState\";\n\nexport interface ClipProcessorLogStateMessageRx {\n\treadonly type: \"logState\";\n\treadonly data?: never;\n}\n\nexport interface ClipProcessorToggleMessageRx {\n\treadonly type: ClipProcessorToggleMessageType;\n\treadonly data?: boolean;\n}\n\nexport interface ClipProcessorBufferMessageRx {\n\treadonly type: \"buffer\";\n\treadonly data: Float32Array[];\n}\n\nexport interface StreamBufferSpan {\n\tstartSample: number;\n\tendSample: number;\n}\n\nexport interface BufferRangeWrite {\n\treadonly startSample: number;\n\treadonly channelData: Float32Array[];\n\treadonly totalLength?: number | null;\n\treadonly streamEnded?: boolean;\n}\n\nexport interface StreamBufferState {\n\ttotalLength: number | null;\n\tcommittedLength: number;\n\tstreamEnded: boolean;\n\tstreaming: boolean;\n\twrittenSpans: StreamBufferSpan[];\n\tpendingWrites: BufferRangeWrite[];\n\tlowWaterThreshold: number;\n\tlowWaterNotified: boolean;\n\tlastUnderrunSample: number | null;\n}\n\nexport interface ClipProcessorBufferInitMessageRx {\n\treadonly type: \"bufferInit\";\n\treadonly data: {\n\t\treadonly channels: number;\n\t\treadonly totalLength: number;\n\t\treadonly streaming?: boolean;\n\t};\n}\n\nexport interface ClipProcessorBufferRangeMessageRx {\n\treadonly type: \"bufferRange\";\n\treadonly data: BufferRangeWrite;\n}\n\nexport interface ClipProcessorBufferEndMessageRx {\n\treadonly type: \"bufferEnd\";\n\treadonly data?: {\n\t\treadonly totalLength?: number;\n\t};\n}\n\nexport interface ClipProcessorBufferResetMessageRx {\n\treadonly type: \"bufferReset\";\n\treadonly data?: never;\n}\n\nexport interface ClipProcessorStartMessageRx {\n\treadonly type: \"start\";\n\treadonly data?: {\n\t\treadonly duration?: number;\n\t\treadonly offset?: number;\n\t\treadonly when?: number;\n\t};\n}\n\nexport interface ClipProcessorStopMessageRx {\n\treadonly type: \"stop\";\n\treadonly data?: number;\n}\n\nexport interface ClipProcessorPauseMessageRx {\n\treadonly type: \"pause\";\n\treadonly data?: number;\n}\n\nexport interface ClipProcessorResumeMessageRx {\n\treadonly type: \"resume\";\n\treadonly data?: number;\n}\n\nexport interface ClipProcessorDisposeMessageRx {\n\treadonly type: \"dispose\";\n\treadonly data?: never;\n}\n\nexport interface ClipProcessorLoopMessageRx {\n\treadonly type: \"loop\";\n\treadonly data: boolean;\n}\n\nexport interface ClipProcessorLoopStartMessageRx {\n\treadonly type: \"loopStart\";\n\treadonly data: number;\n}\n\nexport interface ClipProcessorLoopEndMessageRx {\n\treadonly type: \"loopEnd\";\n\treadonly data: number;\n}\n\nexport interface ClipProcessorPlayheadMessageRx {\n\treadonly type: \"playhead\";\n\treadonly data: number;\n}\n\nexport interface ClipProcessorFadeInMessageRx {\n\treadonly type: \"fadeIn\";\n\treadonly data: number;\n}\n\nexport interface ClipProcessorFadeOutMessageRx {\n\treadonly type: \"fadeOut\";\n\treadonly data: number;\n}\n\nexport interface ClipProcessorLoopCrossfadeMessageRx {\n\treadonly type: \"loopCrossfade\";\n\treadonly data: number;\n}\n\n// ---------------------------------------------------------------------------\n// Block parameters (used by kernel)\n// ---------------------------------------------------------------------------\n\nexport interface BlockParameters {\n\treadonly playhead: number;\n\treadonly durationSamples: number;\n\treadonly loop: boolean;\n\treadonly loopStartSamples: number;\n\treadonly loopEndSamples: number;\n\treadonly bufferLength: number;\n\treadonly playbackRates: Float32Array;\n}\n\nexport interface BlockReturnState {\n\treadonly playhead: number;\n\treadonly ended: boolean;\n\treadonly looped: boolean;\n\treadonly indexes: number[];\n}\n",
6
+ "// processor-kernel.ts — Pure DSP logic, state machine, all filters\n// NO AudioWorklet or platform dependencies. Fully testable.\n\nimport {\n\ttype BlockParameters,\n\ttype BlockReturnState,\n\ttype BufferRangeWrite,\n\ttype ClipProcessorOptions,\n\tState,\n\ttype StreamBufferSpan,\n\ttype StreamBufferState,\n} from \"./types\";\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nexport const SAMPLE_BLOCK_SIZE = 128;\n\nfunction createStreamBufferState(\n\tbuffer: Float32Array[] = [],\n): StreamBufferState {\n\tconst totalLength = buffer[0]?.length ?? 0;\n\tconst hasBuffer = totalLength > 0;\n\treturn {\n\t\ttotalLength: hasBuffer ? totalLength : null,\n\t\tcommittedLength: hasBuffer ? totalLength : 0,\n\t\tstreamEnded: hasBuffer,\n\t\tstreaming: false,\n\t\twrittenSpans: hasBuffer ? [{ startSample: 0, endSample: totalLength }] : [],\n\t\tpendingWrites: [],\n\t\tlowWaterThreshold: SAMPLE_BLOCK_SIZE * 4,\n\t\tlowWaterNotified: false,\n\t\tlastUnderrunSample: null,\n\t};\n}\n\nfunction getBufferLength(buffer: Float32Array[]): number {\n\treturn buffer[0]?.length ?? 0;\n}\n\nfunction getLogicalBufferLength(\n\tproperties: Required<ClipProcessorOptions>,\n): number {\n\treturn (\n\t\tproperties.streamBuffer.totalLength ?? getBufferLength(properties.buffer)\n\t);\n}\n\nfunction createSilentBuffer(channels: number, length: number): Float32Array[] {\n\treturn Array.from({ length: channels }, () => new Float32Array(length));\n}\n\nfunction mergeWrittenSpan(\n\tspans: StreamBufferSpan[],\n\tnextSpan: StreamBufferSpan,\n): StreamBufferSpan[] {\n\tconst merged = [...spans, nextSpan].sort(\n\t\t(a, b) => a.startSample - b.startSample,\n\t);\n\tconst result: StreamBufferSpan[] = [];\n\tfor (const span of merged) {\n\t\tconst previous = result[result.length - 1];\n\t\tif (!previous || span.startSample > previous.endSample) {\n\t\t\tresult.push({ ...span });\n\t\t\tcontinue;\n\t\t}\n\t\tprevious.endSample = Math.max(previous.endSample, span.endSample);\n\t}\n\treturn result;\n}\n\nfunction getCommittedLength(spans: StreamBufferSpan[]): number {\n\tlet committedLength = 0;\n\tfor (const span of spans) {\n\t\tif (span.startSample > committedLength) break;\n\t\tcommittedLength = Math.max(committedLength, span.endSample);\n\t}\n\treturn committedLength;\n}\n\nfunction resetLowWaterState(\n\tstreamBuffer: StreamBufferState,\n\tplayhead: number,\n): void {\n\tif (\n\t\tstreamBuffer.committedLength - Math.floor(playhead) >=\n\t\tstreamBuffer.lowWaterThreshold\n\t) {\n\t\tstreamBuffer.lowWaterNotified = false;\n\t}\n}\n\nfunction ensureBufferCapacity(\n\tproperties: Required<ClipProcessorOptions>,\n\trequiredChannels: number,\n\trequiredLength: number,\n): void {\n\tconst currentLength = getBufferLength(properties.buffer);\n\tconst currentChannels = properties.buffer.length;\n\tif (currentLength >= requiredLength && currentChannels >= requiredChannels) {\n\t\treturn;\n\t}\n\n\tconst nextLength = Math.max(currentLength, requiredLength);\n\tconst nextChannels = Math.max(currentChannels, requiredChannels);\n\tconst nextBuffer = createSilentBuffer(nextChannels, nextLength);\n\tfor (let ch = 0; ch < currentChannels; ch++) {\n\t\tnextBuffer[ch].set(properties.buffer[ch].subarray(0, currentLength));\n\t}\n\tproperties.buffer = nextBuffer;\n\tif (\n\t\tproperties.streamBuffer.totalLength == null ||\n\t\tproperties.streamBuffer.totalLength < nextLength\n\t) {\n\t\tproperties.streamBuffer.totalLength = nextLength;\n\t}\n}\n\nfunction applyBufferRangeWrite(\n\tproperties: Required<ClipProcessorOptions>,\n\twrite: BufferRangeWrite,\n): void {\n\tconst startSample = Math.max(Math.floor(write.startSample), 0);\n\tconst writeLength = write.channelData[0]?.length ?? 0;\n\tconst requestedTotalLength = write.totalLength ?? null;\n\tconst requiredLength = Math.max(\n\t\tstartSample + writeLength,\n\t\trequestedTotalLength ?? 0,\n\t);\n\tensureBufferCapacity(\n\t\tproperties,\n\t\tMath.max(write.channelData.length, properties.buffer.length, 1),\n\t\trequiredLength,\n\t);\n\n\tfor (let ch = 0; ch < write.channelData.length; ch++) {\n\t\tproperties.buffer[ch].set(write.channelData[ch], startSample);\n\t}\n\n\tif (requestedTotalLength != null) {\n\t\tproperties.streamBuffer.totalLength = requestedTotalLength;\n\t}\n\tif (writeLength > 0) {\n\t\tproperties.streamBuffer.writtenSpans = mergeWrittenSpan(\n\t\t\tproperties.streamBuffer.writtenSpans,\n\t\t\t{ startSample, endSample: startSample + writeLength },\n\t\t);\n\t\tproperties.streamBuffer.committedLength = getCommittedLength(\n\t\t\tproperties.streamBuffer.writtenSpans,\n\t\t);\n\t}\n\tif (write.streamEnded === true) {\n\t\tproperties.streamBuffer.streamEnded = true;\n\t}\n\tresetLowWaterState(properties.streamBuffer, properties.playhead);\n}\n\nfunction applyPendingBufferWrites(\n\tproperties: Required<ClipProcessorOptions>,\n): void {\n\tif (properties.streamBuffer.pendingWrites.length === 0) {\n\t\treturn;\n\t}\n\tfor (const write of properties.streamBuffer.pendingWrites) {\n\t\tapplyBufferRangeWrite(properties, write);\n\t}\n\tproperties.streamBuffer.pendingWrites = [];\n}\n\nfunction setWholeBuffer(\n\tproperties: Required<ClipProcessorOptions>,\n\tbuffer: Float32Array[],\n): void {\n\tproperties.buffer = buffer;\n\tproperties.streamBuffer = createStreamBufferState(buffer);\n}\n\n// ---------------------------------------------------------------------------\n// Properties & offset\n// ---------------------------------------------------------------------------\n\nexport function getProperties(\n\topts: ClipProcessorOptions = {},\n\tsampleRate: number,\n): Required<ClipProcessorOptions> {\n\tconst {\n\t\tbuffer = [],\n\t\tstreamBuffer = createStreamBufferState(buffer),\n\t\tduration = -1,\n\t\tloop = false,\n\t\tloopStart = 0,\n\t\tloopEnd = (buffer[0]?.length ?? 0) / sampleRate,\n\t\tloopCrossfade = 0,\n\t\tplayhead = 0,\n\t\toffset = 0,\n\t\tstartWhen = 0,\n\t\tstopWhen = 0,\n\t\tpauseWhen = 0,\n\t\tresumeWhen = 0,\n\t\tplayedSamples = 0,\n\t\tstate = State.Initial,\n\t\ttimesLooped = 0,\n\t\tfadeInDuration = 0,\n\t\tfadeOutDuration = 0,\n\t\tenableFadeIn = fadeInDuration > 0,\n\t\tenableFadeOut = fadeOutDuration > 0,\n\t\tenableLoopStart = true,\n\t\tenableLoopEnd = true,\n\t\tenableLoopCrossfade = loopCrossfade > 0,\n\t\tenableHighpass = true,\n\t\tenableLowpass = true,\n\t\tenableGain = true,\n\t\tenablePan = true,\n\t\tenableDetune = true,\n\t\tenablePlaybackRate = true,\n\t} = opts;\n\n\treturn {\n\t\tbuffer,\n\t\tstreamBuffer,\n\t\tloop,\n\t\tloopStart,\n\t\tloopEnd,\n\t\tloopCrossfade,\n\t\tduration,\n\t\tplayhead,\n\t\toffset,\n\t\tstartWhen,\n\t\tstopWhen,\n\t\tpauseWhen,\n\t\tresumeWhen,\n\t\tplayedSamples,\n\t\tstate,\n\t\ttimesLooped,\n\t\tfadeInDuration,\n\t\tfadeOutDuration,\n\t\tenableFadeIn,\n\t\tenableFadeOut,\n\t\tenableLoopStart,\n\t\tenableLoopEnd,\n\t\tenableHighpass,\n\t\tenableLowpass,\n\t\tenableGain,\n\t\tenablePan,\n\t\tenableDetune,\n\t\tenablePlaybackRate,\n\t\tenableLoopCrossfade,\n\t};\n}\n\nfunction getBufferDurationSeconds(\n\tproperties: Required<ClipProcessorOptions>,\n\tsampleRate: number,\n): number {\n\treturn getLogicalBufferLength(properties) / sampleRate;\n}\n\nfunction normalizeLoopBounds(\n\tproperties: Required<ClipProcessorOptions>,\n\tsampleRate: number,\n): void {\n\tconst bufferDuration = getBufferDurationSeconds(properties, sampleRate);\n\tif (bufferDuration <= 0) {\n\t\tproperties.loopStart = 0;\n\t\tproperties.loopEnd = 0;\n\t\treturn;\n\t}\n\n\tif (!Number.isFinite(properties.loopStart) || properties.loopStart < 0) {\n\t\tproperties.loopStart = 0;\n\t}\n\tif (properties.loopStart >= bufferDuration) {\n\t\tproperties.loopStart = 0;\n\t}\n\tif (\n\t\t!Number.isFinite(properties.loopEnd) ||\n\t\tproperties.loopEnd <= properties.loopStart ||\n\t\tproperties.loopEnd > bufferDuration\n\t) {\n\t\tproperties.loopEnd = bufferDuration;\n\t}\n}\n\nexport function setOffset(\n\tproperties: Required<ClipProcessorOptions>,\n\toffset: number | undefined,\n\tsampleRate: number,\n): number {\n\tif (offset === undefined) {\n\t\tproperties.offset = 0;\n\t\treturn 0;\n\t}\n\tif (offset < 0) {\n\t\treturn setOffset(\n\t\t\tproperties,\n\t\t\tgetLogicalBufferLength(properties) + offset,\n\t\t\tsampleRate,\n\t\t);\n\t}\n\tif (offset > (getLogicalBufferLength(properties) || 1) - 1) {\n\t\treturn setOffset(\n\t\t\tproperties,\n\t\t\tgetLogicalBufferLength(properties) % offset,\n\t\t\tsampleRate,\n\t\t);\n\t}\n\tconst offs = Math.floor(offset * sampleRate);\n\tproperties.offset = offs;\n\treturn offs;\n}\n\n// ---------------------------------------------------------------------------\n// Index calculation\n// ---------------------------------------------------------------------------\n\nexport function findIndexesNormal(p: BlockParameters): BlockReturnState {\n\tconst { playhead, bufferLength, loop, loopStartSamples, loopEndSamples } = p;\n\tlet length = 128;\n\tif (!loop && playhead + 128 > bufferLength) {\n\t\tlength = Math.max(bufferLength - playhead, 0);\n\t}\n\tconst indexes: number[] = new Array(length);\n\n\tif (!loop) {\n\t\tfor (let i = 0, head = playhead; i < length; i++, head++) {\n\t\t\tindexes[i] = head;\n\t\t}\n\t\tconst nextPlayhead = playhead + length;\n\t\treturn {\n\t\t\tplayhead: nextPlayhead,\n\t\t\tindexes,\n\t\t\tlooped: false,\n\t\t\tended: nextPlayhead >= bufferLength,\n\t\t};\n\t}\n\n\tlet head = playhead;\n\tlet looped = false;\n\tfor (let i = 0; i < length; i++, head++) {\n\t\tif (head >= loopEndSamples) {\n\t\t\thead = loopStartSamples + (head - loopEndSamples);\n\t\t\tlooped = true;\n\t\t}\n\t\tindexes[i] = head;\n\t}\n\treturn { indexes, looped, ended: false, playhead: head };\n}\n\nexport function findIndexesWithPlaybackRates(\n\tp: BlockParameters,\n): BlockReturnState {\n\tconst {\n\t\tplayhead,\n\t\tbufferLength,\n\t\tloop,\n\t\tloopStartSamples,\n\t\tloopEndSamples,\n\t\tplaybackRates,\n\t} = p;\n\tlet length = 128;\n\tif (!loop && playhead + 128 > bufferLength) {\n\t\tlength = Math.max(bufferLength - playhead, 0);\n\t}\n\tconst indexes: number[] = new Array(length);\n\tlet head = playhead;\n\tlet looped = false;\n\n\tif (loop) {\n\t\tfor (let i = 0; i < length; i++) {\n\t\t\tindexes[i] = Math.min(Math.max(Math.floor(head), 0), bufferLength - 1);\n\t\t\tconst rate = playbackRates[i] ?? playbackRates[0] ?? 1;\n\t\t\thead += rate;\n\t\t\tif (rate >= 0 && (head > loopEndSamples || head > bufferLength)) {\n\t\t\t\thead = loopStartSamples;\n\t\t\t\tlooped = true;\n\t\t\t} else if (rate < 0 && (head < loopStartSamples || head < 0)) {\n\t\t\t\thead = loopEndSamples;\n\t\t\t\tlooped = true;\n\t\t\t}\n\t\t}\n\t\treturn { playhead: head, indexes, looped, ended: false };\n\t}\n\n\tfor (let i = 0; i < length; i++) {\n\t\tindexes[i] = Math.min(Math.max(Math.floor(head), 0), bufferLength - 1);\n\t\thead += playbackRates[i] ?? playbackRates[0] ?? 1;\n\t}\n\treturn {\n\t\tplayhead: head,\n\t\tindexes,\n\t\tlooped: false,\n\t\tended: head >= bufferLength || head < 0,\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Buffer operations\n// ---------------------------------------------------------------------------\n\nexport function fill(\n\ttarget: Float32Array[],\n\tsource: Float32Array[],\n\tindexes: number[],\n): void {\n\tfor (let i = 0; i < indexes.length; i++) {\n\t\tfor (let ch = 0; ch < target.length; ch++) {\n\t\t\ttarget[ch][i] = source[ch][indexes[i]];\n\t\t}\n\t}\n\tfor (let i = indexes.length; i < target[0].length; i++) {\n\t\tfor (let ch = 0; ch < target.length; ch++) {\n\t\t\ttarget[ch][i] = 0;\n\t\t}\n\t}\n}\n\nexport function fillWithSilence(buffer: Float32Array[]): void {\n\tfor (let ch = 0; ch < buffer.length; ch++) {\n\t\tfor (let j = 0; j < buffer[ch].length; j++) {\n\t\t\tbuffer[ch][j] = 0;\n\t\t}\n\t}\n}\n\nexport function monoToStereo(signal: Float32Array[]): void {\n\tconst r = new Float32Array(signal[0].length);\n\tfor (let i = 0; i < signal[0].length; i++) {\n\t\tr[i] = signal[0][i];\n\t}\n\tsignal.push(r);\n}\n\nexport function copy(source: Float32Array[], target: Float32Array[]): void {\n\tfor (let i = target.length; i < source.length; i++) {\n\t\ttarget[i] = new Float32Array(source[i].length);\n\t}\n\tfor (let ch = 0; ch < source.length; ch++) {\n\t\tfor (let i = 0; i < source[ch].length; i++) {\n\t\t\ttarget[ch][i] = source[ch][i];\n\t\t}\n\t}\n}\n\nexport function checkNans(output: Float32Array[]): number {\n\tlet numNans = 0;\n\tfor (let ch = 0; ch < output.length; ch++) {\n\t\tfor (let j = 0; j < output[ch].length; j++) {\n\t\t\tif (Number.isNaN(output[ch][j])) {\n\t\t\t\tnumNans++;\n\t\t\t\toutput[ch][j] = 0;\n\t\t\t}\n\t\t}\n\t}\n\treturn numNans;\n}\n\n// ---------------------------------------------------------------------------\n// Filters\n// ---------------------------------------------------------------------------\n\nexport interface BiquadState {\n\tx_1: number;\n\tx_2: number;\n\ty_1: number;\n\ty_2: number;\n}\n\nexport function createFilterState(): BiquadState[] {\n\treturn [\n\t\t{ x_1: 0, x_2: 0, y_1: 0, y_2: 0 },\n\t\t{ x_1: 0, x_2: 0, y_1: 0, y_2: 0 },\n\t];\n}\n\nexport function gainFilter(arr: Float32Array[], gains: Float32Array): void {\n\tif (gains.length === 1) {\n\t\tconst g = gains[0];\n\t\tif (g === 1) return;\n\t\tfor (const ch of arr) {\n\t\t\tfor (let i = 0; i < ch.length; i++) ch[i] *= g;\n\t\t}\n\t\treturn;\n\t}\n\tlet g = gains[0];\n\tfor (const ch of arr) {\n\t\tfor (let i = 0; i < ch.length; i++) {\n\t\t\tg = gains[i] ?? g;\n\t\t\tch[i] *= g;\n\t\t}\n\t}\n}\n\nexport function panFilter(signal: Float32Array[], pans: Float32Array): void {\n\tlet pan = pans[0];\n\tfor (let i = 0; i < signal[0].length; i++) {\n\t\tpan = pans[i] ?? pan;\n\t\tconst leftGain = pan <= 0 ? 1 : 1 - pan;\n\t\tconst rightGain = pan >= 0 ? 1 : 1 + pan;\n\t\tsignal[0][i] *= leftGain;\n\t\tsignal[1][i] *= rightGain;\n\t}\n}\n\nexport function lowpassFilter(\n\tbuffer: Float32Array[],\n\tcutoffs: Float32Array,\n\tsampleRate: number,\n\tstates: BiquadState[],\n): void {\n\tfor (let channel = 0; channel < buffer.length; channel++) {\n\t\tconst arr = buffer[channel];\n\t\tlet { x_1, x_2, y_1, y_2 } = states[channel] ?? {\n\t\t\tx_1: 0,\n\t\t\tx_2: 0,\n\t\t\ty_1: 0,\n\t\t\ty_2: 0,\n\t\t};\n\t\tif (cutoffs.length === 1) {\n\t\t\tconst cutoff = cutoffs[0];\n\t\t\tif (cutoff >= 20000) return;\n\t\t\tconst w0 = (2 * Math.PI * cutoff) / sampleRate;\n\t\t\tconst alpha = Math.sin(w0) / 2;\n\t\t\tconst b0 = (1 - Math.cos(w0)) / 2;\n\t\t\tconst b1 = 1 - Math.cos(w0);\n\t\t\tconst b2 = (1 - Math.cos(w0)) / 2;\n\t\t\tconst a0 = 1 + alpha;\n\t\t\tconst a1 = -2 * Math.cos(w0);\n\t\t\tconst a2 = 1 - alpha;\n\t\t\tconst h0 = b0 / a0,\n\t\t\t\th1 = b1 / a0,\n\t\t\t\th2 = b2 / a0,\n\t\t\t\th3 = a1 / a0,\n\t\t\t\th4 = a2 / a0;\n\t\t\tfor (let i = 0; i < arr.length; i++) {\n\t\t\t\tconst x = arr[i];\n\t\t\t\tconst y = h0 * x + h1 * x_1 + h2 * x_2 - h3 * y_1 - h4 * y_2;\n\t\t\t\tx_2 = x_1;\n\t\t\t\tx_1 = x;\n\t\t\t\ty_2 = y_1;\n\t\t\t\ty_1 = y;\n\t\t\t\tarr[i] = y;\n\t\t\t}\n\t\t} else {\n\t\t\tconst prevCutoff = cutoffs[0];\n\t\t\tfor (let i = 0; i < arr.length; i++) {\n\t\t\t\tconst cutoff = cutoffs[i] ?? prevCutoff;\n\t\t\t\tconst w0 = (2 * Math.PI * cutoff) / sampleRate;\n\t\t\t\tconst alpha = Math.sin(w0) / 2;\n\t\t\t\tconst b0 = (1 - Math.cos(w0)) / 2;\n\t\t\t\tconst b1 = 1 - Math.cos(w0);\n\t\t\t\tconst b2 = (1 - Math.cos(w0)) / 2;\n\t\t\t\tconst a0 = 1 + alpha;\n\t\t\t\tconst a1 = -2 * Math.cos(w0);\n\t\t\t\tconst a2 = 1 - alpha;\n\t\t\t\tconst x = arr[i];\n\t\t\t\tconst y =\n\t\t\t\t\t(b0 / a0) * x +\n\t\t\t\t\t(b1 / a0) * x_1 +\n\t\t\t\t\t(b2 / a0) * x_2 -\n\t\t\t\t\t(a1 / a0) * y_1 -\n\t\t\t\t\t(a2 / a0) * y_2;\n\t\t\t\tx_2 = x_1;\n\t\t\t\tx_1 = x;\n\t\t\t\ty_2 = y_1;\n\t\t\t\ty_1 = y;\n\t\t\t\tarr[i] = y;\n\t\t\t}\n\t\t}\n\t\tstates[channel] = { x_1, x_2, y_1, y_2 };\n\t}\n}\n\nexport function highpassFilter(\n\tbuffer: Float32Array[],\n\tcutoffs: Float32Array,\n\tsampleRate: number,\n\tstates: BiquadState[],\n): void {\n\tfor (let channel = 0; channel < buffer.length; channel++) {\n\t\tconst arr = buffer[channel];\n\t\tlet { x_1, x_2, y_1, y_2 } = states[channel] ?? {\n\t\t\tx_1: 0,\n\t\t\tx_2: 0,\n\t\t\ty_1: 0,\n\t\t\ty_2: 0,\n\t\t};\n\t\tif (cutoffs.length === 1) {\n\t\t\tconst cutoff = cutoffs[0];\n\t\t\tif (cutoff <= 20) return;\n\t\t\tconst w0 = (2 * Math.PI * cutoff) / sampleRate;\n\t\t\tconst alpha = Math.sin(w0) / 2;\n\t\t\tconst b0 = (1 + Math.cos(w0)) / 2;\n\t\t\tconst b1 = -(1 + Math.cos(w0));\n\t\t\tconst b2 = (1 + Math.cos(w0)) / 2;\n\t\t\tconst a0 = 1 + alpha;\n\t\t\tconst a1 = -2 * Math.cos(w0);\n\t\t\tconst a2 = 1 - alpha;\n\t\t\tfor (let i = 0; i < arr.length; i++) {\n\t\t\t\tconst x = arr[i];\n\t\t\t\tconst y =\n\t\t\t\t\t(b0 / a0) * x +\n\t\t\t\t\t(b1 / a0) * x_1 +\n\t\t\t\t\t(b2 / a0) * x_2 -\n\t\t\t\t\t(a1 / a0) * y_1 -\n\t\t\t\t\t(a2 / a0) * y_2;\n\t\t\t\tx_2 = x_1;\n\t\t\t\tx_1 = x;\n\t\t\t\ty_2 = y_1;\n\t\t\t\ty_1 = y;\n\t\t\t\tarr[i] = y;\n\t\t\t}\n\t\t} else {\n\t\t\tconst prevCutoff = cutoffs[0];\n\t\t\tfor (let i = 0; i < arr.length; i++) {\n\t\t\t\tconst cutoff = cutoffs[i] ?? prevCutoff;\n\t\t\t\tconst w0 = (2 * Math.PI * cutoff) / sampleRate;\n\t\t\t\tconst alpha = Math.sin(w0) / 2;\n\t\t\t\tconst b0 = (1 + Math.cos(w0)) / 2;\n\t\t\t\tconst b1 = -(1 + Math.cos(w0));\n\t\t\t\tconst b2 = (1 + Math.cos(w0)) / 2;\n\t\t\t\tconst a0 = 1 + alpha;\n\t\t\t\tconst a1 = -2 * Math.cos(w0);\n\t\t\t\tconst a2 = 1 - alpha;\n\t\t\t\tconst x = arr[i];\n\t\t\t\tconst y =\n\t\t\t\t\t(b0 / a0) * x +\n\t\t\t\t\t(b1 / a0) * x_1 +\n\t\t\t\t\t(b2 / a0) * x_2 -\n\t\t\t\t\t(a1 / a0) * y_1 -\n\t\t\t\t\t(a2 / a0) * y_2;\n\t\t\t\tx_2 = x_1;\n\t\t\t\tx_1 = x;\n\t\t\t\ty_2 = y_1;\n\t\t\t\ty_1 = y;\n\t\t\t\tarr[i] = y;\n\t\t\t}\n\t\t}\n\t\tstates[channel] = { x_1, x_2, y_1, y_2 };\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// Message handler\n// ---------------------------------------------------------------------------\n\nexport interface OutboundMessage {\n\ttype: string;\n\tdata?: unknown;\n}\n\nexport function handleProcessorMessage(\n\tproperties: Required<ClipProcessorOptions>,\n\tmessage: { type: string; data?: unknown },\n\tcurrentTime: number,\n\tsampleRate: number,\n): OutboundMessage[] {\n\tconst { type, data } = message;\n\tswitch (type) {\n\t\tcase \"buffer\":\n\t\t\tsetWholeBuffer(properties, data as Float32Array[]);\n\t\t\tnormalizeLoopBounds(properties, sampleRate);\n\t\t\treturn [];\n\t\tcase \"bufferInit\": {\n\t\t\tconst init = data as {\n\t\t\t\tchannels: number;\n\t\t\t\ttotalLength: number;\n\t\t\t\tstreaming?: boolean;\n\t\t\t};\n\t\t\tproperties.buffer = createSilentBuffer(init.channels, init.totalLength);\n\t\t\tproperties.streamBuffer = {\n\t\t\t\t...createStreamBufferState(),\n\t\t\t\ttotalLength: init.totalLength,\n\t\t\t\tstreamEnded: false,\n\t\t\t\tstreaming: init.streaming ?? true,\n\t\t\t};\n\t\t\tnormalizeLoopBounds(properties, sampleRate);\n\t\t\treturn [];\n\t\t}\n\t\tcase \"bufferRange\":\n\t\t\tproperties.streamBuffer.pendingWrites.push(data as BufferRangeWrite);\n\t\t\treturn [];\n\t\tcase \"bufferEnd\": {\n\t\t\tconst endData = data as { totalLength?: number } | undefined;\n\t\t\tif (endData?.totalLength != null) {\n\t\t\t\tproperties.streamBuffer.totalLength = endData.totalLength;\n\t\t\t}\n\t\t\tproperties.streamBuffer.streamEnded = true;\n\t\t\treturn [];\n\t\t}\n\t\tcase \"bufferReset\":\n\t\t\tproperties.buffer = [];\n\t\t\tproperties.streamBuffer = createStreamBufferState();\n\t\t\tnormalizeLoopBounds(properties, sampleRate);\n\t\t\treturn [];\n\t\tcase \"start\":\n\t\t\tproperties.timesLooped = 0;\n\t\t\t{\n\t\t\t\tconst d = data as\n\t\t\t\t\t| { duration?: number; offset?: number; when?: number }\n\t\t\t\t\t| undefined;\n\t\t\t\tproperties.duration = d?.duration ?? -1;\n\t\t\t\tif (properties.duration === -1) {\n\t\t\t\t\tproperties.duration = properties.loop\n\t\t\t\t\t\t? Number.MAX_SAFE_INTEGER\n\t\t\t\t\t\t: (properties.buffer[0]?.length ?? 0) / sampleRate;\n\t\t\t\t}\n\t\t\t\tsetOffset(properties, d?.offset, sampleRate);\n\t\t\t\tnormalizeLoopBounds(properties, sampleRate);\n\t\t\t\tproperties.playhead = properties.offset;\n\t\t\t\tproperties.startWhen = d?.when ?? currentTime;\n\t\t\t\tproperties.stopWhen = properties.startWhen + properties.duration;\n\t\t\t\tproperties.playedSamples = 0;\n\t\t\t\tproperties.state = State.Scheduled;\n\t\t\t}\n\t\t\treturn [{ type: \"scheduled\" }];\n\t\tcase \"stop\":\n\t\t\tif (\n\t\t\t\tproperties.state === State.Ended ||\n\t\t\t\tproperties.state === State.Initial\n\t\t\t)\n\t\t\t\treturn [];\n\t\t\tproperties.stopWhen = (data as number | undefined) ?? properties.stopWhen;\n\t\t\tproperties.state = State.Stopped;\n\t\t\treturn [{ type: \"stopped\" }];\n\t\tcase \"pause\":\n\t\t\tproperties.state = State.Paused;\n\t\t\tproperties.pauseWhen = (data as number | undefined) ?? currentTime;\n\t\t\treturn [{ type: \"paused\" }];\n\t\tcase \"resume\":\n\t\t\tproperties.state = State.Started;\n\t\t\tproperties.startWhen = (data as number | undefined) ?? currentTime;\n\t\t\treturn [{ type: \"resume\" }];\n\t\tcase \"dispose\":\n\t\t\tproperties.state = State.Disposed;\n\t\t\tproperties.buffer = [];\n\t\t\tproperties.streamBuffer = createStreamBufferState();\n\t\t\treturn [{ type: \"disposed\" }];\n\t\tcase \"loop\": {\n\t\t\tconst loop = data as boolean;\n\t\t\tconst st = properties.state;\n\t\t\tif (loop && (st === State.Scheduled || st === State.Started)) {\n\t\t\t\tproperties.stopWhen = Number.MAX_SAFE_INTEGER;\n\t\t\t\tproperties.duration = Number.MAX_SAFE_INTEGER;\n\t\t\t}\n\t\t\tproperties.loop = loop;\n\t\t\tif (loop) {\n\t\t\t\tnormalizeLoopBounds(properties, sampleRate);\n\t\t\t}\n\t\t\treturn [];\n\t\t}\n\t\tcase \"loopStart\":\n\t\t\tproperties.loopStart = data as number;\n\t\t\treturn [];\n\t\tcase \"loopEnd\":\n\t\t\tproperties.loopEnd = data as number;\n\t\t\treturn [];\n\t\tcase \"loopCrossfade\":\n\t\t\tproperties.loopCrossfade = data as number;\n\t\t\treturn [];\n\t\tcase \"playhead\":\n\t\t\tproperties.playhead = Math.floor(data as number);\n\t\t\treturn [];\n\t\tcase \"fadeIn\":\n\t\t\tproperties.fadeInDuration = data as number;\n\t\t\treturn [];\n\t\tcase \"fadeOut\":\n\t\t\tproperties.fadeOutDuration = data as number;\n\t\t\treturn [];\n\t\tcase \"toggleGain\":\n\t\t\tproperties.enableGain =\n\t\t\t\t(data as boolean | undefined) ?? !properties.enableGain;\n\t\t\treturn [];\n\t\tcase \"togglePan\":\n\t\t\tproperties.enablePan =\n\t\t\t\t(data as boolean | undefined) ?? !properties.enablePan;\n\t\t\treturn [];\n\t\tcase \"toggleLowpass\":\n\t\t\tproperties.enableLowpass =\n\t\t\t\t(data as boolean | undefined) ?? !properties.enableLowpass;\n\t\t\treturn [];\n\t\tcase \"toggleHighpass\":\n\t\t\tproperties.enableHighpass =\n\t\t\t\t(data as boolean | undefined) ?? !properties.enableHighpass;\n\t\t\treturn [];\n\t\tcase \"toggleDetune\":\n\t\t\tproperties.enableDetune =\n\t\t\t\t(data as boolean | undefined) ?? !properties.enableDetune;\n\t\t\treturn [];\n\t\tcase \"togglePlaybackRate\":\n\t\t\tproperties.enablePlaybackRate =\n\t\t\t\t(data as boolean | undefined) ?? !properties.enablePlaybackRate;\n\t\t\treturn [];\n\t\tcase \"toggleFadeIn\":\n\t\t\tproperties.enableFadeIn =\n\t\t\t\t(data as boolean | undefined) ?? !properties.enableFadeIn;\n\t\t\treturn [];\n\t\tcase \"toggleFadeOut\":\n\t\t\tproperties.enableFadeOut =\n\t\t\t\t(data as boolean | undefined) ?? !properties.enableFadeOut;\n\t\t\treturn [];\n\t\tcase \"toggleLoopStart\":\n\t\t\tproperties.enableLoopStart =\n\t\t\t\t(data as boolean | undefined) ?? !properties.enableLoopStart;\n\t\t\treturn [];\n\t\tcase \"toggleLoopEnd\":\n\t\t\tproperties.enableLoopEnd =\n\t\t\t\t(data as boolean | undefined) ?? !properties.enableLoopEnd;\n\t\t\treturn [];\n\t\tcase \"toggleLoopCrossfade\":\n\t\t\tproperties.enableLoopCrossfade =\n\t\t\t\t(data as boolean | undefined) ?? !properties.enableLoopCrossfade;\n\t\t\treturn [];\n\t\tcase \"logState\":\n\t\t\treturn [];\n\t}\n\treturn [];\n}\n\n// ---------------------------------------------------------------------------\n// Process block\n// ---------------------------------------------------------------------------\n\nexport interface ProcessContext {\n\tcurrentTime: number;\n\tcurrentFrame: number;\n\tsampleRate: number;\n}\n\nexport interface ProcessResult {\n\tkeepAlive: boolean;\n\tmessages: OutboundMessage[];\n}\n\nexport function processBlock(\n\tprops: Required<ClipProcessorOptions>,\n\toutputs: Float32Array[][],\n\tparameters: Record<string, Float32Array>,\n\tctx: ProcessContext,\n\tfilterState: { lowpass: BiquadState[]; highpass: BiquadState[] },\n): ProcessResult {\n\tconst messages: OutboundMessage[] = [];\n\tlet state = props.state;\n\tif (state === State.Disposed) return { keepAlive: false, messages };\n\n\tapplyPendingBufferWrites(props);\n\n\tif (state === State.Initial) return { keepAlive: true, messages };\n\n\tif (state === State.Ended) {\n\t\tfillWithSilence(outputs[0]);\n\t\treturn { keepAlive: true, messages };\n\t}\n\n\tif (state === State.Scheduled) {\n\t\tif (ctx.currentTime >= props.startWhen) {\n\t\t\tstate = props.state = State.Started;\n\t\t\tmessages.push({ type: \"started\" });\n\t\t} else {\n\t\t\tfillWithSilence(outputs[0]);\n\t\t\treturn { keepAlive: true, messages };\n\t\t}\n\t} else if (state === State.Paused) {\n\t\tif (ctx.currentTime > props.pauseWhen) {\n\t\t\tfillWithSilence(outputs[0]);\n\t\t\treturn { keepAlive: true, messages };\n\t\t}\n\t}\n\n\tif (ctx.currentTime > props.stopWhen) {\n\t\tfillWithSilence(outputs[0]);\n\t\tprops.state = State.Ended;\n\t\tmessages.push({ type: \"ended\" });\n\t\tprops.playedSamples = 0;\n\t\treturn { keepAlive: true, messages };\n\t}\n\n\tconst output0 = outputs[0];\n\tconst sourceLength = getLogicalBufferLength(props);\n\tif (sourceLength === 0) {\n\t\tfillWithSilence(output0);\n\t\treturn { keepAlive: true, messages };\n\t}\n\n\tconst {\n\t\tplaybackRate: playbackRates,\n\t\tdetune: detunes,\n\t\tlowpass,\n\t\thighpass,\n\t\tgain: gains,\n\t\tpan: pans,\n\t} = parameters;\n\n\tconst {\n\t\tbuffer,\n\t\tloopStart,\n\t\tloopEnd,\n\t\tloopCrossfade,\n\t\tstopWhen,\n\t\tplayedSamples,\n\t\tenableLowpass,\n\t\tenableHighpass,\n\t\tenableGain,\n\t\tenablePan,\n\t\tenableDetune,\n\t\tenableFadeOut,\n\t\tenableFadeIn,\n\t\tenableLoopStart,\n\t\tenableLoopEnd,\n\t\tenableLoopCrossfade,\n\t\tplayhead,\n\t\tfadeInDuration,\n\t\tfadeOutDuration,\n\t} = props;\n\tconst hasIncompleteStream =\n\t\tprops.streamBuffer.streaming &&\n\t\tprops.streamBuffer.committedLength < sourceLength;\n\tconst loop = props.loop && !hasIncompleteStream;\n\n\tconst nc = Math.min(buffer.length, output0.length);\n\tconst durationSamples = props.duration * ctx.sampleRate;\n\n\tconst loopCrossfadeSamples = Math.floor(ctx.sampleRate * loopCrossfade);\n\tconst maxLoopStartSample = Math.max(sourceLength - SAMPLE_BLOCK_SIZE, 0);\n\tconst loopStartSamples = enableLoopStart\n\t\t? Math.min(Math.floor(loopStart * ctx.sampleRate), maxLoopStartSample)\n\t\t: 0;\n\tconst loopEndSamples = enableLoopEnd\n\t\t? Math.min(Math.floor(loopEnd * ctx.sampleRate), sourceLength)\n\t\t: sourceLength;\n\tconst loopLengthSamples = loopEndSamples - loopStartSamples;\n\n\t// Apply detune to playback rates: effectiveRate = rate * 2^(detune/1200)\n\tconst needsDetune = enableDetune && detunes.length > 0 && detunes[0] !== 0;\n\tlet effectiveRates = playbackRates;\n\tif (needsDetune) {\n\t\tconst len = Math.max(\n\t\t\tplaybackRates.length,\n\t\t\tdetunes.length,\n\t\t\tSAMPLE_BLOCK_SIZE,\n\t\t);\n\t\teffectiveRates = new Float32Array(len);\n\t\tfor (let i = 0; i < len; i++) {\n\t\t\tconst rate = playbackRates[i] ?? playbackRates[playbackRates.length - 1];\n\t\t\tconst cents = detunes[i] ?? detunes[detunes.length - 1];\n\t\t\teffectiveRates[i] = rate * 2 ** (cents / 1200);\n\t\t}\n\t}\n\n\tconst useRateIndexing = props.enablePlaybackRate || needsDetune;\n\tconst isZeroRateBlock =\n\t\tuseRateIndexing &&\n\t\teffectiveRates.length > 0 &&\n\t\teffectiveRates.every((rate) => rate === 0);\n\n\tif (\n\t\tprops.streamBuffer.streaming &&\n\t\t!props.streamBuffer.streamEnded &&\n\t\t!props.streamBuffer.lowWaterNotified &&\n\t\tprops.streamBuffer.committedLength - Math.floor(playhead) <\n\t\t\tprops.streamBuffer.lowWaterThreshold\n\t) {\n\t\tmessages.push({\n\t\t\ttype: \"bufferLowWater\",\n\t\t\tdata: {\n\t\t\t\tplayhead: Math.floor(playhead),\n\t\t\t\tcommittedLength: props.streamBuffer.committedLength,\n\t\t\t},\n\t\t});\n\t\tprops.streamBuffer.lowWaterNotified = true;\n\t}\n\n\tif (isZeroRateBlock) {\n\t\tfillWithSilence(output0);\n\t\tfor (let i = 1; i < outputs.length; i++) {\n\t\t\tcopy(output0, outputs[i]);\n\t\t}\n\t\treturn { keepAlive: true, messages };\n\t}\n\n\tconst blockParams: BlockParameters = {\n\t\tbufferLength: sourceLength,\n\t\tloop,\n\t\tplayhead,\n\t\tloopStartSamples,\n\t\tloopEndSamples,\n\t\tdurationSamples,\n\t\tplaybackRates: effectiveRates,\n\t};\n\n\tconst {\n\t\tindexes,\n\t\tended,\n\t\tlooped,\n\t\tplayhead: updatedPlayhead,\n\t} = useRateIndexing\n\t\t? findIndexesWithPlaybackRates(blockParams)\n\t\t: findIndexesNormal(blockParams);\n\n\tconst underrunSample = indexes.find(\n\t\t(index) =>\n\t\t\tindex >= props.streamBuffer.committedLength && index < sourceLength,\n\t);\n\tif (\n\t\tunderrunSample !== undefined &&\n\t\t!props.streamBuffer.streamEnded &&\n\t\tprops.streamBuffer.lastUnderrunSample !== underrunSample\n\t) {\n\t\tmessages.push({\n\t\t\ttype: \"bufferUnderrun\",\n\t\t\tdata: {\n\t\t\t\tplayhead: Math.floor(playhead),\n\t\t\t\tcommittedLength: props.streamBuffer.committedLength,\n\t\t\t\trequestedSample: underrunSample,\n\t\t\t},\n\t\t});\n\t\tprops.streamBuffer.lastUnderrunSample = underrunSample;\n\t} else if (underrunSample === undefined) {\n\t\tprops.streamBuffer.lastUnderrunSample = null;\n\t}\n\n\tfill(output0, buffer, indexes);\n\n\t// --- Loop crossfade ---\n\tconst xfadeNumSamples = Math.min(\n\t\tMath.floor(loopCrossfade * ctx.sampleRate),\n\t\tloopLengthSamples,\n\t);\n\tconst isWithinLoopRange =\n\t\tloop && playhead > loopStartSamples && playhead < loopEndSamples;\n\tconst needsCrossfade =\n\t\tenableLoopCrossfade &&\n\t\tloopCrossfadeSamples > 0 &&\n\t\tsourceLength > SAMPLE_BLOCK_SIZE;\n\n\tif (isWithinLoopRange && needsCrossfade) {\n\t\t// Crossfade out at loop start: fade out tail of previous loop iteration.\n\t\t// Source: reads from END of loop (loopEnd - xfade to loopEnd).\n\t\t{\n\t\t\tconst endIndex = loopStartSamples + xfadeNumSamples;\n\t\t\tif (\n\t\t\t\txfadeNumSamples > 0 &&\n\t\t\t\tplayhead > loopStartSamples &&\n\t\t\t\tplayhead < endIndex\n\t\t\t) {\n\t\t\t\tconst elapsed = playhead - loopStartSamples;\n\t\t\t\tconst n = Math.min(Math.floor(endIndex - playhead), SAMPLE_BLOCK_SIZE);\n\t\t\t\tfor (let i = 0; i < n; i++) {\n\t\t\t\t\tconst position = (elapsed + i) / xfadeNumSamples;\n\t\t\t\t\tconst g = Math.cos((Math.PI * position) / 2);\n\t\t\t\t\tconst srcIdx = Math.floor(\n\t\t\t\t\t\tloopEndSamples - xfadeNumSamples + elapsed + i,\n\t\t\t\t\t);\n\t\t\t\t\tif (srcIdx >= 0 && srcIdx < sourceLength) {\n\t\t\t\t\t\tfor (let ch = 0; ch < nc; ch++) {\n\t\t\t\t\t\t\toutput0[ch][i] += buffer[ch][srcIdx] * g;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Crossfade in approaching loop end: fade in head of next loop iteration.\n\t\t// Source: reads from START of loop (loopStart to loopStart + xfade).\n\t\t{\n\t\t\tconst startIndex = loopEndSamples - xfadeNumSamples;\n\t\t\tif (\n\t\t\t\txfadeNumSamples > 0 &&\n\t\t\t\tplayhead > startIndex &&\n\t\t\t\tplayhead < loopEndSamples\n\t\t\t) {\n\t\t\t\tconst elapsed = playhead - startIndex;\n\t\t\t\tconst n = Math.min(\n\t\t\t\t\tMath.floor(loopEndSamples - playhead),\n\t\t\t\t\tSAMPLE_BLOCK_SIZE,\n\t\t\t\t);\n\t\t\t\tfor (let i = 0; i < n; i++) {\n\t\t\t\t\tconst position = (elapsed + i) / xfadeNumSamples;\n\t\t\t\t\tconst g = Math.sin((Math.PI * position) / 2);\n\t\t\t\t\tconst srcIdx = Math.floor(loopStartSamples + elapsed + i);\n\t\t\t\t\tif (srcIdx >= 0 && srcIdx < sourceLength) {\n\t\t\t\t\t\tfor (let ch = 0; ch < nc; ch++) {\n\t\t\t\t\t\t\toutput0[ch][i] += buffer[ch][srcIdx] * g;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// --- Fade in ---\n\tif (enableFadeIn && fadeInDuration > 0) {\n\t\tconst fadeInSamples = Math.floor(fadeInDuration * ctx.sampleRate);\n\t\tconst remaining = fadeInSamples - playedSamples;\n\t\tif (remaining > 0) {\n\t\t\tconst n = Math.min(remaining, SAMPLE_BLOCK_SIZE);\n\t\t\tfor (let i = 0; i < n; i++) {\n\t\t\t\tconst t = (playedSamples + i) / fadeInSamples;\n\t\t\t\tconst g = t * t * t; // cubic: slow start, fast finish\n\t\t\t\tfor (let ch = 0; ch < nc; ch++) {\n\t\t\t\t\toutput0[ch][i] *= g;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// --- Fade out ---\n\tif (enableFadeOut && fadeOutDuration > 0) {\n\t\tconst fadeOutSamples = Math.floor(fadeOutDuration * ctx.sampleRate);\n\t\tconst remainingSamples = Math.floor(\n\t\t\tctx.sampleRate * (stopWhen - ctx.currentTime),\n\t\t);\n\t\tif (remainingSamples < fadeOutSamples + SAMPLE_BLOCK_SIZE) {\n\t\t\tfor (let i = 0; i < SAMPLE_BLOCK_SIZE; i++) {\n\t\t\t\tconst sampleRemaining = remainingSamples - i;\n\t\t\t\tif (sampleRemaining >= fadeOutSamples) continue; // not yet in fade zone\n\t\t\t\tconst t = sampleRemaining <= 0 ? 0 : sampleRemaining / fadeOutSamples;\n\t\t\t\tconst g = t * t * t; // cubic fade-out: fast drop, slow tail\n\t\t\t\tfor (let ch = 0; ch < nc; ch++) {\n\t\t\t\t\toutput0[ch][i] *= g;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// --- Filters ---\n\tif (enableLowpass)\n\t\tlowpassFilter(output0, lowpass, ctx.sampleRate, filterState.lowpass);\n\tif (enableHighpass)\n\t\thighpassFilter(output0, highpass, ctx.sampleRate, filterState.highpass);\n\tif (enableGain) gainFilter(output0, gains);\n\tif (nc === 1) monoToStereo(output0);\n\tif (enablePan) panFilter(output0, pans);\n\n\tif (looped) {\n\t\tprops.timesLooped++;\n\t\tmessages.push({ type: \"looped\", data: props.timesLooped });\n\t}\n\tif (ended) {\n\t\tprops.state = State.Ended;\n\t\tmessages.push({ type: \"ended\" });\n\t}\n\n\tprops.playedSamples += indexes.length;\n\tprops.playhead = updatedPlayhead;\n\n\tconst numNans = checkNans(output0);\n\tif (numNans > 0) {\n\t\tconsole.log({\n\t\t\tnumNans,\n\t\t\tindexes,\n\t\t\tplayhead: updatedPlayhead,\n\t\t\tended,\n\t\t\tlooped,\n\t\t\tsourceLength,\n\t\t});\n\t\treturn { keepAlive: true, messages };\n\t}\n\n\tfor (let i = 1; i < outputs.length; i++) {\n\t\tcopy(output0, outputs[i]);\n\t}\n\treturn { keepAlive: true, messages };\n}\n",
7
+ "// AudioWorklet processor — runs in AudioWorkletGlobalScope\n// Bundled separately and served at /processor.js\n// This is a thin shell — all DSP logic lives in processor-kernel.ts\n\ndeclare const currentTime: number;\ndeclare const currentFrame: number;\ndeclare const sampleRate: number;\ndeclare class AudioWorkletProcessor {\n\treadonly port: MessagePort;\n\tconstructor(options?: AudioWorkletNodeOptions);\n\tprocess(\n\t\tinputs: Float32Array[][],\n\t\toutputs: Float32Array[][],\n\t\tparameters: Record<string, Float32Array>,\n\t): boolean;\n}\n\ndeclare function registerProcessor(\n\tname: string,\n\tctor: new (options?: AudioWorkletNodeOptions) => AudioWorkletProcessor,\n): void;\n\nimport {\n\tcreateFilterState,\n\tgetProperties,\n\thandleProcessorMessage,\n\tprocessBlock,\n} from \"./processor-kernel\";\nimport type { ClipProcessorOptions, ProcessorWorkletOptions } from \"./types\";\nimport { State } from \"./types\";\n\nclass ClipProcessor extends AudioWorkletProcessor {\n\tstatic get parameterDescriptors() {\n\t\treturn [\n\t\t\t{\n\t\t\t\tname: \"playbackRate\",\n\t\t\t\tautomationRate: \"a-rate\" as const,\n\t\t\t\tdefaultValue: 1.0,\n\t\t\t},\n\t\t\t{ name: \"detune\", automationRate: \"a-rate\" as const, defaultValue: 0 },\n\t\t\t{\n\t\t\t\tname: \"gain\",\n\t\t\t\tautomationRate: \"a-rate\" as const,\n\t\t\t\tdefaultValue: 1,\n\t\t\t\tminValue: 0,\n\t\t\t},\n\t\t\t{ name: \"pan\", automationRate: \"a-rate\" as const, defaultValue: 0 },\n\t\t\t{\n\t\t\t\tname: \"highpass\",\n\t\t\t\tautomationRate: \"a-rate\" as const,\n\t\t\t\tdefaultValue: 20,\n\t\t\t\tminValue: 20,\n\t\t\t\tmaxValue: 20000,\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"lowpass\",\n\t\t\t\tautomationRate: \"a-rate\" as const,\n\t\t\t\tdefaultValue: 20000,\n\t\t\t\tminValue: 20,\n\t\t\t\tmaxValue: 20000,\n\t\t\t},\n\t\t];\n\t}\n\n\tproperties: Required<ClipProcessorOptions>;\n\tprivate filterState = {\n\t\tlowpass: createFilterState(),\n\t\thighpass: createFilterState(),\n\t};\n\tprivate lastFrameTime = 0;\n\n\tconstructor(options?: ProcessorWorkletOptions) {\n\t\tsuper(options);\n\t\tthis.properties = getProperties(options?.processorOptions, sampleRate);\n\t\tthis.port.onmessage = (ev: MessageEvent) => {\n\t\t\tconst messages = handleProcessorMessage(\n\t\t\t\tthis.properties,\n\t\t\t\tev.data,\n\t\t\t\tcurrentTime,\n\t\t\t\tsampleRate,\n\t\t\t);\n\t\t\tfor (const msg of messages) this.port.postMessage(msg);\n\t\t\tif (this.properties.state === State.Disposed) this.port.close();\n\t\t};\n\t}\n\n\tprocess(\n\t\t_inputs: Float32Array[][],\n\t\toutputs: Float32Array[][],\n\t\tparameters: Record<string, Float32Array>,\n\t): boolean {\n\t\ttry {\n\t\t\tconst result = processBlock(\n\t\t\t\tthis.properties,\n\t\t\t\toutputs,\n\t\t\t\tparameters,\n\t\t\t\t{ currentTime, currentFrame, sampleRate },\n\t\t\t\tthis.filterState,\n\t\t\t);\n\t\t\tfor (const msg of result.messages) this.port.postMessage(msg);\n\n\t\t\t// Frame reporting\n\t\t\tconst timeTaken = currentTime - this.lastFrameTime;\n\t\t\tthis.lastFrameTime = currentTime;\n\t\t\tthis.port.postMessage({\n\t\t\t\ttype: \"frame\",\n\t\t\t\tdata: [\n\t\t\t\t\tcurrentTime,\n\t\t\t\t\tcurrentFrame,\n\t\t\t\t\tMath.floor(this.properties.playhead),\n\t\t\t\t\ttimeTaken * 1000,\n\t\t\t\t],\n\t\t\t});\n\n\t\t\treturn result.keepAlive;\n\t\t} catch (e) {\n\t\t\tconsole.log(e);\n\t\t\treturn true;\n\t\t}\n\t}\n}\n\nregisterProcessor(\"ClipProcessor\", ClipProcessor);\n"
8
+ ],
9
+ "mappings": "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",
10
+ "debugId": "5101232AAE128B1064756E2164756E21",
11
+ "names": []
12
+ }
@@ -0,0 +1,63 @@
1
+ import { type ControlKey } from "../controls/controlDefs";
2
+ import { type LinkedControlPairKey } from "../controls/linkedControlPairs";
3
+ export interface ClipControlsState {
4
+ values: Record<ControlKey, number>;
5
+ snaps: Record<ControlKey, string>;
6
+ enabled: Record<ControlKey, boolean>;
7
+ mins: Record<ControlKey, number>;
8
+ maxs: Record<ControlKey, number>;
9
+ maxLocked: Record<ControlKey, boolean>;
10
+ linkedPairs: Record<LinkedControlPairKey, boolean>;
11
+ loop: boolean;
12
+ tempo: number;
13
+ setValue: (key: ControlKey, val: number) => void;
14
+ setValuesPartial: (values: Partial<Record<ControlKey, number>>) => void;
15
+ setSnap: (key: ControlKey, snap: string) => void;
16
+ setSnapsPartial: (snaps: Partial<Record<ControlKey, string>>) => void;
17
+ setEnabled: (key: ControlKey, on: boolean) => void;
18
+ setEnabledPartial: (enabled: Partial<Record<ControlKey, boolean>>) => void;
19
+ setMin: (key: ControlKey, val: number) => void;
20
+ setMinsPartial: (mins: Partial<Record<ControlKey, number>>) => void;
21
+ setMax: (key: ControlKey, val: number) => void;
22
+ setMaxsPartial: (maxs: Partial<Record<ControlKey, number>>) => void;
23
+ setMaxLocked: (key: ControlKey, locked: boolean) => void;
24
+ setMaxLockedPartial: (maxLocked: Partial<Record<ControlKey, boolean>>) => void;
25
+ setLinkedPair: (key: LinkedControlPairKey, on: boolean) => void;
26
+ setLoop: (checked: boolean) => void;
27
+ setTempo: (tempo: number) => void;
28
+ setTempoAndValues: (tempo: number, values: Partial<Record<ControlKey, number>>) => void;
29
+ setValues: (values: Record<ControlKey, number>) => void;
30
+ }
31
+ export declare const useClipControls: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<ClipControlsState>, "setState" | "persist"> & {
32
+ setState(partial: ClipControlsState | Partial<ClipControlsState> | ((state: ClipControlsState) => ClipControlsState | Partial<ClipControlsState>), replace?: false | undefined): unknown;
33
+ setState(state: ClipControlsState | ((state: ClipControlsState) => ClipControlsState), replace: true): unknown;
34
+ persist: {
35
+ setOptions: (options: Partial<import("zustand/middleware").PersistOptions<ClipControlsState, {
36
+ values: Record<ControlKey, number>;
37
+ snaps: Record<ControlKey, string>;
38
+ enabled: Record<ControlKey, boolean>;
39
+ mins: Record<ControlKey, number>;
40
+ maxs: Record<ControlKey, number>;
41
+ maxLocked: Record<ControlKey, boolean>;
42
+ linkedPairs: Record<LinkedControlPairKey, boolean>;
43
+ loop: boolean;
44
+ tempo: number;
45
+ }, unknown>>) => void;
46
+ clearStorage: () => void;
47
+ rehydrate: () => Promise<void> | void;
48
+ hasHydrated: () => boolean;
49
+ onHydrate: (fn: (state: ClipControlsState) => void) => () => void;
50
+ onFinishHydration: (fn: (state: ClipControlsState) => void) => () => void;
51
+ getOptions: () => Partial<import("zustand/middleware").PersistOptions<ClipControlsState, {
52
+ values: Record<ControlKey, number>;
53
+ snaps: Record<ControlKey, string>;
54
+ enabled: Record<ControlKey, boolean>;
55
+ mins: Record<ControlKey, number>;
56
+ maxs: Record<ControlKey, number>;
57
+ maxLocked: Record<ControlKey, boolean>;
58
+ linkedPairs: Record<LinkedControlPairKey, boolean>;
59
+ loop: boolean;
60
+ tempo: number;
61
+ }, unknown>>;
62
+ };
63
+ }>;