@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
@@ -1,31 +1,38 @@
1
- import { useState as x, useEffect as y } from "react";
2
- function D(e, t = 64) {
3
- const [r, a] = x({
1
+ import { useState as y, useEffect as x } from "react";
2
+ function D(a, t = 64) {
3
+ const [r, e] = y({
4
4
  peaks: [],
5
5
  isLoading: !1,
6
6
  error: null
7
7
  });
8
- return y(() => {
9
- if (!e) {
10
- a({ peaks: [], isLoading: !1, error: null });
8
+ return x(() => {
9
+ if (!a) {
10
+ e({ peaks: [], isLoading: !1, error: null });
11
11
  return;
12
12
  }
13
13
  let o = !1;
14
- return a((n) => ({ ...n, isLoading: !0, error: null })), (async () => {
14
+ return e((n) => ({ ...n, isLoading: !0, error: null })), (async () => {
15
15
  try {
16
- const n = await fetch(e);
17
- if (!n.ok) throw new Error(`Fetch failed: ${n.status} ${n.statusText}`);
18
- const l = await n.arrayBuffer(), s = new AudioContext(), f = (await s.decodeAudioData(l)).getChannelData(0), w = Math.max(1, Math.floor(f.length / t)), u = [];
19
- for (let h = 0; h < t; h += 1) {
20
- let i = 0;
21
- const d = h * w, m = Math.min(f.length, d + w);
22
- for (let c = d; c < m; c += 1)
23
- i = Math.max(i, Math.abs(f[c] ?? 0));
24
- u.push(i);
16
+ const n = await fetch(a);
17
+ if (!n.ok)
18
+ throw new Error(`Fetch failed: ${n.status} ${n.statusText}`);
19
+ const l = await n.arrayBuffer(), s = new AudioContext();
20
+ try {
21
+ const f = (await s.decodeAudioData(l)).getChannelData(0), w = Math.max(1, Math.floor(f.length / t)), u = [];
22
+ for (let h = 0; h < t; h += 1) {
23
+ let i = 0;
24
+ const d = h * w, m = Math.min(f.length, d + w);
25
+ for (let c = d; c < m; c += 1)
26
+ i = Math.max(i, Math.abs(f[c] ?? 0));
27
+ u.push(i);
28
+ }
29
+ o || e({ peaks: u, isLoading: !1, error: null });
30
+ } finally {
31
+ await s.close().catch(() => {
32
+ });
25
33
  }
26
- await s.close(), o || a({ peaks: u, isLoading: !1, error: null });
27
34
  } catch (n) {
28
- o || a({
35
+ o || e({
29
36
  peaks: [],
30
37
  isLoading: !1,
31
38
  error: n instanceof Error ? n.message : "Failed to decode peaks"
@@ -34,22 +41,22 @@ function D(e, t = 64) {
34
41
  })(), () => {
35
42
  o = !0;
36
43
  };
37
- }, [t, e]), r;
44
+ }, [t, a]), r;
38
45
  }
39
- function A(e, t) {
40
- const r = e.length;
46
+ function A(a, t) {
47
+ const r = a.length;
41
48
  if (r !== t.length || r < 2 || r & r - 1)
42
49
  throw new Error("fftInPlace: length must be equal powers of 2 >= 2");
43
- let a = 0;
50
+ let e = 0;
44
51
  for (let o = 0; o < r - 1; o += 1) {
45
- if (o < a) {
46
- const l = e[o], s = t[o];
47
- e[o] = e[a], t[o] = t[a], e[a] = l, t[a] = s;
52
+ if (o < e) {
53
+ const l = a[o], s = t[o];
54
+ a[o] = a[e], t[o] = t[e], a[e] = l, t[e] = s;
48
55
  }
49
56
  let n = r >> 1;
50
- for (; n <= a; )
51
- a -= n, n >>= 1;
52
- a += n;
57
+ for (; n <= e; )
58
+ e -= n, n >>= 1;
59
+ e += n;
53
60
  }
54
61
  for (let o = 2; o <= r; o <<= 1) {
55
62
  const n = -2 * Math.PI / o, l = Math.cos(n), s = Math.sin(n);
@@ -57,62 +64,62 @@ function A(e, t) {
57
64
  let f = 1, w = 0;
58
65
  const u = o >> 1;
59
66
  for (let h = 0; h < u; h += 1) {
60
- const i = g + h, d = i + u, m = f * e[d] - w * t[d], c = f * t[d] + w * e[d];
61
- e[d] = e[i] - m, t[d] = t[i] - c, e[i] = e[i] + m, t[i] = t[i] + c;
67
+ const i = g + h, d = i + u, m = f * a[d] - w * t[d], c = f * t[d] + w * a[d];
68
+ a[d] = a[i] - m, t[d] = t[i] - c, a[i] = a[i] + m, t[i] = t[i] + c;
62
69
  const M = f * l - w * s, p = f * s + w * l;
63
70
  f = M, w = p;
64
71
  }
65
72
  }
66
73
  }
67
74
  }
68
- function F(e) {
69
- const t = e.length;
75
+ function F(a) {
76
+ const t = a.length;
70
77
  if (t < 2 || t & t - 1)
71
78
  throw new Error("realFftMagnitudes: length must be a power of 2 >= 2");
72
- const r = new Float64Array(t), a = new Float64Array(t);
73
- for (let n = 0; n < t; n += 1) r[n] = e[n];
74
- A(r, a);
79
+ const r = new Float64Array(t), e = new Float64Array(t);
80
+ for (let n = 0; n < t; n += 1) r[n] = a[n];
81
+ A(r, e);
75
82
  const o = new Float64Array(t >> 1);
76
83
  for (let n = 0; n < t >> 1; n += 1)
77
- o[n] = Math.hypot(r[n], a[n]);
84
+ o[n] = Math.hypot(r[n], e[n]);
78
85
  return o;
79
86
  }
80
- function L(e) {
81
- const t = new Float64Array(e);
82
- if (e === 1)
87
+ function L(a) {
88
+ const t = new Float64Array(a);
89
+ if (a === 1)
83
90
  return t[0] = 1, t;
84
- const r = e - 1;
85
- for (let a = 0; a < e; a += 1)
86
- t[a] = 0.5 * (1 - Math.cos(2 * Math.PI * a / r));
91
+ const r = a - 1;
92
+ for (let e = 0; e < a; e += 1)
93
+ t[e] = 0.5 * (1 - Math.cos(2 * Math.PI * e / r));
87
94
  return t;
88
95
  }
89
- function C(e) {
90
- const t = 2 ** Math.round(Math.log2(e));
96
+ function C(a) {
97
+ const t = 2 ** Math.round(Math.log2(a));
91
98
  return Math.min(8192, Math.max(32, t));
92
99
  }
93
- function k(e) {
94
- const { numberOfChannels: t, length: r } = e;
100
+ function k(a) {
101
+ const { numberOfChannels: t, length: r } = a;
95
102
  if (t === 1)
96
- return e.getChannelData(0);
97
- const a = new Float32Array(r), o = 1 / t;
103
+ return a.getChannelData(0);
104
+ const e = new Float32Array(r), o = 1 / t;
98
105
  for (let n = 0; n < t; n += 1) {
99
- const l = e.getChannelData(n);
106
+ const l = a.getChannelData(n);
100
107
  for (let s = 0; s < r; s += 1)
101
- a[s] += l[s] * o;
108
+ e[s] += l[s] * o;
102
109
  }
103
- return a;
110
+ return e;
104
111
  }
105
- function B(e, t) {
106
- if (t === "mix") return k(e);
107
- const r = Math.max(0, Math.min(e.numberOfChannels - 1, t));
108
- return e.getChannelData(r);
112
+ function B(a, t) {
113
+ if (t === "mix") return k(a);
114
+ const r = Math.max(0, Math.min(a.numberOfChannels - 1, t));
115
+ return a.getChannelData(r);
109
116
  }
110
- function E(e, t, r) {
111
- const a = [], o = e.length;
117
+ function E(a, t, r) {
118
+ const e = [], o = a.length;
112
119
  if (o === 0) {
113
120
  for (let l = 0; l < t; l += 1)
114
- a.push(Array.from({ length: r }, () => 0));
115
- return a;
121
+ e.push(Array.from({ length: r }, () => 0));
122
+ return e;
116
123
  }
117
124
  const n = o / t;
118
125
  for (let l = 0; l < t; l += 1) {
@@ -121,17 +128,17 @@ function E(e, t, r) {
121
128
  const i = Math.floor(g + h * u), d = Math.min(f, Math.floor(g + (h + 1) * u));
122
129
  let m = 0;
123
130
  for (let c = i; c < d; c += 1)
124
- m = Math.max(m, Math.abs(e[c] ?? 0));
131
+ m = Math.max(m, Math.abs(a[c] ?? 0));
125
132
  s.push(m);
126
133
  }
127
- a.push(s);
134
+ e.push(s);
128
135
  }
129
- return a;
136
+ return e;
130
137
  }
131
- function S(e, t, r, a) {
138
+ function S(a, t, r, e) {
132
139
  const o = [];
133
140
  let n = 1e-12;
134
- const l = e.length, s = C(r), g = s >> 1, f = Math.min(a, g), w = L(s);
141
+ const l = a.length, s = C(r), g = s >> 1, f = Math.min(e, g), w = L(s);
135
142
  if (l < s) {
136
143
  for (let u = 0; u < t; u += 1)
137
144
  o.push(Array.from({ length: f }, () => 0));
@@ -140,7 +147,7 @@ function S(e, t, r, a) {
140
147
  for (let u = 0; u < t; u += 1) {
141
148
  const h = t <= 1 ? 0 : Math.min(Math.floor(u * (l - s) / (t - 1)), l - s), i = new Float64Array(s);
142
149
  for (let c = 0; c < s; c += 1)
143
- i[c] = (e[h + c] ?? 0) * (w[c] ?? 0);
150
+ i[c] = (a[h + c] ?? 0) * (w[c] ?? 0);
144
151
  const d = F(i), m = [];
145
152
  for (let c = 0; c < f; c += 1) {
146
153
  const M = d[c] ?? 0;
@@ -150,10 +157,10 @@ function S(e, t, r, a) {
150
157
  }
151
158
  return { rows: o, maxMag: n };
152
159
  }
153
- function b(e, t = {}) {
154
- 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), f = E(g, r, a), w = {
155
- duration: e.duration,
156
- sampleRate: e.sampleRate,
160
+ function b(a, t = {}) {
161
+ const r = Math.max(1, t.timeSlices ?? 128), e = 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(a, s), f = E(g, r, e), w = {
162
+ duration: a.duration,
163
+ sampleRate: a.sampleRate,
157
164
  amplitudeGrid: f
158
165
  };
159
166
  if (o) {
@@ -162,43 +169,43 @@ function b(e, t = {}) {
162
169
  }
163
170
  return w;
164
171
  }
165
- async function z(e, t = {}) {
166
- const r = await fetch(e);
172
+ async function z(a, t = {}) {
173
+ const r = await fetch(a);
167
174
  if (!r.ok)
168
175
  throw new Error(`Fetch failed: ${r.status} ${r.statusText}`);
169
- const a = await r.arrayBuffer(), o = window.AudioContext ?? window.webkitAudioContext;
176
+ const e = await r.arrayBuffer(), o = window.AudioContext ?? window.webkitAudioContext;
170
177
  if (!o)
171
178
  throw new Error("Web Audio API is not available");
172
179
  const n = new o();
173
180
  try {
174
- const l = await n.decodeAudioData(a.slice(0));
181
+ const l = await n.decodeAudioData(e.slice(0));
175
182
  return b(l, t);
176
183
  } finally {
177
184
  await n.close();
178
185
  }
179
186
  }
180
- function I(e, t = {}) {
181
- const [r, a] = x({
187
+ function I(a, t = {}) {
188
+ const [r, e] = y({
182
189
  data: null,
183
190
  isLoading: !1,
184
191
  error: null
185
192
  });
186
- return y(() => {
187
- if (!e) {
188
- a({ data: null, isLoading: !1, error: null });
193
+ return x(() => {
194
+ if (!a) {
195
+ e({ data: null, isLoading: !1, error: null });
189
196
  return;
190
197
  }
191
198
  if (typeof window > "u") {
192
- a({ data: null, isLoading: !1, error: null });
199
+ e({ data: null, isLoading: !1, error: null });
193
200
  return;
194
201
  }
195
202
  let o = !1;
196
- return a((n) => ({ ...n, isLoading: !0, error: null })), (async () => {
203
+ return e((n) => ({ ...n, isLoading: !0, error: null })), (async () => {
197
204
  try {
198
- const n = await z(e, t);
199
- o || a({ data: n, isLoading: !1, error: null });
205
+ const n = await z(a, t);
206
+ o || e({ data: n, isLoading: !1, error: null });
200
207
  } catch (n) {
201
- o || a({
208
+ o || e({
202
209
  data: null,
203
210
  isLoading: !1,
204
211
  error: n instanceof Error ? n.message : "Failed to analyze audio file"
@@ -208,7 +215,7 @@ function I(e, t = {}) {
208
215
  o = !0;
209
216
  };
210
217
  }, [
211
- e,
218
+ a,
212
219
  t.timeSlices,
213
220
  t.samplesPerSlice,
214
221
  t.spectrogram,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","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.js","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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"}
@@ -1 +1 @@
1
- {"version":3,"file":"useAudioFileAnalysis.d.ts","sourceRoot":"","sources":["../../src/waveform/useAudioFileAnalysis.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,KAAK,uBAAuB,EAAE,KAAK,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5G,MAAM,MAAM,yBAAyB,GAAG;IACtC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAAC;AAEF,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAClC,OAAO,GAAE,uBAA4B,GACpC,yBAAyB,CAmD3B"}
1
+ {"version":3,"file":"useAudioFileAnalysis.d.ts","sourceRoot":"","sources":["../../src/waveform/useAudioFileAnalysis.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,iBAAiB,EAEvB,MAAM,oBAAoB,CAAC;AAE5B,MAAM,MAAM,yBAAyB,GAAG;IACtC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC/B,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAAC;AAEF,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAClC,OAAO,GAAE,uBAA4B,GACpC,yBAAyB,CAmD3B"}
@@ -1 +1 @@
1
- {"version":3,"file":"useAudioPeaks.d.ts","sourceRoot":"","sources":["../../src/waveform/useAudioPeaks.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAAC;AAEF,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,OAAO,SAAK,GAAG,kBAAkB,CAsDlG"}
1
+ {"version":3,"file":"useAudioPeaks.d.ts","sourceRoot":"","sources":["../../src/waveform/useAudioPeaks.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,CAAC;AAEF,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAClC,OAAO,SAAK,GACX,kBAAkB,CA0DpB"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lucaismyname/ginger",
3
- "version": "0.0.25",
4
- "description": "A headless React audio player",
3
+ "version": "0.0.28",
4
+ "description": "A Headless & batteries-included React audio-player primitive",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "files": [
@@ -45,9 +45,9 @@
45
45
  "test:watch": "vitest",
46
46
  "test:coverage": "vitest run --coverage",
47
47
  "typecheck": "tsc --noEmit -p tsconfig.json",
48
- "lint": "biome check src/testing src/components/controls src/index.ts src/client.ts src/experimental-gapless",
49
- "lint:fix": "biome check --write src/testing src/components/controls src/index.ts src/client.ts src/experimental-gapless",
50
- "format": "biome format --write src/testing src/components/controls src/index.ts src/client.ts src/experimental-gapless",
48
+ "lint": "biome check src",
49
+ "lint:fix": "biome check --write src",
50
+ "format": "biome format --write src",
51
51
  "docs:api": "typedoc --options typedoc.json",
52
52
  "prepublishOnly": "npm run build"
53
53
  },