@lucaismyname/ginger 0.0.25 → 0.0.28

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 (91) hide show
  1. package/README.md +34 -68
  2. package/dist/GingerSplitContexts-BzBExb95.js.map +1 -1
  3. package/dist/GingerSplitContexts-C7puo0M7.cjs.map +1 -1
  4. package/dist/analyzer/liveAudioGraph.d.ts.map +1 -1
  5. package/dist/analyzer/liveAudioGraph.test.d.ts +2 -0
  6. package/dist/analyzer/liveAudioGraph.test.d.ts.map +1 -0
  7. package/dist/analyzer/useGingerLiveAnalyzer.d.ts.map +1 -1
  8. package/dist/analyzer/useGingerLiveAnalyzer.test.d.ts +2 -0
  9. package/dist/analyzer/useGingerLiveAnalyzer.test.d.ts.map +1 -0
  10. package/dist/audio/GingerPlayer.d.ts.map +1 -1
  11. package/dist/client.cjs +1 -1
  12. package/dist/client.js +2 -2
  13. package/dist/components/controls/Controls.d.ts.map +1 -1
  14. package/dist/components/current/Artwork.d.ts.map +1 -1
  15. package/dist/components/current/Chapters.d.ts +1 -1
  16. package/dist/components/current/Chapters.d.ts.map +1 -1
  17. package/dist/components/current/FileUrl.d.ts +1 -1
  18. package/dist/components/current/FileUrl.d.ts.map +1 -1
  19. package/dist/components/current/Lyrics.d.ts +3 -1
  20. package/dist/components/current/Lyrics.d.ts.map +1 -1
  21. package/dist/components/current/LyricsSynced.d.ts +1 -1
  22. package/dist/components/current/LyricsSynced.d.ts.map +1 -1
  23. package/dist/components/current/Playback.d.ts +2 -2
  24. package/dist/components/current/Playback.d.ts.map +1 -1
  25. package/dist/components/current/QueueMeta.d.ts +2 -2
  26. package/dist/components/current/QueueMeta.d.ts.map +1 -1
  27. package/dist/components/current/Time.d.ts +2 -2
  28. package/dist/components/current/Time.d.ts.map +1 -1
  29. package/dist/components/current/Year.d.ts +1 -1
  30. package/dist/components/current/Year.d.ts.map +1 -1
  31. package/dist/components/current/createTextDisplay.d.ts.map +1 -1
  32. package/dist/components/current/texts.d.ts.map +1 -1
  33. package/dist/components/icons/Pause.d.ts +2 -0
  34. package/dist/components/icons/Pause.d.ts.map +1 -0
  35. package/dist/components/icons/Play.d.ts +2 -0
  36. package/dist/components/icons/Play.d.ts.map +1 -0
  37. package/dist/components/icons/Wrapper.d.ts +14 -0
  38. package/dist/components/icons/Wrapper.d.ts.map +1 -0
  39. package/dist/components/playlist/GingerPlaylist.d.ts.map +1 -1
  40. package/dist/components/queue/QueueDisplay.d.ts +1 -1
  41. package/dist/components/queue/QueueDisplay.d.ts.map +1 -1
  42. package/dist/context/GingerContext.d.ts.map +1 -1
  43. package/dist/context/GingerLocaleContext.d.ts.map +1 -1
  44. package/dist/context/GingerProvider.d.ts +1 -1
  45. package/dist/context/GingerProvider.d.ts.map +1 -1
  46. package/dist/context/GingerSplitContexts.d.ts.map +1 -1
  47. package/dist/core/playbackReducer.d.ts.map +1 -1
  48. package/dist/core/queue.d.ts.map +1 -1
  49. package/dist/core/transitions.d.ts.map +1 -1
  50. package/dist/ginger-CVwaVLpC.cjs +2 -0
  51. package/dist/ginger-CVwaVLpC.cjs.map +1 -0
  52. package/dist/ginger-G5-3BYSb.js +2165 -0
  53. package/dist/ginger-G5-3BYSb.js.map +1 -0
  54. package/dist/ginger.d.ts +1 -1
  55. package/dist/ginger.d.ts.map +1 -1
  56. package/dist/hooks/useControlBindings.d.ts.map +1 -1
  57. package/dist/hooks/useGinger.d.ts.map +1 -1
  58. package/dist/hooks/useGingerKeyboardShortcuts.d.ts.map +1 -1
  59. package/dist/hooks/useGingerLyricsSync.d.ts.map +1 -1
  60. package/dist/hooks/useSeekDrag.d.ts.map +1 -1
  61. package/dist/index.cjs +1 -1
  62. package/dist/index.js +2 -2
  63. package/dist/internal/selectors.d.ts.map +1 -1
  64. package/dist/testing/helpers.d.ts +1 -1
  65. package/dist/testing/helpers.d.ts.map +1 -1
  66. package/dist/testing/index.cjs +1 -1
  67. package/dist/testing/index.cjs.map +1 -1
  68. package/dist/testing/index.js +1 -1
  69. package/dist/testing/index.js.map +1 -1
  70. package/dist/testing/mockWebAudio.d.ts +47 -0
  71. package/dist/testing/mockWebAudio.d.ts.map +1 -0
  72. package/dist/types.d.ts +9 -0
  73. package/dist/types.d.ts.map +1 -1
  74. package/dist/{useNextTrackPrefetch-iqM3_D0L.cjs → useNextTrackPrefetch-CtZp7EgH.cjs} +2 -2
  75. package/dist/useNextTrackPrefetch-CtZp7EgH.cjs.map +1 -0
  76. package/dist/{useNextTrackPrefetch-CmfCP_Vz.js → useNextTrackPrefetch-Mj8dQLYR.js} +53 -45
  77. package/dist/useNextTrackPrefetch-Mj8dQLYR.js.map +1 -0
  78. package/dist/waveform/analyzeAudioFile.d.ts.map +1 -1
  79. package/dist/waveform/index.cjs +1 -1
  80. package/dist/waveform/index.cjs.map +1 -1
  81. package/dist/waveform/index.js +91 -84
  82. package/dist/waveform/index.js.map +1 -1
  83. package/dist/waveform/useAudioFileAnalysis.d.ts.map +1 -1
  84. package/dist/waveform/useAudioPeaks.d.ts.map +1 -1
  85. package/package.json +5 -5
  86. package/dist/ginger-Dj-zM_lq.js +0 -1826
  87. package/dist/ginger-Dj-zM_lq.js.map +0 -1
  88. package/dist/ginger-R_CXoaE2.cjs +0 -2
  89. package/dist/ginger-R_CXoaE2.cjs.map +0 -1
  90. package/dist/useNextTrackPrefetch-CmfCP_Vz.js.map +0 -1
  91. package/dist/useNextTrackPrefetch-iqM3_D0L.cjs.map +0 -1
