@jadujoel/web-audio-clip-node 0.1.5 → 0.1.6

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 (36) hide show
  1. package/README.md +50 -4
  2. package/dist/audio/ClipNode.js +1 -1
  3. package/dist/audio/processor-kernel.js +1 -1
  4. package/dist/audio/processor.js +2 -2
  5. package/dist/audio/version.d.ts +1 -1
  6. package/dist/audio/version.js +1 -1
  7. package/dist/audio/workletUrl.js +2 -2
  8. package/dist/components/AudioControl.js +4 -4
  9. package/dist/components/ControlSection.js +1 -1
  10. package/dist/components/DetuneControl.js +2 -2
  11. package/dist/components/FilterControl.js +2 -2
  12. package/dist/components/GainControl.js +2 -2
  13. package/dist/components/PanControl.js +2 -2
  14. package/dist/components/PlaybackRateControl.js +2 -2
  15. package/dist/components/PlayheadSlider.js +2 -2
  16. package/dist/hooks/useClipNode.js +7 -7
  17. package/dist/lib-react.js +14 -14
  18. package/dist/lib.bundle.js +1 -1
  19. package/dist/lib.bundle.js.map +1 -1
  20. package/dist/lib.js +11 -11
  21. package/dist/store/clipStore.js +2 -2
  22. package/dist/styles.css.d.ts +3 -0
  23. package/examples/cdn-vanilla/index.html +2 -2
  24. package/examples/esm-bundler/package.json +1 -1
  25. package/examples/index.html +16 -0
  26. package/examples/react/README.md +1 -1
  27. package/examples/react/bun.lock +45 -0
  28. package/examples/react/src/App.tsx +56 -6
  29. package/examples/react/src/css.d.ts +1 -0
  30. package/examples/react/tsconfig.json +15 -0
  31. package/examples/self-hosted/package.json +2 -4
  32. package/examples/self-hosted/public/processor.js +4 -0
  33. package/examples/self-hosted/src/main.ts +1 -3
  34. package/package.json +6 -2
  35. package/examples/esm-bundler/bun.lock +0 -15
  36. package/examples/self-hosted/bun.lock +0 -15
@@ -17,7 +17,7 @@
17
17
  <p id="status">Click Play to start (loads a sample tone).</p>
18
18
  <script type="module">
19
19
  // Import the bundled library from the CDN (single file, no module resolution needed)
20
- import { ClipNode } from "https://cdn.jsdelivr.net/npm/@jadujoel/web-audio-clip-node/dist/lib.bundle.js";
20
+ import { ClipNode } from "https://cdn.jsdelivr.net/npm/@jadujoel/web-audio-clip-node@latest/dist/lib.bundle.js";
21
21
 
22
22
  const status = document.getElementById("status");
23
23
  let ctx;