@@ -0,0 +1,47 @@
1
+ type MockAudioContextState = AudioContextState;
2
+ declare class MockAudioNode {
3
+ readonly connections: MockAudioNode[];
4
+ readonly connectCalls: MockAudioNode[];
5
+ disconnectCalls: number;
6
+ connect(node: MockAudioNode): MockAudioNode;
7
+ disconnect(): void;
8
+ }
9
+ export declare class MockAudioDestinationNode extends MockAudioNode {
10
+ }
11
+ export declare class MockMediaElementAudioSourceNode extends MockAudioNode {
12
+ readonly mediaElement: HTMLAudioElement;
13
+ constructor(mediaElement: HTMLAudioElement);
14
+ }
15
+ export declare class MockAnalyserNode extends MockAudioNode {
16
+ fftSize: number;
17
+ smoothingTimeConstant: number;
18
+ minDecibels: number;
19
+ maxDecibels: number;
20
+ get frequencyBinCount(): number;
21
+ getByteFrequencyData(array: Uint8Array): void;
22
+ getByteTimeDomainData(array: Uint8Array): void;
23
+ }
24
+ export declare class MockAudioContext extends EventTarget {
25
+ readonly destination: MockAudioDestinationNode;
26
+ readonly sources: MockMediaElementAudioSourceNode[];
27
+ readonly analysers: MockAnalyserNode[];
28
+ sampleRate: number;
29
+ state: MockAudioContextState;
30
+ closeCalls: number;
31
+ resumeCalls: number;
32
+ createMediaElementSource(element: HTMLAudioElement): MediaElementAudioSourceNode;
33
+ createAnalyser(): AnalyserNode;
34
+ resume(): Promise<void>;
35
+ close(): Promise<void>;
36
+ setStateForTest(nextState: MockAudioContextState): void;
37
+ }
38
+ export type MockWebAudioInstall = {
39
+ contexts: MockAudioContext[];
40
+ flushAnimationFrame: (time?: number) => void;
41
+ flushAnimationFrames: (count: number) => void;
42
+ pendingAnimationFrameCount: () => number;
43
+ restore: () => void;
44
+ };
45
+ export declare function installMockWebAudio(): MockWebAudioInstall;
46
+ export {};
47
+ //# sourceMappingURL=mockWebAudio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mockWebAudio.d.ts","sourceRoot":"","sources":["../../src/testing/mockWebAudio.ts"],"names":[],"mappings":"AAAA,KAAK,qBAAqB,GAAG,iBAAiB,CAAC;AAE/C,cAAM,aAAa;IACjB,QAAQ,CAAC,WAAW,EAAE,aAAa,EAAE,CAAM;IAC3C,QAAQ,CAAC,YAAY,EAAE,aAAa,EAAE,CAAM;IAC5C,eAAe,SAAK;IAEpB,OAAO,CAAC,IAAI,EAAE,aAAa;IAM3B,UAAU;CAIX;AAED,qBAAa,wBAAyB,SAAQ,aAAa;CAAG;AAE9D,qBAAa,+BAAgC,SAAQ,aAAa;IACpD,QAAQ,CAAC,YAAY,EAAE,gBAAgB;gBAA9B,YAAY,EAAE,gBAAgB;CAGpD;AAED,qBAAa,gBAAiB,SAAQ,aAAa;IACjD,OAAO,SAAQ;IACf,qBAAqB,SAAO;IAC5B,WAAW,SAAQ;IACnB,WAAW,SAAO;IAElB,IAAI,iBAAiB,WAEpB;IAED,oBAAoB,CAAC,KAAK,EAAE,UAAU;IAMtC,qBAAqB,CAAC,KAAK,EAAE,UAAU;CAKxC;AAED,qBAAa,gBAAiB,SAAQ,WAAW;IAC/C,QAAQ,CAAC,WAAW,2BAAkC;IACtD,QAAQ,CAAC,OAAO,EAAE,+BAA+B,EAAE,CAAM;IACzD,QAAQ,CAAC,SAAS,EAAE,gBAAgB,EAAE,CAAM;IAE5C,UAAU,SAAU;IACpB,KAAK,EAAE,qBAAqB,CAAa;IACzC,UAAU,SAAK;IACf,WAAW,SAAK;IAEhB,wBAAwB,CAAC,OAAO,EAAE,gBAAgB,GAGpB,2BAA2B;IAGzD,cAAc,IAGkB,YAAY;IAGtC,MAAM;IAON,KAAK;IAKX,eAAe,CAAC,SAAS,EAAE,qBAAqB;CAKjD;AAED,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,mBAAmB,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,oBAAoB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,0BAA0B,EAAE,MAAM,MAAM,CAAC;IACzC,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,wBAAgB,mBAAmB,IAAI,mBAAmB,CAgFzD"}
package/dist/types.d.ts CHANGED
@@ -6,6 +6,10 @@ export type GingerLocaleMessages = {
6
6
  seek: string;
7
7
  volume: string;
8
8
  playbackSpeed: string;
9
+ /** Accessible name for the chapter list (`Ginger.Current.Chapters`). */
10
+ chaptersList: string;
11
+ /** Accessible name for the synced lyrics list (`Ginger.Current.LyricsSynced`). */
12
+ syncedLyricsList: string;
9
13
  nextTrack: string;
10
14
  previousTrack: string;
11
15
  shuffle: string;
@@ -236,6 +240,11 @@ export type GingerProviderProps = {
236
240
  resumeOnTrackChange?: boolean;
237
241
  /** Disable default CSS variable/theme styles on provider root. */
238
242
  unstyled?: boolean;
243
+ /**
244
+ * Merge provider props (`className`, `style`, `data-ginger-playback`, `dir`) onto the single child
245
+ * element instead of wrapping in an extra `div`. Use for layout systems that forbid wrapper nodes.
246
+ */
247
+ asChild?: boolean;
239
248
  className?: string;
240
249
  style?: CSSProperties;
241
250
  onTrackChange?: (track: Track | null, index: number) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use strict";const o=require("react"),v=require("./GingerSplitContexts-C7puo0M7.cjs"),P=require("./ginger-R_CXoaE2.cjs");function K(){const t=v.useGingerPlayback(),e=v.useGingerMedia();return o.useMemo(()=>{const n=v.gingerStateFromContextValues(t,e);return{state:n,currentTrack:P.getCurrentTrack(n),playbackUi:P.derivePlaybackUiState(n),duration:P.effectiveDuration(n),remaining:P.effectiveRemaining(n),progress:P.progressFraction(n),artworkUrl:P.resolvedArtwork(n),albumLine:P.resolvedAlbumLine(n),play:t.play,pause:t.pause,togglePlayPause:t.togglePlayPause,seek:e.seek,setVolume:e.setVolume,setMuted:e.setMuted,toggleMute:e.toggleMute,setPlaybackRate:e.setPlaybackRate,next:t.next,prev:t.prev,setRepeatMode:t.setRepeatMode,cycleRepeat:t.cycleRepeat,toggleShuffle:t.toggleShuffle,setQueue:t.setQueue,insertTrackAt:t.insertTrackAt,removeTrackAt:t.removeTrackAt,moveTrack:t.moveTrack,enqueueNext:t.enqueueNext,playTrackAt:t.playTrackAt,selectTrackAt:t.selectTrackAt,setPlaylistMeta:t.setPlaylistMeta,setPlaybackMode:t.setPlaybackMode,init:t.init,audioRef:e.audioRef,dispatch:t.dispatch}},[t,e])}const G=new WeakMap;function O(t){const e=2**Math.round(Math.log2(t));return Math.min(32768,Math.max(32,e))}function V(t,e){let n=G.get(t);if(!n){const d=window.AudioContext??window.webkitAudioContext;if(!d)throw new Error("Web Audio API is not available");const i=new d,m=i.createMediaElementSource(t);n={context:i,source:m,consumers:new Map,nextId:0},G.set(t,n)}const{context:s,source:c}=n,r=s.createAnalyser();r.fftSize=O(e.fftSize),r.smoothingTimeConstant=e.smoothingTimeConstant,r.minDecibels=e.minDecibels,r.maxDecibels=e.maxDecibels,c.connect(r);const a=n.consumers.size===0;a&&r.connect(s.destination);const l=n.nextId;return n.nextId+=1,n.consumers.set(l,{analyser:r,isPlaybackSink:a}),{id:l,context:s,analyser:r}}function U(t,e){const n=G.get(t);if(!n)return;const s=n.consumers.get(e);if(!s)return;const{analyser:c,isPlaybackSink:r}=s;if(c.disconnect(),n.consumers.delete(e),n.consumers.size===0){try{n.source.disconnect()}catch{}n.context.close(),G.delete(t);return}if(r){const a=n.consumers.values().next().value;a&&(a.analyser.connect(n.context.destination),a.isPlaybackSink=!0)}}const q=new Uint8Array(0),I=new Uint8Array(0);function Q(t={}){const{enabled:e=!0,fftSize:n=2048,smoothingTimeConstant:s=.8,minDecibels:c=-100,maxDecibels:r=-30}=t,{audioRef:a,state:l}=K(),d=o.useMemo(()=>({fftSize:n,smoothingTimeConstant:s,minDecibels:c,maxDecibels:r}),[n,s,c,r]),[i,m]=o.useState(0),[p,u]=o.useState(null),[R,k]=o.useState(!1),[S,h]=o.useState({frequencyBinCount:0,sampleRate:0}),g=o.useRef(q),x=o.useRef(I),X=o.useCallback(async()=>{const A=M.current;A&&A.state==="suspended"&&await A.resume()},[]),M=o.useRef(null),L=o.useRef(null);return o.useLayoutEffect(()=>{if(!e||typeof window>"u")return;let A=!1,C=null,E=null,D=0;const F=()=>{const f=M.current;f&&k(f.state==="suspended")},z=()=>{if(A)return;const f=L.current,w=g.current,y=x.current;f&&w.length>0&&y.length>0&&(f.getByteFrequencyData(w),f.getByteTimeDomainData(y),m(T=>T+1)),D=requestAnimationFrame(z)},B=()=>{const f=a.current;if(!f||A)return"no-element";try{const{id:w,context:y,analyser:T}=V(f,d);C=w,E=f,M.current=y,L.current=T,k(y.state==="suspended"),u(null),y.addEventListener("statechange",F);const b=T.frequencyBinCount,H=T.fftSize;return g.current=new Uint8Array(b),x.current=new Uint8Array(H),h({frequencyBinCount:b,sampleRate:y.sampleRate}),D=requestAnimationFrame(z),"ok"}catch(w){const y=w instanceof Error?w.message:"Failed to attach live analyser";return u(y),M.current=null,L.current=null,g.current=q,x.current=I,h({frequencyBinCount:0,sampleRate:0}),"error"}},N=B();if(N!=="ok"){let f=0;const w=120;let y=0;const T=()=>{if(A)return;const b=B();b==="ok"||b==="error"||(y+=1,!(y>=w)&&(f=requestAnimationFrame(T)))};return N==="no-element"&&(f=requestAnimationFrame(T)),()=>{var b;A=!0,cancelAnimationFrame(f),cancelAnimationFrame(D),C!=null&&E&&U(E,C),(b=M.current)==null||b.removeEventListener("statechange",F),M.current=null,L.current=null,g.current=q,x.current=I}}return()=>{var f;A=!0,cancelAnimationFrame(D),C!=null&&E&&U(E,C),(f=M.current)==null||f.removeEventListener("statechange",F),M.current=null,L.current=null,g.current=q,x.current=I,h({frequencyBinCount:0,sampleRate:0})}},[e,a,d,l.currentIndex]),{frequencyData:g.current,timeDomainData:x.current,frequencyBinCount:S.frequencyBinCount,sampleRate:S.sampleRate,isSuspended:R,error:p,resume:X}}function W(t=!0,e={}){const{togglePlayPause:n,next:s,prev:c}=v.useGingerPlayback(),{toggleMute:r}=v.useGingerMedia(),a=e.mute;o.useEffect(()=>{if(!t||typeof window>"u")return;const l=(e.playPause??" ").toLowerCase(),d=(e.next??"ArrowRight").toLowerCase(),i=(e.previous??"ArrowLeft").toLowerCase(),m=a==null?void 0:a.toLowerCase(),p=u=>{const R=u.target;if(R&&(["INPUT","TEXTAREA","SELECT"].includes(R.tagName)||R.isContentEditable))return;const k=u.key.toLowerCase();k===l?(u.preventDefault(),n()):k===d?(u.preventDefault(),s()):k===i?(u.preventDefault(),c()):m&&k===m&&(u.preventDefault(),r())};return window.addEventListener("keydown",p),()=>window.removeEventListener("keydown",p)},[e.next,e.playPause,e.previous,t,a,s,c,r,n])}function j(t){const{durationMs:e,stopAfterTracks:n,respectPause:s=!0,enabled:c=!0,onFire:r}=t,{currentIndex:a,pause:l,isPaused:d}=v.useGingerPlayback(),i=o.useRef(n??0),m=o.useRef(a);o.useEffect(()=>{i.current=n??0},[n]),o.useEffect(()=>{if(!c||!e||e<=0||s&&d)return;const p=setTimeout(()=>{l(),r==null||r()},e);return()=>clearTimeout(p)},[e,c,d,r,l,s]),o.useEffect(()=>{if(!c||!n||n<=0)return;const p=m.current;m.current=a,a!==p&&(i.current-=1,i.current<=0&&(l(),r==null||r()))},[a,c,r,l,n])}function J(t=!1){const e=v.useGingerState(),n=o.useRef(e);o.useEffect(()=>{if(!t||typeof console>"u")return;const s=n.current;s!==e&&console.debug("[ginger]",{from:{currentIndex:s.currentIndex,isPaused:s.isPaused,currentTime:s.currentTime,repeatMode:s.repeatMode},to:{currentIndex:e.currentIndex,isPaused:e.isPaused,currentTime:e.currentTime,repeatMode:e.repeatMode}}),n.current=e},[t,e])}function Y(t){return Math.max(0,Math.min(1,t))}function Z(t){const e=v.useGingerMedia(),n=v.useGingerPlayback(),{seek:s}=e,[c,r]=o.useState(0),[a,l]=o.useState(!1),d=P.progressFraction(v.gingerStateFromContextValues(n,e)),i=a?c:d,m=o.useCallback(p=>{if(!(t>0))return;const u=p.currentTarget,R=u.getBoundingClientRect(),k=g=>{const x=Y((g-R.left)/R.width);r(x),s(x*t)};l(!0),u.setPointerCapture(p.pointerId),k(p.clientX);const S=g=>k(g.clientX),h=g=>{k(g.clientX),l(!1),u.releasePointerCapture(p.pointerId),u.removeEventListener("pointermove",S),u.removeEventListener("pointerup",h),u.removeEventListener("pointercancel",h)};u.addEventListener("pointermove",S),u.addEventListener("pointerup",h),u.addEventListener("pointercancel",h)},[t,s]);return{fraction:c,displayFraction:i,isDragging:a,onPointerDown:m}}function _(t={}){const{enabled:e=!0,crossOrigin:n}=t,{tracks:s,currentIndex:c,repeatMode:r,playbackMode:a}=v.useGingerPlayback();o.useEffect(()=>{var m;if(!e||typeof document>"u")return;const l=P.computeNextIndex({tracks:s,currentIndex:c,repeatMode:r,playbackMode:a});if(l===c)return;const d=((m=s[l])==null?void 0:m.fileUrl)??"";if(!d)return;const i=document.createElement("audio");return i.preload="auto",n&&(i.crossOrigin=n),i.src=d,i.load(),()=>{i.removeAttribute("src"),i.load()}},[e,n,s,c,r,a])}exports.attachLiveAnalyser=V;exports.detachLiveAnalyser=U;exports.useGinger=K;exports.useGingerDebugLog=J;exports.useGingerKeyboardShortcuts=W;exports.useGingerLiveAnalyzer=Q;exports.useGingerSleepTimer=j;exports.useNextTrackPrefetch=_;exports.useSeekDrag=Z;
2
- //# sourceMappingURL=useNextTrackPrefetch-iqM3_D0L.cjs.map
1
+ "use strict";const o=require("react"),v=require("./GingerSplitContexts-C7puo0M7.cjs"),P=require("./ginger-CVwaVLpC.cjs");function K(){const t=v.useGingerPlayback(),e=v.useGingerMedia();return o.useMemo(()=>{const n=v.gingerStateFromContextValues(t,e);return{state:n,currentTrack:P.getCurrentTrack(n),playbackUi:P.derivePlaybackUiState(n),duration:P.effectiveDuration(n),remaining:P.effectiveRemaining(n),progress:P.progressFraction(n),artworkUrl:P.resolvedArtwork(n),albumLine:P.resolvedAlbumLine(n),play:t.play,pause:t.pause,togglePlayPause:t.togglePlayPause,seek:e.seek,setVolume:e.setVolume,setMuted:e.setMuted,toggleMute:e.toggleMute,setPlaybackRate:e.setPlaybackRate,next:t.next,prev:t.prev,setRepeatMode:t.setRepeatMode,cycleRepeat:t.cycleRepeat,toggleShuffle:t.toggleShuffle,setQueue:t.setQueue,insertTrackAt:t.insertTrackAt,removeTrackAt:t.removeTrackAt,moveTrack:t.moveTrack,enqueueNext:t.enqueueNext,playTrackAt:t.playTrackAt,selectTrackAt:t.selectTrackAt,setPlaylistMeta:t.setPlaylistMeta,setPlaybackMode:t.setPlaybackMode,init:t.init,audioRef:e.audioRef,dispatch:t.dispatch}},[t,e])}const G=new WeakMap;function O(t){const e=2**Math.round(Math.log2(t));return Math.min(32768,Math.max(32,e))}function V(t,e){let n=G.get(t);if(!n){const d=window.AudioContext??window.webkitAudioContext;if(!d)throw new Error("Web Audio API is not available");const i=new d,m=i.createMediaElementSource(t);n={context:i,source:m,consumers:new Map,nextId:0},G.set(t,n)}const{context:s,source:c}=n,r=s.createAnalyser();r.fftSize=O(e.fftSize),r.smoothingTimeConstant=e.smoothingTimeConstant,r.minDecibels=e.minDecibels,r.maxDecibels=e.maxDecibels,c.connect(r);const a=n.consumers.size===0;a&&r.connect(s.destination);const l=n.nextId;return n.nextId+=1,n.consumers.set(l,{analyser:r,isPlaybackSink:a}),{id:l,context:s,analyser:r}}function U(t,e){const n=G.get(t);if(!n)return;const s=n.consumers.get(e);if(!s)return;const{analyser:c,isPlaybackSink:r}=s;if(c.disconnect(),n.consumers.delete(e),n.consumers.size===0){try{n.source.disconnect()}catch{}n.context.close(),G.delete(t);return}if(r){const a=n.consumers.values().next().value;a&&(a.analyser.connect(n.context.destination),a.isPlaybackSink=!0)}}const q=new Uint8Array(0),I=new Uint8Array(0);function Q(t={}){const{enabled:e=!0,fftSize:n=2048,smoothingTimeConstant:s=.8,minDecibels:c=-100,maxDecibels:r=-30}=t,{audioRef:a,state:l}=K(),d=o.useMemo(()=>({fftSize:n,smoothingTimeConstant:s,minDecibels:c,maxDecibels:r}),[n,s,c,r]),[i,m]=o.useState(0),[p,u]=o.useState(null),[R,k]=o.useState(!1),[S,h]=o.useState({frequencyBinCount:0,sampleRate:0}),g=o.useRef(q),x=o.useRef(I),X=o.useCallback(async()=>{const A=M.current;A&&A.state==="suspended"&&await A.resume()},[]),M=o.useRef(null),L=o.useRef(null);return o.useLayoutEffect(()=>{if(!e||typeof window>"u")return;let A=!1,C=null,E=null,D=0;const F=()=>{const f=M.current;f&&k(f.state==="suspended")},z=()=>{if(A)return;const f=L.current,w=g.current,y=x.current;f&&w.length>0&&y.length>0&&(f.getByteFrequencyData(w),f.getByteTimeDomainData(y),m(T=>T+1)),D=requestAnimationFrame(z)},B=()=>{const f=a.current;if(!f||A)return"no-element";try{const{id:w,context:y,analyser:T}=V(f,d);C=w,E=f,M.current=y,L.current=T,k(y.state==="suspended"),u(null),y.addEventListener("statechange",F);const b=T.frequencyBinCount,H=T.fftSize;return g.current=new Uint8Array(b),x.current=new Uint8Array(H),h({frequencyBinCount:b,sampleRate:y.sampleRate}),D=requestAnimationFrame(z),"ok"}catch(w){const y=w instanceof Error?w.message:"Failed to attach live analyser";return u(y),M.current=null,L.current=null,g.current=q,x.current=I,h({frequencyBinCount:0,sampleRate:0}),"error"}},N=B();if(N!=="ok"){let f=0;const w=120;let y=0;const T=()=>{if(A)return;const b=B();b==="ok"||b==="error"||(y+=1,!(y>=w)&&(f=requestAnimationFrame(T)))};return N==="no-element"&&(f=requestAnimationFrame(T)),()=>{var b;A=!0,cancelAnimationFrame(f),cancelAnimationFrame(D),C!=null&&E&&U(E,C),(b=M.current)==null||b.removeEventListener("statechange",F),M.current=null,L.current=null,g.current=q,x.current=I}}return()=>{var f;A=!0,cancelAnimationFrame(D),C!=null&&E&&U(E,C),(f=M.current)==null||f.removeEventListener("statechange",F),M.current=null,L.current=null,g.current=q,x.current=I,h({frequencyBinCount:0,sampleRate:0})}},[e,a,d,l.currentIndex]),{frequencyData:g.current,timeDomainData:x.current,frequencyBinCount:S.frequencyBinCount,sampleRate:S.sampleRate,isSuspended:R,error:p,resume:X}}function W(t=!0,e={}){const{togglePlayPause:n,next:s,prev:c}=v.useGingerPlayback(),{toggleMute:r}=v.useGingerMedia(),a=e.mute;o.useEffect(()=>{if(!t||typeof window>"u")return;const l=(e.playPause??" ").toLowerCase(),d=(e.next??"ArrowRight").toLowerCase(),i=(e.previous??"ArrowLeft").toLowerCase(),m=a==null?void 0:a.toLowerCase(),p=u=>{const R=u.target;if(R&&(["INPUT","TEXTAREA","SELECT"].includes(R.tagName)||R.isContentEditable))return;const k=u.key.toLowerCase();k===l?(u.preventDefault(),n()):k===d?(u.preventDefault(),s()):k===i?(u.preventDefault(),c()):m&&k===m&&(u.preventDefault(),r())};return window.addEventListener("keydown",p),()=>window.removeEventListener("keydown",p)},[e.next,e.playPause,e.previous,t,a,s,c,r,n])}function j(t){const{durationMs:e,stopAfterTracks:n,respectPause:s=!0,enabled:c=!0,onFire:r}=t,{currentIndex:a,pause:l,isPaused:d}=v.useGingerPlayback(),i=o.useRef(n??0),m=o.useRef(a);o.useEffect(()=>{i.current=n??0},[n]),o.useEffect(()=>{if(!c||!e||e<=0||s&&d)return;const p=setTimeout(()=>{l(),r==null||r()},e);return()=>clearTimeout(p)},[e,c,d,r,l,s]),o.useEffect(()=>{if(!c||!n||n<=0)return;const p=m.current;m.current=a,a!==p&&(i.current-=1,i.current<=0&&(l(),r==null||r()))},[a,c,r,l,n])}function J(t=!1){const e=v.useGingerState(),n=o.useRef(e);o.useEffect(()=>{if(!t||typeof console>"u")return;const s=n.current;s!==e&&console.debug("[ginger]",{from:{currentIndex:s.currentIndex,isPaused:s.isPaused,currentTime:s.currentTime,repeatMode:s.repeatMode},to:{currentIndex:e.currentIndex,isPaused:e.isPaused,currentTime:e.currentTime,repeatMode:e.repeatMode}}),n.current=e},[t,e])}function Y(t){return Math.max(0,Math.min(1,t))}function Z(t){const e=v.useGingerMedia(),n=v.useGingerPlayback(),{seek:s}=e,[c,r]=o.useState(0),[a,l]=o.useState(!1),d=P.progressFraction(v.gingerStateFromContextValues(n,e)),i=a?c:d,m=o.useCallback(p=>{if(!(t>0))return;const u=p.currentTarget,R=u.getBoundingClientRect(),k=g=>{const x=Y((g-R.left)/R.width);r(x),s(x*t)};l(!0),u.setPointerCapture(p.pointerId),k(p.clientX);const S=g=>k(g.clientX),h=g=>{k(g.clientX),l(!1),u.releasePointerCapture(p.pointerId),u.removeEventListener("pointermove",S),u.removeEventListener("pointerup",h),u.removeEventListener("pointercancel",h)};u.addEventListener("pointermove",S),u.addEventListener("pointerup",h),u.addEventListener("pointercancel",h)},[t,s]);return{fraction:c,displayFraction:i,isDragging:a,onPointerDown:m}}function _(t={}){const{enabled:e=!0,crossOrigin:n}=t,{tracks:s,currentIndex:c,repeatMode:r,playbackMode:a}=v.useGingerPlayback();o.useEffect(()=>{var m;if(!e||typeof document>"u")return;const l=P.computeNextIndex({tracks:s,currentIndex:c,repeatMode:r,playbackMode:a});if(l===c)return;const d=((m=s[l])==null?void 0:m.fileUrl)??"";if(!d)return;const i=document.createElement("audio");return i.preload="auto",n&&(i.crossOrigin=n),i.src=d,i.load(),()=>{i.removeAttribute("src"),i.load()}},[e,n,s,c,r,a])}exports.attachLiveAnalyser=V;exports.detachLiveAnalyser=U;exports.useGinger=K;exports.useGingerDebugLog=J;exports.useGingerKeyboardShortcuts=W;exports.useGingerLiveAnalyzer=Q;exports.useGingerSleepTimer=j;exports.useNextTrackPrefetch=_;exports.useSeekDrag=Z;
2
+ //# sourceMappingURL=useNextTrackPrefetch-CtZp7EgH.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useNextTrackPrefetch-CtZp7EgH.cjs","sources":["../src/hooks/useGinger.ts","../src/analyzer/liveAudioGraph.ts","../src/analyzer/useGingerLiveAnalyzer.ts","../src/hooks/useGingerKeyboardShortcuts.ts","../src/hooks/useGingerSleepTimer.ts","../src/hooks/useGingerDebugLog.ts","../src/hooks/useSeekDrag.ts","../src/hooks/useNextTrackPrefetch.ts"],"sourcesContent":["import { useMemo } from \"react\";\nimport {\n gingerStateFromContextValues,\n useGingerMedia,\n useGingerPlayback,\n} from \"../context/GingerSplitContexts\";\nimport {\n derivePlaybackUiState,\n effectiveDuration,\n effectiveRemaining,\n getCurrentTrack,\n progressFraction,\n resolvedAlbumLine,\n resolvedArtwork,\n} from \"../internal/selectors\";\n\nexport function useGinger() {\n const pb = useGingerPlayback();\n const md = useGingerMedia();\n\n return useMemo(() => {\n const state = gingerStateFromContextValues(pb, md);\n return {\n state,\n currentTrack: getCurrentTrack(state),\n playbackUi: derivePlaybackUiState(state),\n duration: effectiveDuration(state),\n remaining: effectiveRemaining(state),\n progress: progressFraction(state),\n artworkUrl: resolvedArtwork(state),\n albumLine: resolvedAlbumLine(state),\n play: pb.play,\n pause: pb.pause,\n togglePlayPause: pb.togglePlayPause,\n seek: md.seek,\n setVolume: md.setVolume,\n setMuted: md.setMuted,\n toggleMute: md.toggleMute,\n setPlaybackRate: md.setPlaybackRate,\n next: pb.next,\n prev: pb.prev,\n setRepeatMode: pb.setRepeatMode,\n cycleRepeat: pb.cycleRepeat,\n toggleShuffle: pb.toggleShuffle,\n setQueue: pb.setQueue,\n insertTrackAt: pb.insertTrackAt,\n removeTrackAt: pb.removeTrackAt,\n moveTrack: pb.moveTrack,\n enqueueNext: pb.enqueueNext,\n playTrackAt: pb.playTrackAt,\n selectTrackAt: pb.selectTrackAt,\n setPlaylistMeta: pb.setPlaylistMeta,\n setPlaybackMode: pb.setPlaybackMode,\n init: pb.init,\n audioRef: md.audioRef,\n dispatch: pb.dispatch,\n };\n }, [pb, md]);\n}\n","/** One MediaElementAudioSourceNode per HTMLAudioElement; multiple AnalyserNodes may tap the source. */\n\nexport type LiveAnalyserOptions = {\n fftSize: number;\n smoothingTimeConstant: number;\n minDecibels: number;\n maxDecibels: number;\n};\n\ntype Consumer = {\n analyser: AnalyserNode;\n /** This analyser is wired to `audioContext.destination` so the graph is audible. */\n isPlaybackSink: boolean;\n};\n\ntype ElementEntry = {\n context: AudioContext;\n source: MediaElementAudioSourceNode;\n consumers: Map<number, Consumer>;\n nextId: number;\n};\n\nconst entries = new WeakMap<HTMLAudioElement, ElementEntry>();\n\nfunction clampFftSize(n: number): number {\n const p = 2 ** Math.round(Math.log2(n));\n return Math.min(32768, Math.max(32, p));\n}\n\nexport function attachLiveAnalyser(\n element: HTMLAudioElement,\n options: LiveAnalyserOptions,\n): { id: number; context: AudioContext; analyser: AnalyserNode } {\n let entry = entries.get(element);\n if (!entry) {\n const Context =\n window.AudioContext ??\n (window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n if (!Context) {\n throw new Error(\"Web Audio API is not available\");\n }\n const context = new Context();\n const source = context.createMediaElementSource(element);\n entry = { context, source, consumers: new Map(), nextId: 0 };\n entries.set(element, entry);\n }\n\n const { context, source } = entry;\n const analyser = context.createAnalyser();\n analyser.fftSize = clampFftSize(options.fftSize);\n analyser.smoothingTimeConstant = options.smoothingTimeConstant;\n analyser.minDecibels = options.minDecibels;\n analyser.maxDecibels = options.maxDecibels;\n\n source.connect(analyser);\n\n const isFirst = entry.consumers.size === 0;\n if (isFirst) {\n analyser.connect(context.destination);\n }\n\n const id = entry.nextId;\n entry.nextId += 1;\n entry.consumers.set(id, { analyser, isPlaybackSink: isFirst });\n\n return { id, context, analyser };\n}\n\nexport function detachLiveAnalyser(element: HTMLAudioElement, id: number): void {\n const entry = entries.get(element);\n if (!entry) return;\n\n const consumer = entry.consumers.get(id);\n if (!consumer) return;\n\n const { analyser, isPlaybackSink } = consumer;\n analyser.disconnect();\n entry.consumers.delete(id);\n\n if (entry.consumers.size === 0) {\n try {\n entry.source.disconnect();\n } catch {\n // ignore\n }\n void entry.context.close();\n entries.delete(element);\n return;\n }\n\n if (isPlaybackSink) {\n const first = entry.consumers.values().next().value as Consumer | undefined;\n if (first) {\n first.analyser.connect(entry.context.destination);\n first.isPlaybackSink = true;\n }\n }\n}\n","import { useCallback, useLayoutEffect, useMemo, useRef, useState } from \"react\";\nimport { useGinger } from \"../hooks/useGinger\";\nimport { type LiveAnalyserOptions, attachLiveAnalyser, detachLiveAnalyser } from \"./liveAudioGraph\";\n\nexport type UseGingerLiveAnalyzerOptions = {\n /** When false, the analyser is detached and no frames are read. Default true. */\n enabled?: boolean;\n fftSize?: number;\n smoothingTimeConstant?: number;\n minDecibels?: number;\n maxDecibels?: number;\n};\n\nexport type UseGingerLiveAnalyzerResult = {\n /** Byte frequency data (0–255); length equals `frequencyBinCount`. Updated each animation frame while enabled. */\n frequencyData: Uint8Array;\n /** Byte time-domain data (0–255); length equals `fftSize`. */\n timeDomainData: Uint8Array;\n frequencyBinCount: number;\n sampleRate: number;\n isSuspended: boolean;\n error: string | null;\n resume: () => Promise<void>;\n};\n\nconst emptyFreq = new Uint8Array(0);\nconst emptyTime = new Uint8Array(0);\n\nexport function useGingerLiveAnalyzer(\n options: UseGingerLiveAnalyzerOptions = {},\n): UseGingerLiveAnalyzerResult {\n const {\n enabled = true,\n fftSize = 2048,\n smoothingTimeConstant = 0.8,\n minDecibels = -100,\n maxDecibels = -30,\n } = options;\n\n const { audioRef, state } = useGinger();\n const opts = useMemo<LiveAnalyserOptions>(\n () => ({\n fftSize,\n smoothingTimeConstant,\n minDecibels,\n maxDecibels,\n }),\n [fftSize, smoothingTimeConstant, minDecibels, maxDecibels],\n );\n\n const [frame, setFrame] = useState(0);\n const [error, setError] = useState<string | null>(null);\n const [isSuspended, setIsSuspended] = useState(false);\n const [meta, setMeta] = useState({ frequencyBinCount: 0, sampleRate: 0 });\n\n const freqRef = useRef<Uint8Array>(emptyFreq);\n const timeRef = useRef<Uint8Array>(emptyTime);\n\n const resume = useCallback(async () => {\n const ctx = contextHolderRef.current;\n if (ctx && ctx.state === \"suspended\") {\n await ctx.resume();\n }\n }, []);\n\n const contextHolderRef = useRef<AudioContext | null>(null);\n const analyserHolderRef = useRef<AnalyserNode | null>(null);\n\n useLayoutEffect(() => {\n if (!enabled || typeof window === \"undefined\") {\n return;\n }\n\n let cancelled = false;\n let consumerId: number | null = null;\n let element: HTMLAudioElement | null = null;\n let rafId = 0;\n\n const onStateChange = () => {\n const ctx = contextHolderRef.current;\n if (ctx) setIsSuspended(ctx.state === \"suspended\");\n };\n\n const runLoop = () => {\n if (cancelled) return;\n const a = analyserHolderRef.current;\n const fq = freqRef.current;\n const td = timeRef.current;\n if (a && fq.length > 0 && td.length > 0) {\n a.getByteFrequencyData(fq as Uint8Array<ArrayBuffer>);\n a.getByteTimeDomainData(td as Uint8Array<ArrayBuffer>);\n setFrame((n) => n + 1);\n }\n rafId = requestAnimationFrame(runLoop);\n };\n\n type AttachOutcome = \"ok\" | \"no-element\" | \"error\";\n\n const attach = (): AttachOutcome => {\n const el = audioRef.current;\n if (!el || cancelled) return \"no-element\";\n try {\n const { id, context, analyser } = attachLiveAnalyser(el, opts);\n consumerId = id;\n element = el;\n contextHolderRef.current = context;\n analyserHolderRef.current = analyser;\n setIsSuspended(context.state === \"suspended\");\n setError(null);\n\n context.addEventListener(\"statechange\", onStateChange);\n\n const n = analyser.frequencyBinCount;\n const fft = analyser.fftSize;\n freqRef.current = new Uint8Array(n);\n timeRef.current = new Uint8Array(fft);\n setMeta({ frequencyBinCount: n, sampleRate: context.sampleRate });\n\n rafId = requestAnimationFrame(runLoop);\n return \"ok\";\n } catch (e) {\n const msg = e instanceof Error ? e.message : \"Failed to attach live analyser\";\n setError(msg);\n contextHolderRef.current = null;\n analyserHolderRef.current = null;\n freqRef.current = emptyFreq;\n timeRef.current = emptyTime;\n setMeta({ frequencyBinCount: 0, sampleRate: 0 });\n return \"error\";\n }\n };\n\n const first = attach();\n if (first !== \"ok\") {\n let retryRaf = 0;\n const maxAttempts = 120;\n let attempts = 0;\n\n const retryLoop = () => {\n if (cancelled) return;\n const out = attach();\n if (out === \"ok\" || out === \"error\") return;\n attempts += 1;\n if (attempts >= maxAttempts) return;\n retryRaf = requestAnimationFrame(retryLoop);\n };\n\n if (first === \"no-element\") {\n retryRaf = requestAnimationFrame(retryLoop);\n }\n\n return () => {\n cancelled = true;\n cancelAnimationFrame(retryRaf);\n cancelAnimationFrame(rafId);\n if (consumerId != null && element) {\n detachLiveAnalyser(element, consumerId);\n }\n contextHolderRef.current?.removeEventListener(\"statechange\", onStateChange);\n contextHolderRef.current = null;\n analyserHolderRef.current = null;\n freqRef.current = emptyFreq;\n timeRef.current = emptyTime;\n };\n }\n\n return () => {\n cancelled = true;\n cancelAnimationFrame(rafId);\n if (consumerId != null && element) {\n detachLiveAnalyser(element, consumerId);\n }\n contextHolderRef.current?.removeEventListener(\"statechange\", onStateChange);\n contextHolderRef.current = null;\n analyserHolderRef.current = null;\n freqRef.current = emptyFreq;\n timeRef.current = emptyTime;\n setMeta({ frequencyBinCount: 0, sampleRate: 0 });\n };\n }, [enabled, audioRef, opts, state.currentIndex]);\n\n void frame;\n\n return {\n frequencyData: freqRef.current,\n timeDomainData: timeRef.current,\n frequencyBinCount: meta.frequencyBinCount,\n sampleRate: meta.sampleRate,\n isSuspended,\n error,\n resume,\n };\n}\n","import { useEffect } from \"react\";\nimport { useGingerMedia, useGingerPlayback } from \"../context/GingerSplitContexts\";\n\nexport type GingerKeyboardShortcutBindings = {\n playPause?: string;\n next?: string;\n previous?: string;\n mute?: string;\n};\n\nexport function useGingerKeyboardShortcuts(\n enabled = true,\n bindings: GingerKeyboardShortcutBindings = {},\n): void {\n const { togglePlayPause, next, prev } = useGingerPlayback();\n const { toggleMute } = useGingerMedia();\n\n const muteBinding = bindings.mute;\n\n useEffect(() => {\n if (!enabled || typeof window === \"undefined\") return;\n const playPause = (bindings.playPause ?? \" \").toLowerCase();\n const nextKey = (bindings.next ?? \"ArrowRight\").toLowerCase();\n const prevKey = (bindings.previous ?? \"ArrowLeft\").toLowerCase();\n const muteKey = muteBinding?.toLowerCase();\n\n const onKeyDown = (event: KeyboardEvent) => {\n const target = event.target as HTMLElement | null;\n if (\n target &&\n ([\"INPUT\", \"TEXTAREA\", \"SELECT\"].includes(target.tagName) || target.isContentEditable)\n )\n return;\n const key = event.key.toLowerCase();\n if (key === playPause) {\n event.preventDefault();\n togglePlayPause();\n } else if (key === nextKey) {\n event.preventDefault();\n next();\n } else if (key === prevKey) {\n event.preventDefault();\n prev();\n } else if (muteKey && key === muteKey) {\n event.preventDefault();\n toggleMute();\n }\n };\n window.addEventListener(\"keydown\", onKeyDown);\n return () => window.removeEventListener(\"keydown\", onKeyDown);\n }, [\n bindings.next,\n bindings.playPause,\n bindings.previous,\n enabled,\n muteBinding,\n next,\n prev,\n toggleMute,\n togglePlayPause,\n ]);\n}\n","import { useEffect, useRef } from \"react\";\nimport { useGingerPlayback } from \"../context/GingerSplitContexts\";\n\nexport type GingerSleepTimerOptions = {\n durationMs?: number;\n stopAfterTracks?: number;\n respectPause?: boolean;\n enabled?: boolean;\n onFire?: () => void;\n};\n\nexport function useGingerSleepTimer(options: GingerSleepTimerOptions): void {\n const { durationMs, stopAfterTracks, respectPause = true, enabled = true, onFire } = options;\n const { currentIndex, pause, isPaused } = useGingerPlayback();\n const remainingTracksRef = useRef(stopAfterTracks ?? 0);\n const prevIndexRef = useRef(currentIndex);\n\n useEffect(() => {\n remainingTracksRef.current = stopAfterTracks ?? 0;\n }, [stopAfterTracks]);\n\n useEffect(() => {\n if (!enabled || !durationMs || durationMs <= 0) return;\n if (respectPause && isPaused) return;\n const id = setTimeout(() => {\n pause();\n onFire?.();\n }, durationMs);\n return () => clearTimeout(id);\n }, [durationMs, enabled, isPaused, onFire, pause, respectPause]);\n\n useEffect(() => {\n if (!enabled || !stopAfterTracks || stopAfterTracks <= 0) return;\n const prev = prevIndexRef.current;\n prevIndexRef.current = currentIndex;\n if (currentIndex === prev) return;\n remainingTracksRef.current -= 1;\n if (remainingTracksRef.current <= 0) {\n pause();\n onFire?.();\n }\n }, [currentIndex, enabled, onFire, pause, stopAfterTracks]);\n}\n","import { useEffect, useRef } from \"react\";\nimport { useGingerState } from \"../context/GingerSplitContexts\";\n\nexport function useGingerDebugLog(enabled = false): void {\n const state = useGingerState();\n const prevRef = useRef(state);\n\n useEffect(() => {\n if (!enabled || typeof console === \"undefined\") return;\n const prev = prevRef.current;\n if (prev !== state) {\n console.debug(\"[ginger]\", {\n from: {\n currentIndex: prev.currentIndex,\n isPaused: prev.isPaused,\n currentTime: prev.currentTime,\n repeatMode: prev.repeatMode,\n },\n to: {\n currentIndex: state.currentIndex,\n isPaused: state.isPaused,\n currentTime: state.currentTime,\n repeatMode: state.repeatMode,\n },\n });\n }\n prevRef.current = state;\n }, [enabled, state]);\n}\n","import { useCallback, useState } from \"react\";\nimport type { PointerEvent as ReactPointerEvent } from \"react\";\nimport {\n gingerStateFromContextValues,\n useGingerMedia,\n useGingerPlayback,\n} from \"../context/GingerSplitContexts\";\nimport { progressFraction } from \"../internal/selectors\";\n\nexport type SeekDragState = {\n /** Raw drag fraction — only updated during an active drag gesture. */\n fraction: number;\n /** Blended fraction: follows live playback when idle, drag position when dragging. */\n displayFraction: number;\n isDragging: boolean;\n onPointerDown: (event: ReactPointerEvent<HTMLElement>) => void;\n};\n\nfunction clamp01(value: number): number {\n return Math.max(0, Math.min(1, value));\n}\n\nexport function useSeekDrag(duration: number): SeekDragState {\n const media = useGingerMedia();\n const playback = useGingerPlayback();\n const { seek } = media;\n const [fraction, setFraction] = useState(0);\n const [isDragging, setIsDragging] = useState(false);\n\n const liveFraction = progressFraction(gingerStateFromContextValues(playback, media));\n const displayFraction = isDragging ? fraction : liveFraction;\n\n const onPointerDown = useCallback(\n (event: ReactPointerEvent<HTMLElement>) => {\n if (!(duration > 0)) return;\n const target = event.currentTarget;\n const rect = target.getBoundingClientRect();\n const update = (clientX: number) => {\n const ratio = clamp01((clientX - rect.left) / rect.width);\n setFraction(ratio);\n seek(ratio * duration);\n };\n setIsDragging(true);\n target.setPointerCapture(event.pointerId);\n update(event.clientX);\n const onMove = (moveEvent: PointerEvent) => update(moveEvent.clientX);\n const onUp = (upEvent: PointerEvent) => {\n update(upEvent.clientX);\n setIsDragging(false);\n target.releasePointerCapture(event.pointerId);\n target.removeEventListener(\"pointermove\", onMove);\n target.removeEventListener(\"pointerup\", onUp);\n target.removeEventListener(\"pointercancel\", onUp);\n };\n target.addEventListener(\"pointermove\", onMove);\n target.addEventListener(\"pointerup\", onUp);\n target.addEventListener(\"pointercancel\", onUp);\n },\n [duration, seek],\n );\n\n return { fraction, displayFraction, isDragging, onPointerDown };\n}\n","import { useEffect } from \"react\";\nimport { useGingerPlayback } from \"../context/GingerSplitContexts\";\nimport { computeNextIndex } from \"../core/transitions\";\n\nexport type UseNextTrackPrefetchOptions = {\n /** When false, no prefetch runs. Default true. */\n enabled?: boolean;\n /**\n * Match `crossOrigin` on `Ginger.Player` when `fileUrl` is cross-origin so the browser\n * can reuse cached media consistently.\n */\n crossOrigin?: \"\" | \"anonymous\" | \"use-credentials\" | undefined;\n};\n\n/**\n * Warms the browser cache for the **logical** next track (same rules as the Next control:\n * `computeNextIndex` from queue, repeat, and playback mode) using a detached `HTMLAudioElement`\n * with `preload=\"auto\"`. Safe to call alongside `Ginger.Player`; it does not replace main playback.\n */\nexport function useNextTrackPrefetch(options: UseNextTrackPrefetchOptions = {}): void {\n const { enabled = true, crossOrigin } = options;\n const { tracks, currentIndex, repeatMode, playbackMode } = useGingerPlayback();\n\n useEffect(() => {\n if (!enabled || typeof document === \"undefined\") return;\n const nextIndex = computeNextIndex({ tracks, currentIndex, repeatMode, playbackMode });\n if (nextIndex === currentIndex) return;\n const nextUrl = tracks[nextIndex]?.fileUrl ?? \"\";\n if (!nextUrl) return;\n\n const audio = document.createElement(\"audio\");\n audio.preload = \"auto\";\n if (crossOrigin) audio.crossOrigin = crossOrigin;\n audio.src = nextUrl;\n audio.load();\n\n return () => {\n audio.removeAttribute(\"src\");\n audio.load();\n };\n }, [enabled, crossOrigin, tracks, currentIndex, repeatMode, playbackMode]);\n}\n"],"names":["useGinger","pb","useGingerPlayback","md","useGingerMedia","useMemo","state","gingerStateFromContextValues","getCurrentTrack","derivePlaybackUiState","effectiveDuration","effectiveRemaining","progressFraction","resolvedArtwork","resolvedAlbumLine","entries","clampFftSize","n","p","attachLiveAnalyser","element","options","entry","Context","context","source","analyser","isFirst","id","detachLiveAnalyser","consumer","isPlaybackSink","first","emptyFreq","emptyTime","useGingerLiveAnalyzer","enabled","fftSize","smoothingTimeConstant","minDecibels","maxDecibels","audioRef","opts","frame","setFrame","useState","error","setError","isSuspended","setIsSuspended","meta","setMeta","freqRef","useRef","timeRef","resume","useCallback","ctx","contextHolderRef","analyserHolderRef","useLayoutEffect","cancelled","consumerId","rafId","onStateChange","runLoop","a","fq","td","attach","el","fft","e","msg","retryRaf","maxAttempts","attempts","retryLoop","out","_a","useGingerKeyboardShortcuts","bindings","togglePlayPause","next","prev","toggleMute","muteBinding","useEffect","playPause","nextKey","prevKey","muteKey","onKeyDown","event","target","key","useGingerSleepTimer","durationMs","stopAfterTracks","respectPause","onFire","currentIndex","pause","isPaused","remainingTracksRef","prevIndexRef","useGingerDebugLog","useGingerState","prevRef","clamp01","value","useSeekDrag","duration","media","playback","seek","fraction","setFraction","isDragging","setIsDragging","liveFraction","displayFraction","onPointerDown","rect","update","clientX","ratio","onMove","moveEvent","onUp","upEvent","useNextTrackPrefetch","crossOrigin","tracks","repeatMode","playbackMode","nextIndex","computeNextIndex","nextUrl","audio"],"mappings":"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"}
@@ -1,49 +1,46 @@
1
1
  import { useMemo as V, useState as R, useRef as M, useCallback as H, useLayoutEffect as J, useEffect as b } from "react";
2
2
  import { b as S, u as z, g as O, c as Y } from "./GingerSplitContexts-BzBExb95.js";
3
- import { r as Z, j as _, k as Q, l as $, m as ee, b as te, n as ne, o as re } from "./ginger-Dj-zM_lq.js";
3
+ import { r as Z, j as _, k as Q, l as $, m as ee, b as te, n as ne, o as re } from "./ginger-G5-3BYSb.js";
4
4
  function se() {
5
5
  const t = S(), e = z();
6
- return V(
7
- () => {
8
- const n = O(t, e);
9
- return {
10
- state: n,
11
- currentTrack: ne(n),
12
- playbackUi: te(n),
13
- duration: ee(n),
14
- remaining: $(n),
15
- progress: Q(n),
16
- artworkUrl: _(n),
17
- albumLine: Z(n),
18
- play: t.play,
19
- pause: t.pause,
20
- togglePlayPause: t.togglePlayPause,
21
- seek: e.seek,
22
- setVolume: e.setVolume,
23
- setMuted: e.setMuted,
24
- toggleMute: e.toggleMute,
25
- setPlaybackRate: e.setPlaybackRate,
26
- next: t.next,
27
- prev: t.prev,
28
- setRepeatMode: t.setRepeatMode,
29
- cycleRepeat: t.cycleRepeat,
30
- toggleShuffle: t.toggleShuffle,
31
- setQueue: t.setQueue,
32
- insertTrackAt: t.insertTrackAt,
33
- removeTrackAt: t.removeTrackAt,
34
- moveTrack: t.moveTrack,
35
- enqueueNext: t.enqueueNext,
36
- playTrackAt: t.playTrackAt,
37
- selectTrackAt: t.selectTrackAt,
38
- setPlaylistMeta: t.setPlaylistMeta,
39
- setPlaybackMode: t.setPlaybackMode,
40
- init: t.init,
41
- audioRef: e.audioRef,
42
- dispatch: t.dispatch
43
- };
44
- },
45
- [t, e]
46
- );
6
+ return V(() => {
7
+ const n = O(t, e);
8
+ return {
9
+ state: n,
10
+ currentTrack: ne(n),
11
+ playbackUi: te(n),
12
+ duration: ee(n),
13
+ remaining: $(n),
14
+ progress: Q(n),
15
+ artworkUrl: _(n),
16
+ albumLine: Z(n),
17
+ play: t.play,
18
+ pause: t.pause,
19
+ togglePlayPause: t.togglePlayPause,
20
+ seek: e.seek,
21
+ setVolume: e.setVolume,
22
+ setMuted: e.setMuted,
23
+ toggleMute: e.toggleMute,
24
+ setPlaybackRate: e.setPlaybackRate,
25
+ next: t.next,
26
+ prev: t.prev,
27
+ setRepeatMode: t.setRepeatMode,
28
+ cycleRepeat: t.cycleRepeat,
29
+ toggleShuffle: t.toggleShuffle,
30
+ setQueue: t.setQueue,
31
+ insertTrackAt: t.insertTrackAt,
32
+ removeTrackAt: t.removeTrackAt,
33
+ moveTrack: t.moveTrack,
34
+ enqueueNext: t.enqueueNext,
35
+ playTrackAt: t.playTrackAt,
36
+ selectTrackAt: t.selectTrackAt,
37
+ setPlaylistMeta: t.setPlaylistMeta,
38
+ setPlaybackMode: t.setPlaybackMode,
39
+ init: t.init,
40
+ audioRef: e.audioRef,
41
+ dispatch: t.dispatch
42
+ };
43
+ }, [t, e]);
47
44
  }
48
45
  const U = /* @__PURE__ */ new WeakMap();
49
46
  function ae(t) {
@@ -163,12 +160,23 @@ function me(t = !0, e = {}) {
163
160
  if (!t || typeof window > "u") return;
164
161
  const i = (e.playPause ?? " ").toLowerCase(), f = (e.next ?? "ArrowRight").toLowerCase(), u = (e.previous ?? "ArrowLeft").toLowerCase(), m = a == null ? void 0 : a.toLowerCase(), d = (c) => {
165
162
  const w = c.target;
166
- if (w && (["INPUT", "TEXTAREA", "SELECT"].includes(w.tagName) || w.isContentEditable)) return;
163
+ if (w && (["INPUT", "TEXTAREA", "SELECT"].includes(w.tagName) || w.isContentEditable))
164
+ return;
167
165
  const g = c.key.toLowerCase();
168
166
  g === i ? (c.preventDefault(), n()) : g === f ? (c.preventDefault(), s()) : g === u ? (c.preventDefault(), o()) : m && g === m && (c.preventDefault(), r());
169
167
  };
170
168
  return window.addEventListener("keydown", d), () => window.removeEventListener("keydown", d);
171
- }, [e.next, e.playPause, e.previous, t, a, s, o, r, n]);
169
+ }, [
170
+ e.next,
171
+ e.playPause,
172
+ e.previous,
173
+ t,
174
+ a,
175
+ s,
176
+ o,
177
+ r,
178
+ n
179
+ ]);
172
180
  }
173
181
  function de(t) {
174
182
  const { durationMs: e, stopAfterTracks: n, respectPause: s = !0, enabled: o = !0, onFire: r } = t, { currentIndex: a, pause: i, isPaused: f } = S(), u = M(n ?? 0), m = M(a);
@@ -254,4 +262,4 @@ export {
254
262
  ye as h,
255
263
  se as u
256
264
  };
257
- //# sourceMappingURL=useNextTrackPrefetch-CmfCP_Vz.js.map
265
+ //# sourceMappingURL=useNextTrackPrefetch-Mj8dQLYR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useNextTrackPrefetch-Mj8dQLYR.js","sources":["../src/hooks/useGinger.ts","../src/analyzer/liveAudioGraph.ts","../src/analyzer/useGingerLiveAnalyzer.ts","../src/hooks/useGingerKeyboardShortcuts.ts","../src/hooks/useGingerSleepTimer.ts","../src/hooks/useGingerDebugLog.ts","../src/hooks/useSeekDrag.ts","../src/hooks/useNextTrackPrefetch.ts"],"sourcesContent":["import { useMemo } from \"react\";\nimport {\n gingerStateFromContextValues,\n useGingerMedia,\n useGingerPlayback,\n} from \"../context/GingerSplitContexts\";\nimport {\n derivePlaybackUiState,\n effectiveDuration,\n effectiveRemaining,\n getCurrentTrack,\n progressFraction,\n resolvedAlbumLine,\n resolvedArtwork,\n} from \"../internal/selectors\";\n\nexport function useGinger() {\n const pb = useGingerPlayback();\n const md = useGingerMedia();\n\n return useMemo(() => {\n const state = gingerStateFromContextValues(pb, md);\n return {\n state,\n currentTrack: getCurrentTrack(state),\n playbackUi: derivePlaybackUiState(state),\n duration: effectiveDuration(state),\n remaining: effectiveRemaining(state),\n progress: progressFraction(state),\n artworkUrl: resolvedArtwork(state),\n albumLine: resolvedAlbumLine(state),\n play: pb.play,\n pause: pb.pause,\n togglePlayPause: pb.togglePlayPause,\n seek: md.seek,\n setVolume: md.setVolume,\n setMuted: md.setMuted,\n toggleMute: md.toggleMute,\n setPlaybackRate: md.setPlaybackRate,\n next: pb.next,\n prev: pb.prev,\n setRepeatMode: pb.setRepeatMode,\n cycleRepeat: pb.cycleRepeat,\n toggleShuffle: pb.toggleShuffle,\n setQueue: pb.setQueue,\n insertTrackAt: pb.insertTrackAt,\n removeTrackAt: pb.removeTrackAt,\n moveTrack: pb.moveTrack,\n enqueueNext: pb.enqueueNext,\n playTrackAt: pb.playTrackAt,\n selectTrackAt: pb.selectTrackAt,\n setPlaylistMeta: pb.setPlaylistMeta,\n setPlaybackMode: pb.setPlaybackMode,\n init: pb.init,\n audioRef: md.audioRef,\n dispatch: pb.dispatch,\n };\n }, [pb, md]);\n}\n","/** One MediaElementAudioSourceNode per HTMLAudioElement; multiple AnalyserNodes may tap the source. */\n\nexport type LiveAnalyserOptions = {\n fftSize: number;\n smoothingTimeConstant: number;\n minDecibels: number;\n maxDecibels: number;\n};\n\ntype Consumer = {\n analyser: AnalyserNode;\n /** This analyser is wired to `audioContext.destination` so the graph is audible. */\n isPlaybackSink: boolean;\n};\n\ntype ElementEntry = {\n context: AudioContext;\n source: MediaElementAudioSourceNode;\n consumers: Map<number, Consumer>;\n nextId: number;\n};\n\nconst entries = new WeakMap<HTMLAudioElement, ElementEntry>();\n\nfunction clampFftSize(n: number): number {\n const p = 2 ** Math.round(Math.log2(n));\n return Math.min(32768, Math.max(32, p));\n}\n\nexport function attachLiveAnalyser(\n element: HTMLAudioElement,\n options: LiveAnalyserOptions,\n): { id: number; context: AudioContext; analyser: AnalyserNode } {\n let entry = entries.get(element);\n if (!entry) {\n const Context =\n window.AudioContext ??\n (window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n if (!Context) {\n throw new Error(\"Web Audio API is not available\");\n }\n const context = new Context();\n const source = context.createMediaElementSource(element);\n entry = { context, source, consumers: new Map(), nextId: 0 };\n entries.set(element, entry);\n }\n\n const { context, source } = entry;\n const analyser = context.createAnalyser();\n analyser.fftSize = clampFftSize(options.fftSize);\n analyser.smoothingTimeConstant = options.smoothingTimeConstant;\n analyser.minDecibels = options.minDecibels;\n analyser.maxDecibels = options.maxDecibels;\n\n source.connect(analyser);\n\n const isFirst = entry.consumers.size === 0;\n if (isFirst) {\n analyser.connect(context.destination);\n }\n\n const id = entry.nextId;\n entry.nextId += 1;\n entry.consumers.set(id, { analyser, isPlaybackSink: isFirst });\n\n return { id, context, analyser };\n}\n\nexport function detachLiveAnalyser(element: HTMLAudioElement, id: number): void {\n const entry = entries.get(element);\n if (!entry) return;\n\n const consumer = entry.consumers.get(id);\n if (!consumer) return;\n\n const { analyser, isPlaybackSink } = consumer;\n analyser.disconnect();\n entry.consumers.delete(id);\n\n if (entry.consumers.size === 0) {\n try {\n entry.source.disconnect();\n } catch {\n // ignore\n }\n void entry.context.close();\n entries.delete(element);\n return;\n }\n\n if (isPlaybackSink) {\n const first = entry.consumers.values().next().value as Consumer | undefined;\n if (first) {\n first.analyser.connect(entry.context.destination);\n first.isPlaybackSink = true;\n }\n }\n}\n","import { useCallback, useLayoutEffect, useMemo, useRef, useState } from \"react\";\nimport { useGinger } from \"../hooks/useGinger\";\nimport { type LiveAnalyserOptions, attachLiveAnalyser, detachLiveAnalyser } from \"./liveAudioGraph\";\n\nexport type UseGingerLiveAnalyzerOptions = {\n /** When false, the analyser is detached and no frames are read. Default true. */\n enabled?: boolean;\n fftSize?: number;\n smoothingTimeConstant?: number;\n minDecibels?: number;\n maxDecibels?: number;\n};\n\nexport type UseGingerLiveAnalyzerResult = {\n /** Byte frequency data (0–255); length equals `frequencyBinCount`. Updated each animation frame while enabled. */\n frequencyData: Uint8Array;\n /** Byte time-domain data (0–255); length equals `fftSize`. */\n timeDomainData: Uint8Array;\n frequencyBinCount: number;\n sampleRate: number;\n isSuspended: boolean;\n error: string | null;\n resume: () => Promise<void>;\n};\n\nconst emptyFreq = new Uint8Array(0);\nconst emptyTime = new Uint8Array(0);\n\nexport function useGingerLiveAnalyzer(\n options: UseGingerLiveAnalyzerOptions = {},\n): UseGingerLiveAnalyzerResult {\n const {\n enabled = true,\n fftSize = 2048,\n smoothingTimeConstant = 0.8,\n minDecibels = -100,\n maxDecibels = -30,\n } = options;\n\n const { audioRef, state } = useGinger();\n const opts = useMemo<LiveAnalyserOptions>(\n () => ({\n fftSize,\n smoothingTimeConstant,\n minDecibels,\n maxDecibels,\n }),\n [fftSize, smoothingTimeConstant, minDecibels, maxDecibels],\n );\n\n const [frame, setFrame] = useState(0);\n const [error, setError] = useState<string | null>(null);\n const [isSuspended, setIsSuspended] = useState(false);\n const [meta, setMeta] = useState({ frequencyBinCount: 0, sampleRate: 0 });\n\n const freqRef = useRef<Uint8Array>(emptyFreq);\n const timeRef = useRef<Uint8Array>(emptyTime);\n\n const resume = useCallback(async () => {\n const ctx = contextHolderRef.current;\n if (ctx && ctx.state === \"suspended\") {\n await ctx.resume();\n }\n }, []);\n\n const contextHolderRef = useRef<AudioContext | null>(null);\n const analyserHolderRef = useRef<AnalyserNode | null>(null);\n\n useLayoutEffect(() => {\n if (!enabled || typeof window === \"undefined\") {\n return;\n }\n\n let cancelled = false;\n let consumerId: number | null = null;\n let element: HTMLAudioElement | null = null;\n let rafId = 0;\n\n const onStateChange = () => {\n const ctx = contextHolderRef.current;\n if (ctx) setIsSuspended(ctx.state === \"suspended\");\n };\n\n const runLoop = () => {\n if (cancelled) return;\n const a = analyserHolderRef.current;\n const fq = freqRef.current;\n const td = timeRef.current;\n if (a && fq.length > 0 && td.length > 0) {\n a.getByteFrequencyData(fq as Uint8Array<ArrayBuffer>);\n a.getByteTimeDomainData(td as Uint8Array<ArrayBuffer>);\n setFrame((n) => n + 1);\n }\n rafId = requestAnimationFrame(runLoop);\n };\n\n type AttachOutcome = \"ok\" | \"no-element\" | \"error\";\n\n const attach = (): AttachOutcome => {\n const el = audioRef.current;\n if (!el || cancelled) return \"no-element\";\n try {\n const { id, context, analyser } = attachLiveAnalyser(el, opts);\n consumerId = id;\n element = el;\n contextHolderRef.current = context;\n analyserHolderRef.current = analyser;\n setIsSuspended(context.state === \"suspended\");\n setError(null);\n\n context.addEventListener(\"statechange\", onStateChange);\n\n const n = analyser.frequencyBinCount;\n const fft = analyser.fftSize;\n freqRef.current = new Uint8Array(n);\n timeRef.current = new Uint8Array(fft);\n setMeta({ frequencyBinCount: n, sampleRate: context.sampleRate });\n\n rafId = requestAnimationFrame(runLoop);\n return \"ok\";\n } catch (e) {\n const msg = e instanceof Error ? e.message : \"Failed to attach live analyser\";\n setError(msg);\n contextHolderRef.current = null;\n analyserHolderRef.current = null;\n freqRef.current = emptyFreq;\n timeRef.current = emptyTime;\n setMeta({ frequencyBinCount: 0, sampleRate: 0 });\n return \"error\";\n }\n };\n\n const first = attach();\n if (first !== \"ok\") {\n let retryRaf = 0;\n const maxAttempts = 120;\n let attempts = 0;\n\n const retryLoop = () => {\n if (cancelled) return;\n const out = attach();\n if (out === \"ok\" || out === \"error\") return;\n attempts += 1;\n if (attempts >= maxAttempts) return;\n retryRaf = requestAnimationFrame(retryLoop);\n };\n\n if (first === \"no-element\") {\n retryRaf = requestAnimationFrame(retryLoop);\n }\n\n return () => {\n cancelled = true;\n cancelAnimationFrame(retryRaf);\n cancelAnimationFrame(rafId);\n if (consumerId != null && element) {\n detachLiveAnalyser(element, consumerId);\n }\n contextHolderRef.current?.removeEventListener(\"statechange\", onStateChange);\n contextHolderRef.current = null;\n analyserHolderRef.current = null;\n freqRef.current = emptyFreq;\n timeRef.current = emptyTime;\n };\n }\n\n return () => {\n cancelled = true;\n cancelAnimationFrame(rafId);\n if (consumerId != null && element) {\n detachLiveAnalyser(element, consumerId);\n }\n contextHolderRef.current?.removeEventListener(\"statechange\", onStateChange);\n contextHolderRef.current = null;\n analyserHolderRef.current = null;\n freqRef.current = emptyFreq;\n timeRef.current = emptyTime;\n setMeta({ frequencyBinCount: 0, sampleRate: 0 });\n };\n }, [enabled, audioRef, opts, state.currentIndex]);\n\n void frame;\n\n return {\n frequencyData: freqRef.current,\n timeDomainData: timeRef.current,\n frequencyBinCount: meta.frequencyBinCount,\n sampleRate: meta.sampleRate,\n isSuspended,\n error,\n resume,\n };\n}\n","import { useEffect } from \"react\";\nimport { useGingerMedia, useGingerPlayback } from \"../context/GingerSplitContexts\";\n\nexport type GingerKeyboardShortcutBindings = {\n playPause?: string;\n next?: string;\n previous?: string;\n mute?: string;\n};\n\nexport function useGingerKeyboardShortcuts(\n enabled = true,\n bindings: GingerKeyboardShortcutBindings = {},\n): void {\n const { togglePlayPause, next, prev } = useGingerPlayback();\n const { toggleMute } = useGingerMedia();\n\n const muteBinding = bindings.mute;\n\n useEffect(() => {\n if (!enabled || typeof window === \"undefined\") return;\n const playPause = (bindings.playPause ?? \" \").toLowerCase();\n const nextKey = (bindings.next ?? \"ArrowRight\").toLowerCase();\n const prevKey = (bindings.previous ?? \"ArrowLeft\").toLowerCase();\n const muteKey = muteBinding?.toLowerCase();\n\n const onKeyDown = (event: KeyboardEvent) => {\n const target = event.target as HTMLElement | null;\n if (\n target &&\n ([\"INPUT\", \"TEXTAREA\", \"SELECT\"].includes(target.tagName) || target.isContentEditable)\n )\n return;\n const key = event.key.toLowerCase();\n if (key === playPause) {\n event.preventDefault();\n togglePlayPause();\n } else if (key === nextKey) {\n event.preventDefault();\n next();\n } else if (key === prevKey) {\n event.preventDefault();\n prev();\n } else if (muteKey && key === muteKey) {\n event.preventDefault();\n toggleMute();\n }\n };\n window.addEventListener(\"keydown\", onKeyDown);\n return () => window.removeEventListener(\"keydown\", onKeyDown);\n }, [\n bindings.next,\n bindings.playPause,\n bindings.previous,\n enabled,\n muteBinding,\n next,\n prev,\n toggleMute,\n togglePlayPause,\n ]);\n}\n","import { useEffect, useRef } from \"react\";\nimport { useGingerPlayback } from \"../context/GingerSplitContexts\";\n\nexport type GingerSleepTimerOptions = {\n durationMs?: number;\n stopAfterTracks?: number;\n respectPause?: boolean;\n enabled?: boolean;\n onFire?: () => void;\n};\n\nexport function useGingerSleepTimer(options: GingerSleepTimerOptions): void {\n const { durationMs, stopAfterTracks, respectPause = true, enabled = true, onFire } = options;\n const { currentIndex, pause, isPaused } = useGingerPlayback();\n const remainingTracksRef = useRef(stopAfterTracks ?? 0);\n const prevIndexRef = useRef(currentIndex);\n\n useEffect(() => {\n remainingTracksRef.current = stopAfterTracks ?? 0;\n }, [stopAfterTracks]);\n\n useEffect(() => {\n if (!enabled || !durationMs || durationMs <= 0) return;\n if (respectPause && isPaused) return;\n const id = setTimeout(() => {\n pause();\n onFire?.();\n }, durationMs);\n return () => clearTimeout(id);\n }, [durationMs, enabled, isPaused, onFire, pause, respectPause]);\n\n useEffect(() => {\n if (!enabled || !stopAfterTracks || stopAfterTracks <= 0) return;\n const prev = prevIndexRef.current;\n prevIndexRef.current = currentIndex;\n if (currentIndex === prev) return;\n remainingTracksRef.current -= 1;\n if (remainingTracksRef.current <= 0) {\n pause();\n onFire?.();\n }\n }, [currentIndex, enabled, onFire, pause, stopAfterTracks]);\n}\n","import { useEffect, useRef } from \"react\";\nimport { useGingerState } from \"../context/GingerSplitContexts\";\n\nexport function useGingerDebugLog(enabled = false): void {\n const state = useGingerState();\n const prevRef = useRef(state);\n\n useEffect(() => {\n if (!enabled || typeof console === \"undefined\") return;\n const prev = prevRef.current;\n if (prev !== state) {\n console.debug(\"[ginger]\", {\n from: {\n currentIndex: prev.currentIndex,\n isPaused: prev.isPaused,\n currentTime: prev.currentTime,\n repeatMode: prev.repeatMode,\n },\n to: {\n currentIndex: state.currentIndex,\n isPaused: state.isPaused,\n currentTime: state.currentTime,\n repeatMode: state.repeatMode,\n },\n });\n }\n prevRef.current = state;\n }, [enabled, state]);\n}\n","import { useCallback, useState } from \"react\";\nimport type { PointerEvent as ReactPointerEvent } from \"react\";\nimport {\n gingerStateFromContextValues,\n useGingerMedia,\n useGingerPlayback,\n} from \"../context/GingerSplitContexts\";\nimport { progressFraction } from \"../internal/selectors\";\n\nexport type SeekDragState = {\n /** Raw drag fraction — only updated during an active drag gesture. */\n fraction: number;\n /** Blended fraction: follows live playback when idle, drag position when dragging. */\n displayFraction: number;\n isDragging: boolean;\n onPointerDown: (event: ReactPointerEvent<HTMLElement>) => void;\n};\n\nfunction clamp01(value: number): number {\n return Math.max(0, Math.min(1, value));\n}\n\nexport function useSeekDrag(duration: number): SeekDragState {\n const media = useGingerMedia();\n const playback = useGingerPlayback();\n const { seek } = media;\n const [fraction, setFraction] = useState(0);\n const [isDragging, setIsDragging] = useState(false);\n\n const liveFraction = progressFraction(gingerStateFromContextValues(playback, media));\n const displayFraction = isDragging ? fraction : liveFraction;\n\n const onPointerDown = useCallback(\n (event: ReactPointerEvent<HTMLElement>) => {\n if (!(duration > 0)) return;\n const target = event.currentTarget;\n const rect = target.getBoundingClientRect();\n const update = (clientX: number) => {\n const ratio = clamp01((clientX - rect.left) / rect.width);\n setFraction(ratio);\n seek(ratio * duration);\n };\n setIsDragging(true);\n target.setPointerCapture(event.pointerId);\n update(event.clientX);\n const onMove = (moveEvent: PointerEvent) => update(moveEvent.clientX);\n const onUp = (upEvent: PointerEvent) => {\n update(upEvent.clientX);\n setIsDragging(false);\n target.releasePointerCapture(event.pointerId);\n target.removeEventListener(\"pointermove\", onMove);\n target.removeEventListener(\"pointerup\", onUp);\n target.removeEventListener(\"pointercancel\", onUp);\n };\n target.addEventListener(\"pointermove\", onMove);\n target.addEventListener(\"pointerup\", onUp);\n target.addEventListener(\"pointercancel\", onUp);\n },\n [duration, seek],\n );\n\n return { fraction, displayFraction, isDragging, onPointerDown };\n}\n","import { useEffect } from \"react\";\nimport { useGingerPlayback } from \"../context/GingerSplitContexts\";\nimport { computeNextIndex } from \"../core/transitions\";\n\nexport type UseNextTrackPrefetchOptions = {\n /** When false, no prefetch runs. Default true. */\n enabled?: boolean;\n /**\n * Match `crossOrigin` on `Ginger.Player` when `fileUrl` is cross-origin so the browser\n * can reuse cached media consistently.\n */\n crossOrigin?: \"\" | \"anonymous\" | \"use-credentials\" | undefined;\n};\n\n/**\n * Warms the browser cache for the **logical** next track (same rules as the Next control:\n * `computeNextIndex` from queue, repeat, and playback mode) using a detached `HTMLAudioElement`\n * with `preload=\"auto\"`. Safe to call alongside `Ginger.Player`; it does not replace main playback.\n */\nexport function useNextTrackPrefetch(options: UseNextTrackPrefetchOptions = {}): void {\n const { enabled = true, crossOrigin } = options;\n const { tracks, currentIndex, repeatMode, playbackMode } = useGingerPlayback();\n\n useEffect(() => {\n if (!enabled || typeof document === \"undefined\") return;\n const nextIndex = computeNextIndex({ tracks, currentIndex, repeatMode, playbackMode });\n if (nextIndex === currentIndex) return;\n const nextUrl = tracks[nextIndex]?.fileUrl ?? \"\";\n if (!nextUrl) return;\n\n const audio = document.createElement(\"audio\");\n audio.preload = \"auto\";\n if (crossOrigin) audio.crossOrigin = crossOrigin;\n audio.src = nextUrl;\n audio.load();\n\n return () => {\n audio.removeAttribute(\"src\");\n audio.load();\n };\n }, [enabled, crossOrigin, tracks, currentIndex, repeatMode, playbackMode]);\n}\n"],"names":["useGinger","pb","useGingerPlayback","md","useGingerMedia","useMemo","state","gingerStateFromContextValues","getCurrentTrack","derivePlaybackUiState","effectiveDuration","effectiveRemaining","progressFraction","resolvedArtwork","resolvedAlbumLine","entries","clampFftSize","n","p","attachLiveAnalyser","element","options","entry","Context","context","source","analyser","isFirst","id","detachLiveAnalyser","consumer","isPlaybackSink","first","emptyFreq","emptyTime","useGingerLiveAnalyzer","enabled","fftSize","smoothingTimeConstant","minDecibels","maxDecibels","audioRef","opts","frame","setFrame","useState","error","setError","isSuspended","setIsSuspended","meta","setMeta","freqRef","useRef","timeRef","resume","useCallback","ctx","contextHolderRef","analyserHolderRef","useLayoutEffect","cancelled","consumerId","rafId","onStateChange","runLoop","a","fq","td","attach","el","fft","e","msg","retryRaf","maxAttempts","attempts","retryLoop","out","_a","useGingerKeyboardShortcuts","bindings","togglePlayPause","next","prev","toggleMute","muteBinding","useEffect","playPause","nextKey","prevKey","muteKey","onKeyDown","event","target","key","useGingerSleepTimer","durationMs","stopAfterTracks","respectPause","onFire","currentIndex","pause","isPaused","remainingTracksRef","prevIndexRef","useGingerDebugLog","useGingerState","prevRef","clamp01","value","useSeekDrag","duration","media","playback","seek","fraction","setFraction","isDragging","setIsDragging","liveFraction","displayFraction","onPointerDown","rect","update","clientX","ratio","onMove","moveEvent","onUp","upEvent","useNextTrackPrefetch","crossOrigin","tracks","repeatMode","playbackMode","nextIndex","computeNextIndex","nextUrl","audio"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"analyzeAudioFile.d.ts","sourceRoot":"","sources":["../../src/waveform/analyzeAudioFile.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,uBAAuB,GAAG;IACpC,2FAA2F;IAC3F,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yFAAyF;IACzF,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+FAA+F;IAC/F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,gFAAgF;IAChF,aAAa,EAAE,MAAM,EAAE,EAAE,CAAC;IAC1B,uGAAuG;IACvG,WAAW,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC;CAC1B,CAAC;AAwGF;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,GAAE,uBAA4B,GAAG,iBAAiB,CAwBhH;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,iBAAiB,CAAC,CAiB5B"}
1
+ {"version":3,"file":"analyzeAudioFile.d.ts","sourceRoot":"","sources":["../../src/waveform/analyzeAudioFile.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,uBAAuB,GAAG;IACpC,2FAA2F;IAC3F,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oEAAoE;IACpE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,yFAAyF;IACzF,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+FAA+F;IAC/F,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,gFAAgF;IAChF,aAAa,EAAE,MAAM,EAAE,EAAE,CAAC;IAC1B,uGAAuG;IACvG,WAAW,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC;CAC1B,CAAC;AAsGF;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,WAAW,EACnB,OAAO,GAAE,uBAA4B,GACpC,iBAAiB,CAwBnB;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,iBAAiB,CAAC,CAmB5B"}
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const y=require("react");function F(e,t=64){const[r,a]=y.useState({peaks:[],isLoading:!1,error:null});return y.useEffect(()=>{if(!e){a({peaks:[],isLoading:!1,error:null});return}let o=!1;return a(n=>({...n,isLoading:!0,error:null})),(async()=>{try{const n=await fetch(e);if(!n.ok)throw new Error(`Fetch failed: ${n.status} ${n.statusText}`);const l=await n.arrayBuffer(),s=new AudioContext,u=(await s.decodeAudioData(l)).getChannelData(0),w=Math.max(1,Math.floor(u.length/t)),f=[];for(let d=0;d<t;d+=1){let i=0;const h=d*w,M=Math.min(u.length,h+w);for(let c=h;c<M;c+=1)i=Math.max(i,Math.abs(u[c]??0));f.push(i)}await s.close(),o||a({peaks:f,isLoading:!1,error:null})}catch(n){o||a({peaks:[],isLoading:!1,error:n instanceof Error?n.message:"Failed to decode peaks"})}})(),()=>{o=!0}},[t,e]),r}function L(e,t){const r=e.length;if(r!==t.length||r<2||r&r-1)throw new Error("fftInPlace: length must be equal powers of 2 >= 2");let a=0;for(let o=0;o<r-1;o+=1){if(o<a){const l=e[o],s=t[o];e[o]=e[a],t[o]=t[a],e[a]=l,t[a]=s}let n=r>>1;for(;n<=a;)a-=n,n>>=1;a+=n}for(let o=2;o<=r;o<<=1){const n=-2*Math.PI/o,l=Math.cos(n),s=Math.sin(n);for(let g=0;g<r;g+=o){let u=1,w=0;const f=o>>1;for(let d=0;d<f;d+=1){const i=g+d,h=i+f,M=u*e[h]-w*t[h],c=u*t[h]+w*e[h];e[h]=e[i]-M,t[h]=t[i]-c,e[i]=e[i]+M,t[i]=t[i]+c;const m=u*l-w*s,p=u*s+w*l;u=m,w=p}}}}function C(e){const t=e.length;if(t<2||t&t-1)throw new Error("realFftMagnitudes: length must be a power of 2 >= 2");const r=new Float64Array(t),a=new Float64Array(t);for(let n=0;n<t;n+=1)r[n]=e[n];L(r,a);const o=new Float64Array(t>>1);for(let n=0;n<t>>1;n+=1)o[n]=Math.hypot(r[n],a[n]);return o}function k(e){const t=new Float64Array(e);if(e===1)return t[0]=1,t;const r=e-1;for(let a=0;a<e;a+=1)t[a]=.5*(1-Math.cos(2*Math.PI*a/r));return t}function S(e){const t=2**Math.round(Math.log2(e));return Math.min(8192,Math.max(32,t))}function b(e){const{numberOfChannels:t,length:r}=e;if(t===1)return e.getChannelData(0);const a=new Float32Array(r),o=1/t;for(let n=0;n<t;n+=1){const l=e.getChannelData(n);for(let s=0;s<r;s+=1)a[s]+=l[s]*o}return a}function B(e,t){if(t==="mix")return b(e);const r=Math.max(0,Math.min(e.numberOfChannels-1,t));return e.getChannelData(r)}function E(e,t,r){const a=[],o=e.length;if(o===0){for(let l=0;l<t;l+=1)a.push(Array.from({length:r},()=>0));return a}const n=o/t;for(let l=0;l<t;l+=1){const s=[],g=Math.floor(l*n),u=Math.floor((l+1)*n),f=Math.max(1,u-g)/r;for(let d=0;d<r;d+=1){const i=Math.floor(g+d*f),h=Math.min(u,Math.floor(g+(d+1)*f));let M=0;for(let c=i;c<h;c+=1)M=Math.max(M,Math.abs(e[c]??0));s.push(M)}a.push(s)}return a}function z(e,t,r,a){const o=[];let n=1e-12;const l=e.length,s=S(r),g=s>>1,u=Math.min(a,g),w=k(s);if(l<s){for(let f=0;f<t;f+=1)o.push(Array.from({length:u},()=>0));return{rows:o,maxMag:1}}for(let f=0;f<t;f+=1){const d=t<=1?0:Math.min(Math.floor(f*(l-s)/(t-1)),l-s),i=new Float64Array(s);for(let c=0;c<s;c+=1)i[c]=(e[d+c]??0)*(w[c]??0);const h=C(i),M=[];for(let c=0;c<u;c+=1){const m=h[c]??0;M.push(m),n=Math.max(n,m)}o.push(M)}return{rows:o,maxMag:n}}function A(e,t={}){const r=Math.max(1,t.timeSlices??128),a=Math.max(1,t.samplesPerSlice??8),o=!!t.spectrogram,n=t.fftSize??1024,l=Math.max(1,t.frequencyBins??256),s=t.channel??0,g=B(e,s),u=E(g,r,a),w={duration:e.duration,sampleRate:e.sampleRate,amplitudeGrid:u};if(o){const{rows:f,maxMag:d}=z(g,r,n,l),i=d>0?1/d:1;w.spectrogram=f.map(h=>h.map(M=>M*i))}return w}async function x(e,t={}){const r=await fetch(e);if(!r.ok)throw new Error(`Fetch failed: ${r.status} ${r.statusText}`);const a=await r.arrayBuffer(),o=window.AudioContext??window.webkitAudioContext;if(!o)throw new Error("Web Audio API is not available");const n=new o;try{const l=await n.decodeAudioData(a.slice(0));return A(l,t)}finally{await n.close()}}function P(e,t={}){const[r,a]=y.useState({data:null,isLoading:!1,error:null});return y.useEffect(()=>{if(!e){a({data:null,isLoading:!1,error:null});return}if(typeof window>"u"){a({data:null,isLoading:!1,error:null});return}let o=!1;return a(n=>({...n,isLoading:!0,error:null})),(async()=>{try{const n=await x(e,t);o||a({data:n,isLoading:!1,error:null})}catch(n){o||a({data:null,isLoading:!1,error:n instanceof Error?n.message:"Failed to analyze audio file"})}})(),()=>{o=!0}},[e,t.timeSlices,t.samplesPerSlice,t.spectrogram,t.fftSize,t.frequencyBins,t.channel]),r}exports.analyzeAudioBuffer=A;exports.analyzeAudioFile=x;exports.useAudioFileAnalysis=P;exports.useAudioPeaks=F;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const y=require("react");function F(e,t=64){const[r,a]=y.useState({peaks:[],isLoading:!1,error:null});return y.useEffect(()=>{if(!e){a({peaks:[],isLoading:!1,error:null});return}let o=!1;return a(n=>({...n,isLoading:!0,error:null})),(async()=>{try{const n=await fetch(e);if(!n.ok)throw new Error(`Fetch failed: ${n.status} ${n.statusText}`);const l=await n.arrayBuffer(),s=new AudioContext;try{const u=(await s.decodeAudioData(l)).getChannelData(0),w=Math.max(1,Math.floor(u.length/t)),f=[];for(let d=0;d<t;d+=1){let i=0;const h=d*w,M=Math.min(u.length,h+w);for(let c=h;c<M;c+=1)i=Math.max(i,Math.abs(u[c]??0));f.push(i)}o||a({peaks:f,isLoading:!1,error:null})}finally{await s.close().catch(()=>{})}}catch(n){o||a({peaks:[],isLoading:!1,error:n instanceof Error?n.message:"Failed to decode peaks"})}})(),()=>{o=!0}},[t,e]),r}function L(e,t){const r=e.length;if(r!==t.length||r<2||r&r-1)throw new Error("fftInPlace: length must be equal powers of 2 >= 2");let a=0;for(let o=0;o<r-1;o+=1){if(o<a){const l=e[o],s=t[o];e[o]=e[a],t[o]=t[a],e[a]=l,t[a]=s}let n=r>>1;for(;n<=a;)a-=n,n>>=1;a+=n}for(let o=2;o<=r;o<<=1){const n=-2*Math.PI/o,l=Math.cos(n),s=Math.sin(n);for(let g=0;g<r;g+=o){let u=1,w=0;const f=o>>1;for(let d=0;d<f;d+=1){const i=g+d,h=i+f,M=u*e[h]-w*t[h],c=u*t[h]+w*e[h];e[h]=e[i]-M,t[h]=t[i]-c,e[i]=e[i]+M,t[i]=t[i]+c;const m=u*l-w*s,p=u*s+w*l;u=m,w=p}}}}function C(e){const t=e.length;if(t<2||t&t-1)throw new Error("realFftMagnitudes: length must be a power of 2 >= 2");const r=new Float64Array(t),a=new Float64Array(t);for(let n=0;n<t;n+=1)r[n]=e[n];L(r,a);const o=new Float64Array(t>>1);for(let n=0;n<t>>1;n+=1)o[n]=Math.hypot(r[n],a[n]);return o}function k(e){const t=new Float64Array(e);if(e===1)return t[0]=1,t;const r=e-1;for(let a=0;a<e;a+=1)t[a]=.5*(1-Math.cos(2*Math.PI*a/r));return t}function S(e){const t=2**Math.round(Math.log2(e));return Math.min(8192,Math.max(32,t))}function b(e){const{numberOfChannels:t,length:r}=e;if(t===1)return e.getChannelData(0);const a=new Float32Array(r),o=1/t;for(let n=0;n<t;n+=1){const l=e.getChannelData(n);for(let s=0;s<r;s+=1)a[s]+=l[s]*o}return a}function B(e,t){if(t==="mix")return b(e);const r=Math.max(0,Math.min(e.numberOfChannels-1,t));return e.getChannelData(r)}function E(e,t,r){const a=[],o=e.length;if(o===0){for(let l=0;l<t;l+=1)a.push(Array.from({length:r},()=>0));return a}const n=o/t;for(let l=0;l<t;l+=1){const s=[],g=Math.floor(l*n),u=Math.floor((l+1)*n),f=Math.max(1,u-g)/r;for(let d=0;d<r;d+=1){const i=Math.floor(g+d*f),h=Math.min(u,Math.floor(g+(d+1)*f));let M=0;for(let c=i;c<h;c+=1)M=Math.max(M,Math.abs(e[c]??0));s.push(M)}a.push(s)}return a}function z(e,t,r,a){const o=[];let n=1e-12;const l=e.length,s=S(r),g=s>>1,u=Math.min(a,g),w=k(s);if(l<s){for(let f=0;f<t;f+=1)o.push(Array.from({length:u},()=>0));return{rows:o,maxMag:1}}for(let f=0;f<t;f+=1){const d=t<=1?0:Math.min(Math.floor(f*(l-s)/(t-1)),l-s),i=new Float64Array(s);for(let c=0;c<s;c+=1)i[c]=(e[d+c]??0)*(w[c]??0);const h=C(i),M=[];for(let c=0;c<u;c+=1){const m=h[c]??0;M.push(m),n=Math.max(n,m)}o.push(M)}return{rows:o,maxMag:n}}function A(e,t={}){const r=Math.max(1,t.timeSlices??128),a=Math.max(1,t.samplesPerSlice??8),o=!!t.spectrogram,n=t.fftSize??1024,l=Math.max(1,t.frequencyBins??256),s=t.channel??0,g=B(e,s),u=E(g,r,a),w={duration:e.duration,sampleRate:e.sampleRate,amplitudeGrid:u};if(o){const{rows:f,maxMag:d}=z(g,r,n,l),i=d>0?1/d:1;w.spectrogram=f.map(h=>h.map(M=>M*i))}return w}async function x(e,t={}){const r=await fetch(e);if(!r.ok)throw new Error(`Fetch failed: ${r.status} ${r.statusText}`);const a=await r.arrayBuffer(),o=window.AudioContext??window.webkitAudioContext;if(!o)throw new Error("Web Audio API is not available");const n=new o;try{const l=await n.decodeAudioData(a.slice(0));return A(l,t)}finally{await n.close()}}function P(e,t={}){const[r,a]=y.useState({data:null,isLoading:!1,error:null});return y.useEffect(()=>{if(!e){a({data:null,isLoading:!1,error:null});return}if(typeof window>"u"){a({data:null,isLoading:!1,error:null});return}let o=!1;return a(n=>({...n,isLoading:!0,error:null})),(async()=>{try{const n=await x(e,t);o||a({data:n,isLoading:!1,error:null})}catch(n){o||a({data:null,isLoading:!1,error:n instanceof Error?n.message:"Failed to analyze audio file"})}})(),()=>{o=!0}},[e,t.timeSlices,t.samplesPerSlice,t.spectrogram,t.fftSize,t.frequencyBins,t.channel]),r}exports.analyzeAudioBuffer=A;exports.analyzeAudioFile=x;exports.useAudioFileAnalysis=P;exports.useAudioPeaks=F;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../src/waveform/useAudioPeaks.ts","../../src/internal/fft.ts","../../src/waveform/analyzeAudioFile.ts","../../src/waveform/useAudioFileAnalysis.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\nexport type UseAudioPeaksState = {\n peaks: number[];\n isLoading: boolean;\n error: string | null;\n};\n\nexport function useAudioPeaks(fileUrl: string | null | undefined, buckets = 64): UseAudioPeaksState {\n const [state, setState] = useState<UseAudioPeaksState>({\n peaks: [],\n isLoading: false,\n error: null,\n });\n\n useEffect(() => {\n if (!fileUrl) {\n setState({ peaks: [], isLoading: false, error: null });\n return;\n }\n let cancelled = false;\n setState((prev) => ({ ...prev, isLoading: true, error: null }));\n void (async () => {\n try {\n const response = await fetch(fileUrl);\n if (!response.ok) throw new Error(`Fetch failed: ${response.status} ${response.statusText}`);\n const buffer = await response.arrayBuffer();\n const audioContext = new AudioContext();\n const audioBuffer = await audioContext.decodeAudioData(buffer);\n const channel = audioBuffer.getChannelData(0);\n const step = Math.max(1, Math.floor(channel.length / buckets));\n const peaks: number[] = [];\n for (let i = 0; i < buckets; i += 1) {\n let max = 0;\n const start = i * step;\n const end = Math.min(channel.length, start + step);\n for (let j = start; j < end; j += 1) {\n max = Math.max(max, Math.abs(channel[j] ?? 0));\n }\n peaks.push(max);\n }\n await audioContext.close();\n if (!cancelled) {\n setState({ peaks, isLoading: false, error: null });\n }\n } catch (error) {\n if (!cancelled) {\n setState({\n peaks: [],\n isLoading: false,\n error: error instanceof Error ? error.message : \"Failed to decode peaks\",\n });\n }\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, [buckets, fileUrl]);\n\n return state;\n}\n","/** In-place radix-2 Cooley–Tukey FFT; `length` must be a power of 2 and >= 2. */\nexport function fftInPlace(re: Float64Array, im: Float64Array): void {\n const n = re.length;\n if (n !== im.length || n < 2 || (n & (n - 1)) !== 0) {\n throw new Error(\"fftInPlace: length must be equal powers of 2 >= 2\");\n }\n\n let j = 0;\n for (let i = 0; i < n - 1; i += 1) {\n if (i < j) {\n const tr = re[i]!;\n const ti = im[i]!;\n re[i] = re[j]!;\n im[i] = im[j]!;\n re[j] = tr;\n im[j] = ti;\n }\n let k = n >> 1;\n while (k <= j) {\n j -= k;\n k >>= 1;\n }\n j += k;\n }\n\n for (let len = 2; len <= n; len <<= 1) {\n const ang = (-2 * Math.PI) / len;\n const wlenR = Math.cos(ang);\n const wlenI = Math.sin(ang);\n for (let i = 0; i < n; i += len) {\n let wr = 1;\n let wi = 0;\n const half = len >> 1;\n for (let k = 0; k < half; k += 1) {\n const u = i + k;\n const v = u + half;\n const tr = wr * re[v]! - wi * im[v]!;\n const ti = wr * im[v]! + wi * re[v]!;\n re[v] = re[u]! - tr;\n im[v] = im[u]! - ti;\n re[u] = re[u]! + tr;\n im[u] = im[u]! + ti;\n const nwr = wr * wlenR - wi * wlenI;\n const nwi = wr * wlenI + wi * wlenR;\n wr = nwr;\n wi = nwi;\n }\n }\n }\n}\n\n/** Magnitude spectrum for real input: length `n` (power of 2). Returns `n/2` magnitudes for bins 0..n/2-1. */\nexport function realFftMagnitudes(samples: Float64Array): Float64Array {\n const n = samples.length;\n if (n < 2 || (n & (n - 1)) !== 0) {\n throw new Error(\"realFftMagnitudes: length must be a power of 2 >= 2\");\n }\n const re = new Float64Array(n);\n const im = new Float64Array(n);\n for (let i = 0; i < n; i += 1) re[i] = samples[i]!;\n fftInPlace(re, im);\n const out = new Float64Array(n >> 1);\n for (let k = 0; k < n >> 1; k += 1) {\n out[k] = Math.hypot(re[k]!, im[k]!);\n }\n return out;\n}\n\nexport function hanningWindow(length: number): Float64Array {\n const w = new Float64Array(length);\n if (length === 1) {\n w[0] = 1;\n return w;\n }\n const denom = length - 1;\n for (let i = 0; i < length; i += 1) {\n w[i] = 0.5 * (1 - Math.cos((2 * Math.PI * i) / denom));\n }\n return w;\n}\n\nexport function clampFftSize(n: number): number {\n const p = 2 ** Math.round(Math.log2(n));\n return Math.min(8192, Math.max(32, p));\n}\n","import { clampFftSize, hanningWindow, realFftMagnitudes } from \"../internal/fft\";\n\nexport type AnalyzeAudioFileOptions = {\n /** Number of time rows in the amplitude grid (and spectrogram if enabled). Default 128. */\n timeSlices?: number;\n /** Sub-buckets per time slice for the amplitude grid. Default 8. */\n samplesPerSlice?: number;\n /** When true, include `spectrogram` using windowed FFT per time slice. Default false. */\n spectrogram?: boolean;\n /** FFT length for spectrogram (power of 2). Default 1024. */\n fftSize?: number;\n /** Number of frequency bins to keep per row (first bins; capped by fftSize/2). Default 256. */\n frequencyBins?: number;\n /** Channel index, or `\"mix\"` for equal mix of all channels. Default 0. */\n channel?: number | \"mix\";\n};\n\nexport type AudioFileAnalysis = {\n duration: number;\n sampleRate: number;\n /** Peak amplitudes in [0, 1]: `timeSlices` rows × `samplesPerSlice` columns. */\n amplitudeGrid: number[][];\n /** Optional magnitude spectrogram rows, each length `frequencyBins`, normalized to [0, 1] globally. */\n spectrogram?: number[][];\n};\n\nfunction mixChannels(buffer: AudioBuffer): Float32Array {\n const { numberOfChannels, length } = buffer;\n if (numberOfChannels === 1) {\n return buffer.getChannelData(0);\n }\n const out = new Float32Array(length);\n const scale = 1 / numberOfChannels;\n for (let c = 0; c < numberOfChannels; c += 1) {\n const ch = buffer.getChannelData(c);\n for (let i = 0; i < length; i += 1) {\n out[i] += ch[i]! * scale;\n }\n }\n return out;\n}\n\nfunction getChannel(buffer: AudioBuffer, channel: number | \"mix\"): Float32Array {\n if (channel === \"mix\") return mixChannels(buffer);\n const idx = Math.max(0, Math.min(buffer.numberOfChannels - 1, channel));\n return buffer.getChannelData(idx);\n}\n\nfunction buildAmplitudeGrid(\n channel: Float32Array,\n timeSlices: number,\n samplesPerSlice: number,\n): number[][] {\n const grid: number[][] = [];\n const len = channel.length;\n if (len === 0) {\n for (let t = 0; t < timeSlices; t += 1) {\n grid.push(Array.from({ length: samplesPerSlice }, () => 0));\n }\n return grid;\n }\n\n const segmentLen = len / timeSlices;\n\n for (let t = 0; t < timeSlices; t += 1) {\n const row: number[] = [];\n const segStart = Math.floor(t * segmentLen);\n const segEnd = Math.floor((t + 1) * segmentLen);\n const segLen = Math.max(1, segEnd - segStart);\n const subLen = segLen / samplesPerSlice;\n\n for (let s = 0; s < samplesPerSlice; s += 1) {\n const a = Math.floor(segStart + s * subLen);\n const b = Math.min(segEnd, Math.floor(segStart + (s + 1) * subLen));\n let peak = 0;\n for (let i = a; i < b; i += 1) {\n peak = Math.max(peak, Math.abs(channel[i] ?? 0));\n }\n row.push(peak);\n }\n grid.push(row);\n }\n return grid;\n}\n\nfunction buildSpectrogram(\n channel: Float32Array,\n timeSlices: number,\n fftSize: number,\n frequencyBins: number,\n): { rows: number[][]; maxMag: number } {\n const rows: number[][] = [];\n let maxMag = 1e-12;\n const len = channel.length;\n const n = clampFftSize(fftSize);\n const half = n >> 1;\n const bins = Math.min(frequencyBins, half);\n const window = hanningWindow(n);\n\n if (len < n) {\n for (let t = 0; t < timeSlices; t += 1) {\n rows.push(Array.from({ length: bins }, () => 0));\n }\n return { rows, maxMag: 1 };\n }\n\n for (let t = 0; t < timeSlices; t += 1) {\n const start =\n timeSlices <= 1\n ? 0\n : Math.min(Math.floor((t * (len - n)) / (timeSlices - 1)), len - n);\n const frame = new Float64Array(n);\n for (let i = 0; i < n; i += 1) {\n frame[i] = (channel[start + i] ?? 0) * (window[i] ?? 0);\n }\n const mags = realFftMagnitudes(frame);\n const row: number[] = [];\n for (let k = 0; k < bins; k += 1) {\n const v = mags[k] ?? 0;\n row.push(v);\n maxMag = Math.max(maxMag, v);\n }\n rows.push(row);\n }\n\n return { rows, maxMag };\n}\n\n/**\n * Decodes an `AudioBuffer` into visualization-friendly grids (no network).\n */\nexport function analyzeAudioBuffer(buffer: AudioBuffer, options: AnalyzeAudioFileOptions = {}): AudioFileAnalysis {\n const timeSlices = Math.max(1, options.timeSlices ?? 128);\n const samplesPerSlice = Math.max(1, options.samplesPerSlice ?? 8);\n const wantSpec = Boolean(options.spectrogram);\n const fftSize = options.fftSize ?? 1024;\n const frequencyBins = Math.max(1, options.frequencyBins ?? 256);\n const channel = options.channel ?? 0;\n\n const data = getChannel(buffer, channel);\n const amplitudeGrid = buildAmplitudeGrid(data, timeSlices, samplesPerSlice);\n\n const result: AudioFileAnalysis = {\n duration: buffer.duration,\n sampleRate: buffer.sampleRate,\n amplitudeGrid,\n };\n\n if (wantSpec) {\n const { rows, maxMag } = buildSpectrogram(data, timeSlices, fftSize, frequencyBins);\n const norm = maxMag > 0 ? 1 / maxMag : 1;\n result.spectrogram = rows.map((row) => row.map((v) => v * norm));\n }\n\n return result;\n}\n\n/**\n * Fetches a URL, decodes audio to an `AudioBuffer`, runs {@link analyzeAudioBuffer}, then closes the temporary `AudioContext`.\n */\nexport async function analyzeAudioFile(\n fileUrl: string,\n options: AnalyzeAudioFileOptions = {},\n): Promise<AudioFileAnalysis> {\n const response = await fetch(fileUrl);\n if (!response.ok) {\n throw new Error(`Fetch failed: ${response.status} ${response.statusText}`);\n }\n const raw = await response.arrayBuffer();\n const Context = window.AudioContext ?? (window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n if (!Context) {\n throw new Error(\"Web Audio API is not available\");\n }\n const audioContext = new Context();\n try {\n const buffer = await audioContext.decodeAudioData(raw.slice(0));\n return analyzeAudioBuffer(buffer, options);\n } finally {\n await audioContext.close();\n }\n}\n","import { useEffect, useState } from \"react\";\nimport { analyzeAudioFile, type AnalyzeAudioFileOptions, type AudioFileAnalysis } from \"./analyzeAudioFile\";\n\nexport type UseAudioFileAnalysisState = {\n data: AudioFileAnalysis | null;\n isLoading: boolean;\n error: string | null;\n};\n\nexport function useAudioFileAnalysis(\n fileUrl: string | null | undefined,\n options: AnalyzeAudioFileOptions = {},\n): UseAudioFileAnalysisState {\n const [state, setState] = useState<UseAudioFileAnalysisState>({\n data: null,\n isLoading: false,\n error: null,\n });\n\n useEffect(() => {\n if (!fileUrl) {\n setState({ data: null, isLoading: false, error: null });\n return;\n }\n if (typeof window === \"undefined\") {\n setState({ data: null, isLoading: false, error: null });\n return;\n }\n\n let cancelled = false;\n setState((prev) => ({ ...prev, isLoading: true, error: null }));\n\n void (async () => {\n try {\n const data = await analyzeAudioFile(fileUrl, options);\n if (!cancelled) {\n setState({ data, isLoading: false, error: null });\n }\n } catch (error) {\n if (!cancelled) {\n setState({\n data: null,\n isLoading: false,\n error: error instanceof Error ? error.message : \"Failed to analyze audio file\",\n });\n }\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, [\n fileUrl,\n options.timeSlices,\n options.samplesPerSlice,\n options.spectrogram,\n options.fftSize,\n options.frequencyBins,\n options.channel,\n ]);\n\n return state;\n}\n"],"names":["useAudioPeaks","fileUrl","buckets","state","setState","useState","useEffect","cancelled","prev","response","buffer","audioContext","channel","step","peaks","i","max","start","end","j","error","fftInPlace","re","im","n","tr","ti","k","len","ang","wlenR","wlenI","wr","wi","half","u","v","nwr","nwi","realFftMagnitudes","samples","out","hanningWindow","length","w","denom","clampFftSize","p","mixChannels","numberOfChannels","scale","c","ch","getChannel","idx","buildAmplitudeGrid","timeSlices","samplesPerSlice","grid","t","segmentLen","row","segStart","segEnd","subLen","s","a","b","peak","buildSpectrogram","fftSize","frequencyBins","rows","maxMag","bins","window","frame","mags","analyzeAudioBuffer","options","wantSpec","data","amplitudeGrid","result","norm","analyzeAudioFile","raw","Context","useAudioFileAnalysis"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../../src/waveform/useAudioPeaks.ts","../../src/internal/fft.ts","../../src/waveform/analyzeAudioFile.ts","../../src/waveform/useAudioFileAnalysis.ts"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\nexport type UseAudioPeaksState = {\n peaks: number[];\n isLoading: boolean;\n error: string | null;\n};\n\nexport function useAudioPeaks(\n fileUrl: string | null | undefined,\n buckets = 64,\n): UseAudioPeaksState {\n const [state, setState] = useState<UseAudioPeaksState>({\n peaks: [],\n isLoading: false,\n error: null,\n });\n\n useEffect(() => {\n if (!fileUrl) {\n setState({ peaks: [], isLoading: false, error: null });\n return;\n }\n let cancelled = false;\n setState((prev) => ({ ...prev, isLoading: true, error: null }));\n void (async () => {\n try {\n const response = await fetch(fileUrl);\n if (!response.ok)\n throw new Error(`Fetch failed: ${response.status} ${response.statusText}`);\n const buffer = await response.arrayBuffer();\n const audioContext = new AudioContext();\n try {\n const audioBuffer = await audioContext.decodeAudioData(buffer);\n const channel = audioBuffer.getChannelData(0);\n const step = Math.max(1, Math.floor(channel.length / buckets));\n const peaks: number[] = [];\n for (let i = 0; i < buckets; i += 1) {\n let max = 0;\n const start = i * step;\n const end = Math.min(channel.length, start + step);\n for (let j = start; j < end; j += 1) {\n max = Math.max(max, Math.abs(channel[j] ?? 0));\n }\n peaks.push(max);\n }\n if (!cancelled) {\n setState({ peaks, isLoading: false, error: null });\n }\n } finally {\n await audioContext.close().catch(() => {});\n }\n } catch (error) {\n if (!cancelled) {\n setState({\n peaks: [],\n isLoading: false,\n error: error instanceof Error ? error.message : \"Failed to decode peaks\",\n });\n }\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, [buckets, fileUrl]);\n\n return state;\n}\n","/** In-place radix-2 Cooley–Tukey FFT; `length` must be a power of 2 and >= 2. */\nexport function fftInPlace(re: Float64Array, im: Float64Array): void {\n const n = re.length;\n if (n !== im.length || n < 2 || (n & (n - 1)) !== 0) {\n throw new Error(\"fftInPlace: length must be equal powers of 2 >= 2\");\n }\n\n let j = 0;\n for (let i = 0; i < n - 1; i += 1) {\n if (i < j) {\n const tr = re[i]!;\n const ti = im[i]!;\n re[i] = re[j]!;\n im[i] = im[j]!;\n re[j] = tr;\n im[j] = ti;\n }\n let k = n >> 1;\n while (k <= j) {\n j -= k;\n k >>= 1;\n }\n j += k;\n }\n\n for (let len = 2; len <= n; len <<= 1) {\n const ang = (-2 * Math.PI) / len;\n const wlenR = Math.cos(ang);\n const wlenI = Math.sin(ang);\n for (let i = 0; i < n; i += len) {\n let wr = 1;\n let wi = 0;\n const half = len >> 1;\n for (let k = 0; k < half; k += 1) {\n const u = i + k;\n const v = u + half;\n const tr = wr * re[v]! - wi * im[v]!;\n const ti = wr * im[v]! + wi * re[v]!;\n re[v] = re[u]! - tr;\n im[v] = im[u]! - ti;\n re[u] = re[u]! + tr;\n im[u] = im[u]! + ti;\n const nwr = wr * wlenR - wi * wlenI;\n const nwi = wr * wlenI + wi * wlenR;\n wr = nwr;\n wi = nwi;\n }\n }\n }\n}\n\n/** Magnitude spectrum for real input: length `n` (power of 2). Returns `n/2` magnitudes for bins 0..n/2-1. */\nexport function realFftMagnitudes(samples: Float64Array): Float64Array {\n const n = samples.length;\n if (n < 2 || (n & (n - 1)) !== 0) {\n throw new Error(\"realFftMagnitudes: length must be a power of 2 >= 2\");\n }\n const re = new Float64Array(n);\n const im = new Float64Array(n);\n for (let i = 0; i < n; i += 1) re[i] = samples[i]!;\n fftInPlace(re, im);\n const out = new Float64Array(n >> 1);\n for (let k = 0; k < n >> 1; k += 1) {\n out[k] = Math.hypot(re[k]!, im[k]!);\n }\n return out;\n}\n\nexport function hanningWindow(length: number): Float64Array {\n const w = new Float64Array(length);\n if (length === 1) {\n w[0] = 1;\n return w;\n }\n const denom = length - 1;\n for (let i = 0; i < length; i += 1) {\n w[i] = 0.5 * (1 - Math.cos((2 * Math.PI * i) / denom));\n }\n return w;\n}\n\nexport function clampFftSize(n: number): number {\n const p = 2 ** Math.round(Math.log2(n));\n return Math.min(8192, Math.max(32, p));\n}\n","import { clampFftSize, hanningWindow, realFftMagnitudes } from \"../internal/fft\";\n\nexport type AnalyzeAudioFileOptions = {\n /** Number of time rows in the amplitude grid (and spectrogram if enabled). Default 128. */\n timeSlices?: number;\n /** Sub-buckets per time slice for the amplitude grid. Default 8. */\n samplesPerSlice?: number;\n /** When true, include `spectrogram` using windowed FFT per time slice. Default false. */\n spectrogram?: boolean;\n /** FFT length for spectrogram (power of 2). Default 1024. */\n fftSize?: number;\n /** Number of frequency bins to keep per row (first bins; capped by fftSize/2). Default 256. */\n frequencyBins?: number;\n /** Channel index, or `\"mix\"` for equal mix of all channels. Default 0. */\n channel?: number | \"mix\";\n};\n\nexport type AudioFileAnalysis = {\n duration: number;\n sampleRate: number;\n /** Peak amplitudes in [0, 1]: `timeSlices` rows × `samplesPerSlice` columns. */\n amplitudeGrid: number[][];\n /** Optional magnitude spectrogram rows, each length `frequencyBins`, normalized to [0, 1] globally. */\n spectrogram?: number[][];\n};\n\nfunction mixChannels(buffer: AudioBuffer): Float32Array {\n const { numberOfChannels, length } = buffer;\n if (numberOfChannels === 1) {\n return buffer.getChannelData(0);\n }\n const out = new Float32Array(length);\n const scale = 1 / numberOfChannels;\n for (let c = 0; c < numberOfChannels; c += 1) {\n const ch = buffer.getChannelData(c);\n for (let i = 0; i < length; i += 1) {\n out[i] += ch[i]! * scale;\n }\n }\n return out;\n}\n\nfunction getChannel(buffer: AudioBuffer, channel: number | \"mix\"): Float32Array {\n if (channel === \"mix\") return mixChannels(buffer);\n const idx = Math.max(0, Math.min(buffer.numberOfChannels - 1, channel));\n return buffer.getChannelData(idx);\n}\n\nfunction buildAmplitudeGrid(\n channel: Float32Array,\n timeSlices: number,\n samplesPerSlice: number,\n): number[][] {\n const grid: number[][] = [];\n const len = channel.length;\n if (len === 0) {\n for (let t = 0; t < timeSlices; t += 1) {\n grid.push(Array.from({ length: samplesPerSlice }, () => 0));\n }\n return grid;\n }\n\n const segmentLen = len / timeSlices;\n\n for (let t = 0; t < timeSlices; t += 1) {\n const row: number[] = [];\n const segStart = Math.floor(t * segmentLen);\n const segEnd = Math.floor((t + 1) * segmentLen);\n const segLen = Math.max(1, segEnd - segStart);\n const subLen = segLen / samplesPerSlice;\n\n for (let s = 0; s < samplesPerSlice; s += 1) {\n const a = Math.floor(segStart + s * subLen);\n const b = Math.min(segEnd, Math.floor(segStart + (s + 1) * subLen));\n let peak = 0;\n for (let i = a; i < b; i += 1) {\n peak = Math.max(peak, Math.abs(channel[i] ?? 0));\n }\n row.push(peak);\n }\n grid.push(row);\n }\n return grid;\n}\n\nfunction buildSpectrogram(\n channel: Float32Array,\n timeSlices: number,\n fftSize: number,\n frequencyBins: number,\n): { rows: number[][]; maxMag: number } {\n const rows: number[][] = [];\n let maxMag = 1e-12;\n const len = channel.length;\n const n = clampFftSize(fftSize);\n const half = n >> 1;\n const bins = Math.min(frequencyBins, half);\n const window = hanningWindow(n);\n\n if (len < n) {\n for (let t = 0; t < timeSlices; t += 1) {\n rows.push(Array.from({ length: bins }, () => 0));\n }\n return { rows, maxMag: 1 };\n }\n\n for (let t = 0; t < timeSlices; t += 1) {\n const start =\n timeSlices <= 1 ? 0 : Math.min(Math.floor((t * (len - n)) / (timeSlices - 1)), len - n);\n const frame = new Float64Array(n);\n for (let i = 0; i < n; i += 1) {\n frame[i] = (channel[start + i] ?? 0) * (window[i] ?? 0);\n }\n const mags = realFftMagnitudes(frame);\n const row: number[] = [];\n for (let k = 0; k < bins; k += 1) {\n const v = mags[k] ?? 0;\n row.push(v);\n maxMag = Math.max(maxMag, v);\n }\n rows.push(row);\n }\n\n return { rows, maxMag };\n}\n\n/**\n * Decodes an `AudioBuffer` into visualization-friendly grids (no network).\n */\nexport function analyzeAudioBuffer(\n buffer: AudioBuffer,\n options: AnalyzeAudioFileOptions = {},\n): AudioFileAnalysis {\n const timeSlices = Math.max(1, options.timeSlices ?? 128);\n const samplesPerSlice = Math.max(1, options.samplesPerSlice ?? 8);\n const wantSpec = Boolean(options.spectrogram);\n const fftSize = options.fftSize ?? 1024;\n const frequencyBins = Math.max(1, options.frequencyBins ?? 256);\n const channel = options.channel ?? 0;\n\n const data = getChannel(buffer, channel);\n const amplitudeGrid = buildAmplitudeGrid(data, timeSlices, samplesPerSlice);\n\n const result: AudioFileAnalysis = {\n duration: buffer.duration,\n sampleRate: buffer.sampleRate,\n amplitudeGrid,\n };\n\n if (wantSpec) {\n const { rows, maxMag } = buildSpectrogram(data, timeSlices, fftSize, frequencyBins);\n const norm = maxMag > 0 ? 1 / maxMag : 1;\n result.spectrogram = rows.map((row) => row.map((v) => v * norm));\n }\n\n return result;\n}\n\n/**\n * Fetches a URL, decodes audio to an `AudioBuffer`, runs {@link analyzeAudioBuffer}, then closes the temporary `AudioContext`.\n */\nexport async function analyzeAudioFile(\n fileUrl: string,\n options: AnalyzeAudioFileOptions = {},\n): Promise<AudioFileAnalysis> {\n const response = await fetch(fileUrl);\n if (!response.ok) {\n throw new Error(`Fetch failed: ${response.status} ${response.statusText}`);\n }\n const raw = await response.arrayBuffer();\n const Context =\n window.AudioContext ??\n (window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext;\n if (!Context) {\n throw new Error(\"Web Audio API is not available\");\n }\n const audioContext = new Context();\n try {\n const buffer = await audioContext.decodeAudioData(raw.slice(0));\n return analyzeAudioBuffer(buffer, options);\n } finally {\n await audioContext.close();\n }\n}\n","import { useEffect, useState } from \"react\";\nimport {\n type AnalyzeAudioFileOptions,\n type AudioFileAnalysis,\n analyzeAudioFile,\n} from \"./analyzeAudioFile\";\n\nexport type UseAudioFileAnalysisState = {\n data: AudioFileAnalysis | null;\n isLoading: boolean;\n error: string | null;\n};\n\nexport function useAudioFileAnalysis(\n fileUrl: string | null | undefined,\n options: AnalyzeAudioFileOptions = {},\n): UseAudioFileAnalysisState {\n const [state, setState] = useState<UseAudioFileAnalysisState>({\n data: null,\n isLoading: false,\n error: null,\n });\n\n useEffect(() => {\n if (!fileUrl) {\n setState({ data: null, isLoading: false, error: null });\n return;\n }\n if (typeof window === \"undefined\") {\n setState({ data: null, isLoading: false, error: null });\n return;\n }\n\n let cancelled = false;\n setState((prev) => ({ ...prev, isLoading: true, error: null }));\n\n void (async () => {\n try {\n const data = await analyzeAudioFile(fileUrl, options);\n if (!cancelled) {\n setState({ data, isLoading: false, error: null });\n }\n } catch (error) {\n if (!cancelled) {\n setState({\n data: null,\n isLoading: false,\n error: error instanceof Error ? error.message : \"Failed to analyze audio file\",\n });\n }\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, [\n fileUrl,\n options.timeSlices,\n options.samplesPerSlice,\n options.spectrogram,\n options.fftSize,\n options.frequencyBins,\n options.channel,\n ]);\n\n return state;\n}\n"],"names":["useAudioPeaks","fileUrl","buckets","state","setState","useState","useEffect","cancelled","prev","response","buffer","audioContext","channel","step","peaks","i","max","start","end","j","error","fftInPlace","re","im","n","tr","ti","k","len","ang","wlenR","wlenI","wr","wi","half","u","v","nwr","nwi","realFftMagnitudes","samples","out","hanningWindow","length","w","denom","clampFftSize","p","mixChannels","numberOfChannels","scale","c","ch","getChannel","idx","buildAmplitudeGrid","timeSlices","samplesPerSlice","grid","t","segmentLen","row","segStart","segEnd","subLen","s","a","b","peak","buildSpectrogram","fftSize","frequencyBins","rows","maxMag","bins","window","frame","mags","analyzeAudioBuffer","options","wantSpec","data","amplitudeGrid","result","norm","analyzeAudioFile","raw","Context","useAudioFileAnalysis"],"mappings":"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"}