@@ -37,7 +37,7 @@
37
37
  document.getElementById("play").addEventListener("click", async () => {
38
38
  if (!ctx) {
39
39
  ctx = new AudioContext();
40
- await ctx.audioWorklet.addModule("https://cdn.jsdelivr.net/npm/@jadujoel/web-audio-clip-node/dist/processor.js");
40
+ await ctx.audioWorklet.addModule("https://cdn.jsdelivr.net/npm/@jadujoel/web-audio-clip-node@latest/dist/processor.js");
41
41
  clip = new ClipNode(ctx);
42
42
  clip.connect(ctx.destination);
43
43
  clip.buffer = createToneBuffer(ctx);
@@ -7,6 +7,6 @@
7
7
  "build": "bun build ./src/main.ts --outdir=dist --minify"
8
8
  },
9
9
  "dependencies": {
10
- "@jadujoel/web-audio-clip-node": "latest"
10
+ "@jadujoel/web-audio-clip-node": "file:../.."
11
11
  }
12
12
  }
@@ -0,0 +1,16 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Examples</title>
7
+ </head>
8
+ <body>
9
+ <ul>
10
+ <li><a href="cdn-vanilla">Vanilla</a>
11
+ <li><a href="esm-bundler">ESM Bundler</a></li>
12
+ <li><a href="react">React</a></li>
13
+ <li><a href="self-hosted">Self Hosted</a></li>
14
+ </ul>
15
+ </body>
16
+ </html>
@@ -7,4 +7,4 @@ bun install
7
7
  bun index.html
8
8
  ```
9
9
 
10
- Uses `useClipNode` + `useClipControls` to wire everything up, and renders `<TransportButtons />` and `<AudioControl />` out of the box.
10
+ Uses `useClipNode` + `useClipControls` to wire up `TransportButtons`, `PlaybackRateControl`, and `GainControl` with valid props.
@@ -0,0 +1,45 @@
1
+ {
2
+ "lockfileVersion": 1,
3
+ "configVersion": 1,
4
+ "workspaces": {
5
+ "": {
6
+ "name": "react-example",
7
+ "dependencies": {
8
+ "@jadujoel/web-audio-clip-node": "latest",
9
+ "react": "^19",
10
+ "react-dom": "^19",
11
+ "zustand": "^5",
12
+ },
13
+ "devDependencies": {
14
+ "@types/bun": "latest",
15
+ "@types/react": "^19",
16
+ "@types/react-dom": "^19",
17
+ },
18
+ },
19
+ },
20
+ "packages": {
21
+ "@jadujoel/web-audio-clip-node": ["@jadujoel/web-audio-clip-node@0.1.5", "", { "peerDependencies": { "react": ">=18", "react-dom": ">=18", "zustand": ">=4" }, "optionalPeers": ["react", "react-dom", "zustand"] }, "sha512-q4aUslRnuRqscWh5W6GWnPC1H2HXArHbt7aeiQM+EbmlSmL9WmOHqfMIqaIi6ByzIZsrV395va1zKLoBKwiaHA=="],
22
+
23
+ "@types/bun": ["@types/bun@1.3.12", "", { "dependencies": { "bun-types": "1.3.12" } }, "sha512-DBv81elK+/VSwXHDlnH3Qduw+KxkTIWi7TXkAeh24zpi5l0B2kUg9Ga3tb4nJaPcOFswflgi/yAvMVBPrxMB+A=="],
24
+
25
+ "@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
26
+
27
+ "@types/react": ["@types/react@19.2.14", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w=="],
28
+
29
+ "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
30
+
31
+ "bun-types": ["bun-types@1.3.12", "", { "dependencies": { "@types/node": "*" } }, "sha512-HqOLj5PoFajAQciOMRiIZGNoKxDJSr6qigAttOX40vJuSp6DN/CxWp9s3C1Xwm4oH7ybueITwiaOcWXoYVoRkA=="],
32
+
33
+ "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="],
34
+
35
+ "react": ["react@19.2.5", "", {}, "sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA=="],
36
+
37
+ "react-dom": ["react-dom@19.2.5", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.5" } }, "sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag=="],
38
+
39
+ "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
40
+
41
+ "undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
42
+
43
+ "zustand": ["zustand@5.0.12", "", { "peerDependencies": { "@types/react": ">=18.0.0", "immer": ">=9.0.6", "react": ">=18.0.0", "use-sync-external-store": ">=1.2.0" }, "optionalPeers": ["@types/react", "immer", "react", "use-sync-external-store"] }, "sha512-i77ae3aZq4dhMlRhJVCYgMLKuSiZAaUPAct2AksxQ+gOtimhGMdXljRT21P5BNpeT4kXlLIckvkPM029OljD7g=="],
44
+ }
45
+ }
@@ -1,5 +1,6 @@
1
1
  import {
2
- AudioControl,
2
+ GainControl,
3
+ PlaybackRateControl,
3
4
  TransportButtons,
4
5
  useClipControls,
5
6
  useClipNode,
@@ -8,13 +9,62 @@ import "@jadujoel/web-audio-clip-node/styles.css";
8
9
 
9
10
  export function App() {
10
11
  const controls = useClipControls();
11
- useClipNode({ ...controls });
12
+ const clip = useClipNode({
13
+ values: controls.values,
14
+ enabled: controls.enabled,
15
+ loop: controls.loop,
16
+ setValue: controls.setValue,
17
+ });
12
18
 
13
19
  return (
14
- <div style={{ maxWidth: 480, margin: "2rem auto", fontFamily: "system-ui, sans-serif" }}>
20
+ <main
21
+ style={{
22
+ maxWidth: 480,
23
+ margin: "2rem auto",
24
+ fontFamily: "system-ui, sans-serif",
25
+ display: "grid",
26
+ gap: "1rem",
27
+ }}
28
+ >
15
29
  <h1>ClipNode – React</h1>
16
- <TransportButtons />
17
- <AudioControl />
18
- </div>
30
+ <p>Load a sound, then drive ClipNode with the packaged React controls.</p>
31
+ <TransportButtons
32
+ nodeState={clip.nodeState}
33
+ onStart={clip.start}
34
+ onStop={clip.stop}
35
+ onPause={clip.pause}
36
+ onResume={clip.resume}
37
+ onDispose={clip.dispose}
38
+ onLog={clip.logState}
39
+ onLoadSound={clip.loadSound}
40
+ />
41
+ <PlaybackRateControl
42
+ value={controls.values.playbackRate}
43
+ defaultValue={1}
44
+ enabled={controls.enabled.playbackRate}
45
+ onChange={(value) => {
46
+ controls.setValue("playbackRate", value);
47
+ clip.applyValue("playbackRate", value);
48
+ }}
49
+ onToggle={(enabled) => {
50
+ controls.setEnabled("playbackRate", enabled);
51
+ clip.applyToggle("playbackRate", enabled);
52
+ }}
53
+ />
54
+ <GainControl
55
+ value={controls.values.gain}
56
+ defaultValue={0}
57
+ enabled={controls.enabled.gain}
58
+ onChange={(value) => {
59
+ controls.setValue("gain", value);
60
+ clip.applyValue("gain", value);
61
+ }}
62
+ onToggle={(enabled) => {
63
+ controls.setEnabled("gain", enabled);
64
+ clip.applyToggle("gain", enabled);
65
+ }}
66
+ />
67
+ {clip.statusMessage ? <p>{clip.statusMessage}</p> : null}
68
+ </main>
19
69
  );
20
70
  }
@@ -0,0 +1 @@
1
+ declare module "@jadujoel/web-audio-clip-node/styles.css";
@@ -0,0 +1,15 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "jsx": "react-jsx",
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "lib": ["ESNext", "DOM", "DOM.Iterable"],
12
+ "noEmit": true
13
+ },
14
+ "include": ["src"]
15
+ }
@@ -3,11 +3,9 @@
3
3
  "private": true,
4
4
  "type": "module",
5
5
  "scripts": {
6
- "setup": "cp node_modules/@jadujoel/web-audio-clip-node/dist/processor.js public/processor.js",
6
+ "setup": "cp ../../dist/processor.js public/processor.js",
7
7
  "dev": "bun index.html",
8
8
  "build": "bun build ./src/main.ts --outdir=dist --minify"
9
9
  },
10
- "dependencies": {
11
- "@jadujoel/web-audio-clip-node": "^0.1.1"
12
- }
10
+ "dependencies": {}
13
11
  }
@@ -0,0 +1,4 @@
1
+ var P={Initial:0,Started:1,Stopped:2,Paused:3,Scheduled:4,Ended:5,Disposed:6};var _=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:_*4,lowWaterNotified:!1,lastUnderrunSample:null}}function G0(V){return V[0]?.length??0}function o(V){return V.streamBuffer.totalLength??G0(V.buffer)}function H0(V,A){return Array.from({length:V},()=>new Float32Array(A))}function E0(V,A){let F=[...V,A].sort((J,k)=>J.startSample-k.startSample),T=[];for(let J of F){let k=T[T.length-1];if(!k||J.startSample>k.endSample){T.push({...J});continue}k.endSample=Math.max(k.endSample,J.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=G0(V.buffer),J=V.buffer.length;if(T>=F&&J>=A)return;let k=Math.max(T,F),Q=Math.max(J,A),X=H0(Q,k);for(let U=0;U<J;U++)X[U].set(V.buffer[U].subarray(0,T));if(V.buffer=X,V.streamBuffer.totalLength==null||V.streamBuffer.totalLength<k)V.streamBuffer.totalLength=k}function B0(V,A){let F=Math.max(Math.floor(A.startSample),0),T=A.channelData[0]?.length??0,J=A.totalLength??null,k=Math.max(F+T,J??0);R0(V,Math.max(A.channelData.length,V.buffer.length,1),k);for(let Q=0;Q<A.channelData.length;Q++)V.buffer[Q].set(A.channelData[Q],F);if(J!=null)V.streamBuffer.totalLength=J;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 y0(V){if(V.streamBuffer.pendingWrites.length===0)return;for(let A of V.streamBuffer.pendingWrites)B0(V,A);V.streamBuffer.pendingWrites=[]}function _0(V,A){V.buffer=A,V.streamBuffer=i(A)}function v0(V={},A){let{buffer:F=[],streamBuffer:T=i(F),duration:J=-1,loop:k=!1,loopStart:Q=0,loopEnd:X=(F[0]?.length??0)/A,loopCrossfade:U=0,playhead:$=0,offset:M=0,startWhen:Y=0,stopWhen:j=0,pauseWhen:z=0,resumeWhen:C=0,playedSamples:N=0,state:K=P.Initial,timesLooped:w=0,fadeInDuration:v=0,fadeOutDuration:Z=0,enableFadeIn:E=v>0,enableFadeOut:O=Z>0,enableLoopStart:R=!0,enableLoopEnd:d=!0,enableLoopCrossfade:b=U>0,enableHighpass:c=!0,enableLowpass:g=!0,enableGain:s=!0,enablePan:t=!0,enableDetune:r=!0,enablePlaybackRate:p=!0}=V;return{buffer:F,streamBuffer:T,loop:k,loopStart:Q,loopEnd:X,loopCrossfade:U,duration:J,playhead:$,offset:M,startWhen:Y,stopWhen:j,pauseWhen:z,resumeWhen:C,playedSamples:N,state:K,timesLooped:w,fadeInDuration:v,fadeOutDuration:Z,enableFadeIn:E,enableFadeOut:O,enableLoopStart:R,enableLoopEnd:d,enableHighpass:c,enableLowpass:g,enableGain:s,enablePan:t,enableDetune:r,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:J,loopEndSamples:k}=V,Q=128;if(!T&&A+128>F)Q=Math.max(F-A,0);let X=Array(Q);if(!T){for(let Y=0,j=A;Y<Q;Y++,j++)X[Y]=j;let M=A+Q;return{playhead:M,indexes:X,looped:!1,ended:M>=F}}let U=A,$=!1;for(let M=0;M<Q;M++,U++){if(U>=k)U=J+(U-k),$=!0;X[M]=U}return{indexes:X,looped:$,ended:!1,playhead:U}}function x0(V){let{playhead:A,bufferLength:F,loop:T,loopStartSamples:J,loopEndSamples:k,playbackRates:Q}=V,X=128;if(!T&&A+128>F)X=Math.max(F-A,0);let U=Array(X),$=A,M=!1;if(T){for(let Y=0;Y<X;Y++){U[Y]=Math.min(Math.max(Math.floor($),0),F-1);let j=Q[Y]??Q[0]??1;if($+=j,j>=0&&($>k||$>F))$=J,M=!0;else if(j<0&&($<J||$<0))$=k,M=!0}return{playhead:$,indexes:U,looped:M,ended:!1}}for(let Y=0;Y<X;Y++)U[Y]=Math.min(Math.max(Math.floor($),0),F-1),$+=Q[Y]??Q[0]??1;return{playhead:$,indexes:U,looped:!1,ended:$>=F||$<0}}function m0(V,A,F){let T=Math.min(V.length,A.length);for(let J=0;J<F.length;J++)for(let k=0;k<T;k++)V[k][J]=A[k][F[J]];for(let J=T;J<V.length;J++)for(let k=0;k<V[J].length;k++)V[J][k]=0;for(let J=F.length;J<V[0].length;J++)for(let k=0;k<T;k++)V[k][J]=0}function h(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){if(V.length>=2)for(let A=0;A<V[0].length;A++)V[1][A]=V[0][A];else{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 M0(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 J of V)for(let k=0;k<J.length;k++)J[k]*=T;return}let F=A[0];for(let T of V)for(let J=0;J<T.length;J++)F=A[J]??F,T[J]*=F}function h0(V,A){let F=A[0];for(let T=0;T<V[0].length;T++){F=A[T]??F;let J=F<=0?1:1-F,k=F>=0?1:1+F;V[0][T]*=J,V[1][T]*=k}}function d0(V,A,F,T){for(let J=0;J<V.length;J++){let k=V[J],{x_1:Q,x_2:X,y_1:U,y_2:$}=T[J]??{x_1:0,x_2:0,y_1:0,y_2:0};if(A.length===1){let M=A[0];if(M>=20000)return;let Y=2*Math.PI*M/F,j=Math.sin(Y)/2,z=(1-Math.cos(Y))/2,C=1-Math.cos(Y),N=(1-Math.cos(Y))/2,K=1+j,w=-2*Math.cos(Y),v=1-j,Z=z/K,E=C/K,O=N/K,R=w/K,d=v/K;for(let b=0;b<k.length;b++){let c=k[b],g=Z*c+E*Q+O*X-R*U-d*$;X=Q,Q=c,$=U,U=g,k[b]=g}}else{let M=A[0];for(let Y=0;Y<k.length;Y++){let j=A[Y]??M,z=2*Math.PI*j/F,C=Math.sin(z)/2,N=(1-Math.cos(z))/2,K=1-Math.cos(z),w=(1-Math.cos(z))/2,v=1+C,Z=-2*Math.cos(z),E=1-C,O=k[Y],R=N/v*O+K/v*Q+w/v*X-Z/v*U-E/v*$;X=Q,Q=O,$=U,U=R,k[Y]=R}}T[J]={x_1:Q,x_2:X,y_1:U,y_2:$}}}function u0(V,A,F,T){for(let J=0;J<V.length;J++){let k=V[J],{x_1:Q,x_2:X,y_1:U,y_2:$}=T[J]??{x_1:0,x_2:0,y_1:0,y_2:0};if(A.length===1){let M=A[0];if(M<=20)return;let Y=2*Math.PI*M/F,j=Math.sin(Y)/2,z=(1+Math.cos(Y))/2,C=-(1+Math.cos(Y)),N=(1+Math.cos(Y))/2,K=1+j,w=-2*Math.cos(Y),v=1-j;for(let Z=0;Z<k.length;Z++){let E=k[Z],O=z/K*E+C/K*Q+N/K*X-w/K*U-v/K*$;X=Q,Q=E,$=U,U=O,k[Z]=O}}else{let M=A[0];for(let Y=0;Y<k.length;Y++){let j=A[Y]??M,z=2*Math.PI*j/F,C=Math.sin(z)/2,N=(1+Math.cos(z))/2,K=-(1+Math.cos(z)),w=(1+Math.cos(z))/2,v=1+C,Z=-2*Math.cos(z),E=1-C,O=k[Y],R=N/v*O+K/v*Q+w/v*X-Z/v*U-E/v*$;X=Q,Q=O,$=U,U=R,k[Y]=R}}T[J]={x_1:Q,x_2:X,y_1:U,y_2:$}}}function P0(V,A,F,T){let{type:J,data:k}=A;switch(J){case"buffer":return _0(V,k),n(V,T),[];case"bufferInit":{let Q=k;return V.buffer=H0(Q.channels,Q.totalLength),V.streamBuffer={...i(),totalLength:Q.totalLength,streamEnded:!1,streaming:Q.streaming??!0},n(V,T),[]}case"bufferRange":return V.streamBuffer.pendingWrites.push(k),[];case"bufferEnd":{let Q=k;if(Q?.totalLength!=null)V.streamBuffer.totalLength=Q.totalLength;return V.streamBuffer.streamEnded=!0,[]}case"bufferReset":return V.buffer=[],V.streamBuffer=i(),n(V,T),[];case"start":V.timesLooped=0;{let Q=k;if(V.duration=Q?.duration??-1,V.duration===-1)V.duration=V.loop?Number.MAX_SAFE_INTEGER:(V.buffer[0]?.length??0)/T;e(V,Q?.offset,T),n(V,T),V.playhead=V.offset,V.startWhen=Q?.when??F,V.stopWhen=V.startWhen+V.duration,V.playedSamples=0,V.state=P.Scheduled}return[{type:"scheduled"}];case"stop":if(V.state===P.Ended||V.state===P.Initial)return[];return V.stopWhen=k??V.stopWhen,V.state=P.Stopped,[{type:"stopped"}];case"pause":return V.state=P.Paused,V.pauseWhen=k??F,[{type:"paused"}];case"resume":return V.state=P.Started,V.startWhen=k??F,[{type:"resume"}];case"dispose":return V.state=P.Disposed,V.buffer=[],V.streamBuffer=i(),[{type:"disposed"}];case"loop":{let Q=k,X=V.state;if(Q&&(X===P.Scheduled||X===P.Started))V.stopWhen=Number.MAX_SAFE_INTEGER,V.duration=Number.MAX_SAFE_INTEGER;if(V.loop=Q,Q)n(V,T);return[]}case"loopStart":return V.loopStart=k,[];case"loopEnd":return V.loopEnd=k,[];case"loopCrossfade":return V.loopCrossfade=k,[];case"playhead":return V.playhead=Math.floor(k),[];case"fadeIn":return V.fadeInDuration=k,[];case"fadeOut":return V.fadeOutDuration=k,[];case"toggleGain":return V.enableGain=k??!V.enableGain,[];case"togglePan":return V.enablePan=k??!V.enablePan,[];case"toggleLowpass":return V.enableLowpass=k??!V.enableLowpass,[];case"toggleHighpass":return V.enableHighpass=k??!V.enableHighpass,[];case"toggleDetune":return V.enableDetune=k??!V.enableDetune,[];case"togglePlaybackRate":return V.enablePlaybackRate=k??!V.enablePlaybackRate,[];case"toggleFadeIn":return V.enableFadeIn=k??!V.enableFadeIn,[];case"toggleFadeOut":return V.enableFadeOut=k??!V.enableFadeOut,[];case"toggleLoopStart":return V.enableLoopStart=k??!V.enableLoopStart,[];case"toggleLoopEnd":return V.enableLoopEnd=k??!V.enableLoopEnd,[];case"toggleLoopCrossfade":return V.enableLoopCrossfade=k??!V.enableLoopCrossfade,[];case"logState":return[]}return[]}function j0(V,A,F,T,J){let k=[],Q=V.state;if(Q===P.Disposed)return{keepAlive:!1,messages:k};if(y0(V),Q===P.Initial)return{keepAlive:!0,messages:k};if(Q===P.Ended)return h(A[0]),{keepAlive:!0,messages:k};if(Q===P.Scheduled)if(T.currentTime>=V.startWhen)Q=V.state=P.Started,k.push({type:"started"});else return h(A[0]),{keepAlive:!0,messages:k};else if(Q===P.Paused){if(T.currentTime>V.pauseWhen)return h(A[0]),{keepAlive:!0,messages:k}}if(T.currentTime>V.stopWhen)return h(A[0]),V.state=P.Ended,k.push({type:"ended"}),V.playedSamples=0,{keepAlive:!0,messages:k};let X=A[0],U=o(V);if(U===0)return h(X),{keepAlive:!0,messages:k};let{playbackRate:$,detune:M,lowpass:Y,highpass:j,gain:z,pan:C}=F,{buffer:N,loopStart:K,loopEnd:w,loopCrossfade:v,stopWhen:Z,playedSamples:E,enableLowpass:O,enableHighpass:R,enableGain:d,enablePan:b,enableDetune:c,enableFadeOut:g,enableFadeIn:s,enableLoopStart:t,enableLoopEnd:r,enableLoopCrossfade:p,playhead:D,fadeInDuration:A0,fadeOutDuration:F0}=V,K0=V.streamBuffer.streaming&&V.streamBuffer.committedLength<U,k0=V.loop&&!K0,u=Math.min(N.length,X.length),W0=V.duration*T.sampleRate,Z0=Math.floor(T.sampleRate*v),q0=Math.max(U-_,0),L=t?Math.min(Math.floor(K*T.sampleRate),q0):0,x=r?Math.min(Math.floor(w*T.sampleRate),U):U,N0=x-L,T0=c&&M.length>0&&M[0]!==0,l=$;if(T0){let G=Math.max($.length,M.length,_);l=new Float32Array(G);for(let W=0;W<G;W++){let I=$[W]??$[$.length-1],H=M[W]??M[M.length-1];l[W]=I*2**(H/1200)}}let J0=V.enablePlaybackRate||T0,O0=J0&&l.length>0&&l.every((G)=>G===0);if(V.streamBuffer.streaming&&!V.streamBuffer.streamEnded&&!V.streamBuffer.lowWaterNotified&&V.streamBuffer.committedLength-Math.floor(D)<V.streamBuffer.lowWaterThreshold)k.push({type:"bufferLowWater",data:{playhead:Math.floor(D),committedLength:V.streamBuffer.committedLength}}),V.streamBuffer.lowWaterNotified=!0;if(O0){h(X);for(let G=1;G<A.length;G++)M0(X,A[G]);return{keepAlive:!0,messages:k}}let Q0={bufferLength:U,loop:k0,playhead:D,loopStartSamples:L,loopEndSamples:x,durationSamples:W0,playbackRates:l},{indexes:a,ended:U0,looped:X0,playhead:Y0}=J0?x0(Q0):L0(Q0),f=a.find((G)=>G>=V.streamBuffer.committedLength&&G<U);if(f!==void 0&&!V.streamBuffer.streamEnded&&V.streamBuffer.lastUnderrunSample!==f)k.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(X,N,a);let m=Math.min(Math.floor(v*T.sampleRate),N0),D0=k0&&D>L&&D<x,C0=p&&Z0>0&&U>_;if(D0&&C0){{let G=L+m;if(m>0&&D>L&&D<G){let W=D-L,I=Math.min(Math.floor(G-D),_);for(let H=0;H<I;H++){let B=(W+H)/m,S=Math.cos(Math.PI*B/2),q=Math.floor(x-m+W+H);if(q>=0&&q<U)for(let y=0;y<u;y++)X[y][H]+=N[y][q]*S}}}{let G=x-m;if(m>0&&D>G&&D<x){let W=D-G,I=Math.min(Math.floor(x-D),_);for(let H=0;H<I;H++){let B=(W+H)/m,S=Math.sin(Math.PI*B/2),q=Math.floor(L+W+H);if(q>=0&&q<U)for(let y=0;y<u;y++)X[y][H]+=N[y][q]*S}}}}if(s&&A0>0){let G=Math.floor(A0*T.sampleRate),W=G-E;if(W>0){let I=Math.min(W,_);for(let H=0;H<I;H++){let B=(E+H)/G,S=B*B*B;for(let q=0;q<u;q++)X[q][H]*=S}}}if(g&&F0>0){let G=Math.floor(F0*T.sampleRate),W=Math.floor(T.sampleRate*(Z-T.currentTime));if(W<G+_)for(let I=0;I<_;I++){let H=W-I;if(H>=G)continue;let B=H<=0?0:H/G,S=B*B*B;for(let q=0;q<u;q++)X[q][I]*=S}}if(O)d0(X,Y,T.sampleRate,J.lowpass);if(R)u0(X,j,T.sampleRate,J.highpass);if(d)g0(X,z);if(u===1)S0(X);if(b)h0(X,C);if(X0)V.timesLooped++,k.push({type:"looped",data:V.timesLooped});if(U0)V.state=P.Ended,k.push({type:"ended"});V.playedSamples+=a.length,V.playhead=Y0;let $0=c0(X);if($0>0)return console.log({numNans:$0,indexes:a,playhead:Y0,ended:U0,looped:X0,sourceLength:U}),{keepAlive:!0,messages:k};for(let G=1;G<A.length;G++)M0(X,A[G]);return{keepAlive:!0,messages:k}}class z0 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=P0(this.properties,A.data,currentTime,sampleRate);for(let T of F)this.port.postMessage(T);if(this.properties.state===P.Disposed)this.port.close()}}process(V,A,F){try{let T=j0(this.properties,A,F,{currentTime,currentFrame,sampleRate},this.filterState);for(let k of T.messages)this.port.postMessage(k);let J=currentTime-this.lastFrameTime;return this.lastFrameTime=currentTime,this.port.postMessage({type:"frame",data:[currentTime,currentFrame,Math.floor(this.properties.playhead),J*1000]}),T.keepAlive}catch(T){return this.port.postMessage({type:"processorError",data:{error:String(T),state:this.properties.state,bufferChannels:this.properties.buffer?.length,bufferLength:this.properties.buffer?.[0]?.length,paramKeys:Object.keys(F),hasPlaybackRate:!!F.playbackRate,hasDetune:!!F.detune,hasGain:!!F.gain,hasPan:!!F.pan,outputChannels:A[0]?.length}}),!0}}}registerProcessor("ClipProcessor",z0);
2
+
3
+ //# debugId=12FC7555EABD465B64756E2164756E21
4
+ //# sourceMappingURL=processor.js.map
@@ -28,9 +28,7 @@ document.getElementById("play")!.addEventListener("click", async () => {
28
28
  // Load the processor from your own server (public/processor.js)
29
29
  const processorUrl = getProcessorModuleUrl(window.location.href);
30
30
  await ctx.audioWorklet.addModule(processorUrl);
31
- clip = new ClipNode(ctx, {
32
- processorOptions: { sampleRate: ctx.sampleRate },
33
- });
31
+ clip = new ClipNode(ctx);
34
32
  clip.connect(ctx.destination);
35
33
  clip.buffer = createToneBuffer(ctx);
36
34
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jadujoel/web-audio-clip-node",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "type": "module",
5
5
  "description": "Full-featured AudioWorklet clip player with playback rate, detune, gain, pan, filters, looping, fades, crossfade, and streaming buffer support. React components included.",
6
6
  "keywords": [
@@ -30,7 +30,10 @@
30
30
  "import": "./dist/lib-react.js"
31
31
  },
32
32
  "./processor": "./dist/processor.js",
33
- "./styles.css": "./dist/styles.css"
33
+ "./styles.css": {
34
+ "types": "./dist/styles.css.d.ts",
35
+ "default": "./dist/styles.css"
36
+ }
34
37
  },
35
38
  "main": "./dist/lib.js",
36
39
  "types": "./dist/lib.d.ts",
@@ -45,6 +48,7 @@
45
48
  "build": "bun build.ts",
46
49
  "build:lib": "bun build.ts --lib",
47
50
  "dev": "bun serve.ts",
51
+ "examples": "bun examples.ts",
48
52
  "lint": "biome check",
49
53
  "test": "bun test",
50
54
  "typecheck": "tsc --noEmit",
@@ -1,15 +0,0 @@
1
- {
2
- "lockfileVersion": 1,
3
- "configVersion": 0,
4
- "workspaces": {
5
- "": {
6
- "name": "esm-bundler-example",
7
- "dependencies": {
8
- "@jadujoel/web-audio-clip-node": "latest",
9
- },
10
- },
11
- },
12
- "packages": {
13
- "@jadujoel/web-audio-clip-node": ["@jadujoel/web-audio-clip-node@0.1.4", "", { "peerDependencies": { "react": ">=18", "react-dom": ">=18", "zustand": ">=4" }, "optionalPeers": ["react", "react-dom", "zustand"] }, "sha512-mQhckPRRz6fOUdqJbBatyWyhEo0zOKTaKHt5KltxF+F0o4iq7GcLhlR/iv/Qu/qn0rH+9eOlNxypDF6gG5su/w=="],
14
- }
15
- }
@@ -1,15 +0,0 @@
1
- {
2
- "lockfileVersion": 1,
3
- "configVersion": 1,
4
- "workspaces": {
5
- "": {
6
- "name": "self-hosted-example",
7
- "dependencies": {
8
- "@jadujoel/web-audio-clip-node": "^0.1.1",
9
- },
10
- },
11
- },
12
- "packages": {
13
- "@jadujoel/web-audio-clip-node": ["@jadujoel/web-audio-clip-node@0.1.4", "", { "peerDependencies": { "react": ">=18", "react-dom": ">=18", "zustand": ">=4" }, "optionalPeers": ["react", "react-dom", "zustand"] }, "sha512-mQhckPRRz6fOUdqJbBatyWyhEo0zOKTaKHt5KltxF+F0o4iq7GcLhlR/iv/Qu/qn0rH+9eOlNxypDF6gG5su/w=="],
14
- }
15
- }