wavegram 0.1.0 → 0.1.2
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.
- package/README.md +37 -11
- package/dist/assets/{spectrogram.worker-Burn7NUr.js → spectrogram.worker-CJxyA_5B.js} +1 -1
- package/dist/audio/decodeAudio.d.ts +1 -1
- package/dist/audio/decodeAudio.d.ts.map +1 -1
- package/dist/audio/readAudioSampleRate.d.ts +2 -0
- package/dist/audio/readAudioSampleRate.d.ts.map +1 -0
- package/dist/component/Wavegram.d.ts +3 -0
- package/dist/component/Wavegram.d.ts.map +1 -1
- package/dist/index.es.js +306 -206
- package/dist/index.umd.js +2 -2
- package/dist/render/drawCursor.d.ts.map +1 -1
- package/dist/render/drawWaveform.d.ts.map +1 -1
- package/dist/types.d.ts +1 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,18 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
Lightweight Web Component for previewing audio with a synchronized waveform, spectrogram, and playback cursor. It is intended for research demos, paper companion pages, audio dataset previews, and source-separation result comparisons.
|
|
4
4
|
|
|
5
|
+
Wavegram aims to provide a minimal, academic, and scientific visualization surface rather than a general-purpose media player or audio editor.
|
|
6
|
+
|
|
5
7
|
It is not an editor. It does not implement recording, effects, multitrack editing, annotation editing, ASR, or server-side processing.
|
|
6
8
|
|
|
7
9
|
## Design Focus
|
|
8
10
|
|
|
9
|
-
Wavegram is closest in spirit to lightweight waveform players
|
|
11
|
+
Wavegram is closest in spirit to lightweight waveform players, but its primary view is not just a waveform. It always treats waveform and spectrogram as two synchronized views over the same audio timeline.
|
|
10
12
|
|
|
11
13
|
The core feature set is deliberately narrow:
|
|
12
14
|
|
|
13
15
|
- Simultaneous waveform and spectrogram display.
|
|
14
16
|
- One playback cursor rendered at the same time position in both views.
|
|
15
17
|
- Click-to-seek from either waveform or spectrogram. By default, clicking a stopped player starts playback from that position, and clicking a playing player pauses after seeking.
|
|
16
|
-
-
|
|
18
|
+
- Minimal, low-decoration presentation suitable for academic papers, scientific demos, and dataset browsers.
|
|
17
19
|
- No DAW-style editing, multitrack arrangement, effects, recording, or annotation workflow.
|
|
18
20
|
|
|
19
21
|
## Install
|
|
@@ -34,6 +36,8 @@ import "wavegram";
|
|
|
34
36
|
></wavegram-player>
|
|
35
37
|
```
|
|
36
38
|
|
|
39
|
+

|
|
40
|
+
|
|
37
41
|
The package is named `wavegram`. The custom element tag is `wavegram-player` because browser custom element names must contain a hyphen.
|
|
38
42
|
|
|
39
43
|
The `src` value may be a relative URL such as `audio/example.wav` or an absolute URI such as the example above.
|
|
@@ -144,6 +148,12 @@ The older `<audio-preview-spectrogram>` tag is still registered as a compatibili
|
|
|
144
148
|
|
|
145
149
|
The examples use WAV files from [`pdx-cs-sound/wavs`](https://github.com/pdx-cs-sound/wavs), a sample collection for Portland State University's Computers, Sound and Music course. The repository states that the files are Creative Commons CC0 unless otherwise indicated.
|
|
146
150
|
|
|
151
|
+
The 16 kHz keyword-spotting example uses a WAV file from [`fkuhne/KWS-Dataset`](https://github.com/fkuhne/KWS-Dataset). Its `wavs` directory is described by that project as WAV audio converted to 16 kHz and is distributed under CC0-1.0.
|
|
152
|
+
|
|
153
|
+
## Acknowledgements
|
|
154
|
+
|
|
155
|
+
Wavegram is inspired by [`wavesurfer.js`](https://wavesurfer.xyz/), especially its lightweight browser-based waveform player model. Wavegram is an independent implementation focused on synchronized waveform and spectrogram previews for research demos and dataset browsing.
|
|
156
|
+
|
|
147
157
|
## Styling
|
|
148
158
|
|
|
149
159
|
The component uses Shadow DOM and supports CSS custom properties:
|
|
@@ -182,16 +192,32 @@ npm run test:e2e
|
|
|
182
192
|
|
|
183
193
|
## Examples
|
|
184
194
|
|
|
185
|
-
Run
|
|
195
|
+
Run the local dev server:
|
|
196
|
+
|
|
197
|
+
```sh
|
|
198
|
+
npm run dev -- --port 4173
|
|
199
|
+
```
|
|
186
200
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
- `examples/
|
|
190
|
-
- `examples/
|
|
191
|
-
- `examples/
|
|
192
|
-
- `examples/
|
|
193
|
-
- `examples/
|
|
194
|
-
- `examples/
|
|
201
|
+
Then open:
|
|
202
|
+
|
|
203
|
+
- `http://127.0.0.1:4173/examples/basic.html`
|
|
204
|
+
- `http://127.0.0.1:4173/examples/multiple.html`
|
|
205
|
+
- `http://127.0.0.1:4173/examples/large-file.html`
|
|
206
|
+
- `http://127.0.0.1:4173/examples/profile.html`
|
|
207
|
+
- `http://127.0.0.1:4173/examples/multichannel.html`
|
|
208
|
+
- `http://127.0.0.1:4173/examples/kws-16khz.html`
|
|
209
|
+
- `http://127.0.0.1:4173/examples/waveform-only.html`
|
|
210
|
+
- `http://127.0.0.1:4173/examples/spectrogram-only.html`
|
|
211
|
+
- `http://127.0.0.1:4173/examples/styles.html`
|
|
212
|
+
|
|
213
|
+
For automated local checks, run:
|
|
214
|
+
|
|
215
|
+
```sh
|
|
216
|
+
npm run test
|
|
217
|
+
npm run typecheck
|
|
218
|
+
npm run build
|
|
219
|
+
npm run test:e2e
|
|
220
|
+
```
|
|
195
221
|
|
|
196
222
|
## License
|
|
197
223
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(){"use strict";function g(t,o,n){return Math.min(n,Math.max(o,t))}const b=1e-10;function M(t){return Number.isInteger(t)&&t>0&&(t&t-1)===0}function x(t,o){const n=new Float32Array(t);if(t===1)return n[0]=1,n;for(let e=0;e<t;e+=1)o==="hann"?n[e]=.5-.5*Math.cos(2*Math.PI*e/(t-1)):o==="hamming"?n[e]=.54-.46*Math.cos(2*Math.PI*e/(t-1)):n[e]=1;return n}function S(t){let o=0;for(const n of t)o+=n;return o/t.length}function
|
|
1
|
+
(function(){"use strict";function g(t,o,n){return Math.min(n,Math.max(o,t))}const b=1e-10;function M(t){return Number.isInteger(t)&&t>0&&(t&t-1)===0}function x(t,o){const n=new Float32Array(t);if(t===1)return n[0]=1,n;for(let e=0;e<t;e+=1)o==="hann"?n[e]=.5-.5*Math.cos(2*Math.PI*e/(t-1)):o==="hamming"?n[e]=.54-.46*Math.cos(2*Math.PI*e/(t-1)):n[e]=1;return n}function S(t){let o=0;for(const n of t)o+=n;return o/t.length}function y(t){return 20*Math.log10(Math.abs(t)+b)}function D(t,o){const n=t.length;if(!M(n)||o.length!==n)throw new Error("FFT input length must be a radix-2 size.");for(let e=1,a=0;e<n;e+=1){let f=n>>1;for(;a&f;f>>=1)a^=f;if(a^=f,e<a){const h=t[e];t[e]=t[a],t[a]=h;const r=o[e];o[e]=o[a],o[a]=r}}for(let e=2;e<=n;e<<=1){const a=-2*Math.PI/e,f=Math.cos(a),h=Math.sin(a);for(let r=0;r<n;r+=e){let c=1,l=0;for(let s=0;s<e/2;s+=1){const d=t[r+s],p=o[r+s],m=t[r+s+e/2]*c-o[r+s+e/2]*l,u=t[r+s+e/2]*l+o[r+s+e/2]*c;t[r+s]=d+m,o[r+s]=p+u,t[r+s+e/2]=d-m,o[r+s+e/2]=p-u;const w=c*f-l*h;l=c*h+l*f,c=w}}}}function F(t,o,n){const{fftSize:e,hopSize:a,windowType:f,minDb:h,maxDb:r}=n;if(!M(e))throw new Error(`fftSize must be a power of two. Received ${e}.`);if(!Number.isInteger(a)||a<=0)throw new Error(`hopSize must be a positive integer. Received ${a}.`);if(r<=h)throw new Error("maxDb must be greater than minDb.");const c=e/2+1,l=Math.max(1,Math.floor(Math.max(0,t.length-e)/a)+1),s=new Float32Array(l*c),d=x(e,f),p=Math.max(b,e*S(d)/2),m=new Float32Array(e),u=new Float32Array(e);for(let w=0;w<l;w+=1){const I=w*a;m.fill(0),u.fill(0);for(let i=0;i<e;i+=1)m[i]=(t[I+i]??0)*d[i];D(m,u);for(let i=0;i<c;i+=1){const R=Math.hypot(m[i],u[i])/p;s[w*c+i]=g(y(R),h,r)}}return{values:s,freqBins:c,timeFrames:l,sampleRate:o,maxFrequencyHz:o/2,fftSize:e,hopSize:a,minDb:h,maxDb:r}}self.addEventListener("message",t=>{try{const o=F(t.data.samples,t.data.sampleRate,{fftSize:t.data.fftSize,hopSize:t.data.hopSize,windowType:t.data.windowType,minDb:t.data.minDb,maxDb:t.data.maxDb});self.postMessage(o,[o.values.buffer])}catch(o){self.postMessage({error:{message:o instanceof Error?o.message:"Failed to compute spectrogram."}})}})})();
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare function decodeAudioData(arrayBuffer: ArrayBuffer): Promise<AudioBuffer>;
|
|
1
|
+
export declare function decodeAudioData(arrayBuffer: ArrayBuffer, sampleRate?: number): Promise<AudioBuffer>;
|
|
2
2
|
//# sourceMappingURL=decodeAudio.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decodeAudio.d.ts","sourceRoot":"","sources":["../../src/audio/decodeAudio.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"decodeAudio.d.ts","sourceRoot":"","sources":["../../src/audio/decodeAudio.ts"],"names":[],"mappings":"AAYA,wBAAsB,eAAe,CAAC,WAAW,EAAE,WAAW,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAGzG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readAudioSampleRate.d.ts","sourceRoot":"","sources":["../../src/audio/readAudioSampleRate.ts"],"names":[],"mappings":"AAAA,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAGpF"}
|
|
@@ -3,12 +3,14 @@ export declare class Wavegram extends HTMLElement {
|
|
|
3
3
|
static observedAttributes: string[];
|
|
4
4
|
private audio?;
|
|
5
5
|
private audioBuffer?;
|
|
6
|
+
private sourceSampleRate?;
|
|
6
7
|
private waveformPeaks?;
|
|
7
8
|
private spectrogram?;
|
|
8
9
|
private worker?;
|
|
9
10
|
private resizeObserver?;
|
|
10
11
|
private animationFrame;
|
|
11
12
|
private loadingToken;
|
|
13
|
+
private waveformPeaksWidth;
|
|
12
14
|
private blobUrl?;
|
|
13
15
|
private playRequestedAt?;
|
|
14
16
|
private readonly root;
|
|
@@ -73,6 +75,7 @@ export declare class Wavegram extends HTMLElement {
|
|
|
73
75
|
private computeSpectrogramForCurrentBuffer;
|
|
74
76
|
private computeSpectrogramInWorker;
|
|
75
77
|
private bindAudio;
|
|
78
|
+
private handleResize;
|
|
76
79
|
private layoutAndRender;
|
|
77
80
|
private drawCursors;
|
|
78
81
|
private clearCursor;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Wavegram.d.ts","sourceRoot":"","sources":["../../src/component/Wavegram.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Wavegram.d.ts","sourceRoot":"","sources":["../../src/component/Wavegram.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EAQZ,aAAa,EACb,UAAU,EACX,MAAM,UAAU,CAAC;AAqMlB,qBAAa,QAAS,SAAQ,WAAW;IACvC,MAAM,CAAC,kBAAkB,WAoBvB;IAEF,OAAO,CAAC,KAAK,CAAC,CAAmB;IACjC,OAAO,CAAC,WAAW,CAAC,CAAc;IAClC,OAAO,CAAC,gBAAgB,CAAC,CAAS;IAClC,OAAO,CAAC,aAAa,CAAC,CAAgB;IACtC,OAAO,CAAC,WAAW,CAAC,CAAkB;IACtC,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,cAAc,CAAC,CAAiB;IACxC,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,kBAAkB,CAAK;IAC/B,OAAO,CAAC,OAAO,CAAC,CAAS;IACzB,OAAO,CAAC,eAAe,CAAC,CAAS;IAEjC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAC3C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IACtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAc;IACxC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAc;IACzC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAc;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IACtC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAc;IAC3C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAc;IAC9C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAoB;IACnD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAoB;IACtD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAoB;IACvD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAoB;IACnD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAoB;;IAwBtD,IAAI,GAAG,IAAI,MAAM,CAEhB;IAED,IAAI,GAAG,CAAC,KAAK,EAAE,MAAM,EAEpB;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,MAAM,CAAC,KAAK,EAAE,MAAM,EAEvB;IAED,IAAI,cAAc,IAAI,MAAM,CAE3B;IAED,IAAI,cAAc,CAAC,KAAK,EAAE,MAAM,EAE/B;IAED,IAAI,iBAAiB,IAAI,MAAM,CAE9B;IAED,IAAI,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAElC;IAED,IAAI,YAAY,IAAI,OAAO,CAE1B;IAED,IAAI,YAAY,CAAC,KAAK,EAAE,OAAO,EAE9B;IAED,IAAI,eAAe,IAAI,OAAO,CAE7B;IAED,IAAI,eAAe,CAAC,KAAK,EAAE,OAAO,EAEjC;IAED,IAAI,YAAY,IAAI,OAAO,CAE1B;IAED,IAAI,YAAY,CAAC,KAAK,EAAE,OAAO,EAE9B;IAED,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,IAAI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAE1B;IAED,IAAI,aAAa,IAAI,aAAa,CAMjC;IAED,IAAI,aAAa,CAAC,KAAK,EAAE,aAAa,EAErC;IAED,IAAI,gBAAgB,IAAI,MAAM,GAAG,SAAS,CAEzC;IAED,IAAI,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAEjC;IAED,IAAI,kBAAkB,IAAI,MAAM,GAAG,SAAS,CAE3C;IAED,IAAI,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAEnC;IAED,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED,IAAI,QAAQ,CAAC,KAAK,EAAE,OAAO,EAE1B;IAED,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,IAAI,OAAO,CAAC,KAAK,EAAE,MAAM,EAExB;IAED,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,IAAI,OAAO,CAAC,KAAK,EAAE,MAAM,EAExB;IAED,IAAI,UAAU,IAAI,UAAU,CAG3B;IAED,IAAI,UAAU,CAAC,KAAK,EAAE,UAAU,EAE/B;IAED,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAEtB;IAED,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,IAAI,KAAK,CAAC,KAAK,EAAE,MAAM,EAEtB;IAED,IAAI,QAAQ,IAAI,YAAY,CAI3B;IAED,IAAI,QAAQ,CAAC,KAAK,EAAE,YAAY,EAE/B;IAED,IAAI,OAAO,IAAI,gBAAgB,CAK9B;IAED,IAAI,OAAO,CAAC,KAAK,EAAE,gBAAgB,EAElC;IAED,iBAAiB,IAAI,IAAI;IAgBzB,oBAAoB,IAAI,IAAI;IAY5B,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;YAehF,IAAI;YA2EJ,iBAAiB;YAoBjB,kCAAkC;IA2ChD,OAAO,CAAC,0BAA0B;IAoClC,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,eAAe;IAuCvB,OAAO,CAAC,WAAW;IAyBnB,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,sBAAsB;IAgB9B,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAQ/B;IAEF,OAAO,CAAC,QAAQ,CAAC,eAAe,CAe9B;IAEF,OAAO,CAAC,QAAQ,CAAC,aAAa,CAI5B;IAEF,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAG/B;IAEF,OAAO,CAAC,QAAQ,CAAC,eAAe,CAK9B;IAEF,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CASjC;IAEF,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAO/B;IAEF,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,gBAAgB,CAGtB;IAEF,OAAO,KAAK,QAAQ,GAEnB;IAED,OAAO,KAAK,gBAAgB,GAI3B;IAED,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,WAAW;IAYnB,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,cAAc;IAItB,OAAO,CAAC,cAAc;IAwCtB,OAAO,CAAC,kBAAkB;IAK1B,OAAO,CAAC,0BAA0B;IAMlC,OAAO,CAAC,mBAAmB;IAM3B,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,MAAM;IAId,OAAO,CAAC,YAAY;IAKpB,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,iBAAiB;IAwBzB,OAAO,CAAC,aAAa;CAMtB"}
|
package/dist/index.es.js
CHANGED
|
@@ -1,115 +1,196 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var c = (e,
|
|
4
|
-
let
|
|
5
|
-
function
|
|
6
|
-
return
|
|
1
|
+
var q = Object.defineProperty;
|
|
2
|
+
var I = (e, o, t) => o in e ? q(e, o, { enumerable: !0, configurable: !0, writable: !0, value: t }) : e[o] = t;
|
|
3
|
+
var c = (e, o, t) => I(e, typeof o != "symbol" ? o + "" : o, t);
|
|
4
|
+
let v, P;
|
|
5
|
+
function V(e) {
|
|
6
|
+
return (!v || P !== e) && (v == null || v.close(), v = new AudioContext(e ? { sampleRate: e } : void 0), P = e), v;
|
|
7
7
|
}
|
|
8
|
-
async function
|
|
9
|
-
return
|
|
8
|
+
async function $(e, o) {
|
|
9
|
+
return V(o).decodeAudioData(e.slice(0));
|
|
10
10
|
}
|
|
11
|
-
async function
|
|
12
|
-
const
|
|
13
|
-
if (!
|
|
14
|
-
throw new Error(`Failed to load audio: ${
|
|
15
|
-
return
|
|
11
|
+
async function j(e) {
|
|
12
|
+
const o = await fetch(e);
|
|
13
|
+
if (!o.ok)
|
|
14
|
+
throw new Error(`Failed to load audio: ${o.status} ${o.statusText}`);
|
|
15
|
+
return o.arrayBuffer();
|
|
16
16
|
}
|
|
17
|
-
function
|
|
17
|
+
function Y(e, o) {
|
|
18
18
|
const t = new Audio(e);
|
|
19
|
-
return t.preload = "auto", t.autoplay =
|
|
19
|
+
return t.preload = "auto", t.autoplay = o, t.crossOrigin = "anonymous", t;
|
|
20
20
|
}
|
|
21
|
-
function
|
|
22
|
-
|
|
21
|
+
function X(e) {
|
|
22
|
+
const o = new DataView(e);
|
|
23
|
+
return K(o) ?? G(o) ?? J(o) ?? _(o);
|
|
23
24
|
}
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
function K(e) {
|
|
26
|
+
if (e.byteLength < 28 || !A(e, 0, "RIFF") && !A(e, 0, "RF64") || !A(e, 8, "WAVE")) return;
|
|
27
|
+
let o = 12;
|
|
28
|
+
for (; o + 8 <= e.byteLength; ) {
|
|
29
|
+
const t = U(e, o, 4), r = e.getUint32(o + 4, !0), i = o + 8;
|
|
30
|
+
if (i + r > e.byteLength) return;
|
|
31
|
+
if (t === "fmt ") {
|
|
32
|
+
if (r < 8) return;
|
|
33
|
+
const s = e.getUint32(i + 4, !0);
|
|
34
|
+
return Number.isFinite(s) && s > 0 ? s : void 0;
|
|
35
|
+
}
|
|
36
|
+
o = i + r + r % 2;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function G(e) {
|
|
40
|
+
if (!A(e, 0, "fLaC")) return;
|
|
41
|
+
let o = 4;
|
|
42
|
+
for (; o + 4 <= e.byteLength; ) {
|
|
43
|
+
const r = e.getUint8(o) & 127, i = e.getUint8(o + 1) << 16 | e.getUint8(o + 2) << 8 | e.getUint8(o + 3), s = o + 4;
|
|
44
|
+
if (s + i > e.byteLength) return;
|
|
45
|
+
if (r === 0) {
|
|
46
|
+
if (i < 13) return;
|
|
47
|
+
const a = e.getUint8(s + 10) << 12 | e.getUint8(s + 11) << 4 | e.getUint8(s + 12) >> 4;
|
|
48
|
+
return a > 0 ? a : void 0;
|
|
49
|
+
}
|
|
50
|
+
o = s + i;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function J(e) {
|
|
54
|
+
const o = R(e, [1, 118, 111, 114, 98, 105, 115]);
|
|
55
|
+
if (o !== -1 && o + 16 <= e.byteLength) {
|
|
56
|
+
const r = e.getUint32(o + 12, !0);
|
|
57
|
+
return r > 0 ? r : void 0;
|
|
58
|
+
}
|
|
59
|
+
const t = R(e, [79, 112, 117, 115, 72, 101, 97, 100]);
|
|
60
|
+
if (t !== -1 && t + 16 <= e.byteLength) {
|
|
61
|
+
const r = e.getUint32(t + 12, !0);
|
|
62
|
+
return r > 0 ? r : 48e3;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
function _(e) {
|
|
66
|
+
let o = 0;
|
|
67
|
+
A(e, 0, "ID3") && e.byteLength >= 10 && (o = 10 + Q(e, 6));
|
|
68
|
+
const t = [44100, 48e3, 32e3], r = [22050, 24e3, 16e3], i = [11025, 12e3, 8e3];
|
|
69
|
+
for (; o + 4 <= e.byteLength; o += 1) {
|
|
70
|
+
const s = e.getUint8(o), a = e.getUint8(o + 1);
|
|
71
|
+
if (s !== 255 || (a & 224) !== 224) continue;
|
|
72
|
+
const n = a >> 3 & 3, h = a >> 1 & 3, l = e.getUint8(o + 2) >> 2 & 3;
|
|
73
|
+
if (n === 1 || h === 0 || l === 3) continue;
|
|
74
|
+
return (n === 3 ? t : n === 2 ? r : i)[l];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function R(e, o) {
|
|
78
|
+
const t = e.byteLength - o.length;
|
|
79
|
+
for (let r = 0; r <= t; r += 1) {
|
|
80
|
+
let i = !0;
|
|
81
|
+
for (let s = 0; s < o.length; s += 1)
|
|
82
|
+
if (e.getUint8(r + s) !== o[s]) {
|
|
83
|
+
i = !1;
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
if (i) return r;
|
|
87
|
+
}
|
|
88
|
+
return -1;
|
|
89
|
+
}
|
|
90
|
+
function Q(e, o) {
|
|
91
|
+
return e.getUint8(o) << 21 | e.getUint8(o + 1) << 14 | e.getUint8(o + 2) << 7 | e.getUint8(o + 3);
|
|
92
|
+
}
|
|
93
|
+
function A(e, o, t) {
|
|
94
|
+
return o + t.length > e.byteLength ? !1 : U(e, o, t.length) === t;
|
|
95
|
+
}
|
|
96
|
+
function U(e, o, t) {
|
|
97
|
+
let r = "";
|
|
98
|
+
for (let i = 0; i < t; i += 1)
|
|
99
|
+
r += String.fromCharCode(e.getUint8(o + i));
|
|
100
|
+
return r;
|
|
101
|
+
}
|
|
102
|
+
function M(e, o, t) {
|
|
103
|
+
return Math.min(t, Math.max(o, e));
|
|
104
|
+
}
|
|
105
|
+
const D = 1e-10;
|
|
106
|
+
function z(e) {
|
|
26
107
|
return Number.isInteger(e) && e > 0 && (e & e - 1) === 0;
|
|
27
108
|
}
|
|
28
|
-
function
|
|
109
|
+
function Z(e, o) {
|
|
29
110
|
const t = new Float32Array(e);
|
|
30
111
|
if (e === 1)
|
|
31
112
|
return t[0] = 1, t;
|
|
32
113
|
for (let r = 0; r < e; r += 1)
|
|
33
|
-
|
|
114
|
+
o === "hann" ? t[r] = 0.5 - 0.5 * Math.cos(2 * Math.PI * r / (e - 1)) : o === "hamming" ? t[r] = 0.54 - 0.46 * Math.cos(2 * Math.PI * r / (e - 1)) : t[r] = 1;
|
|
34
115
|
return t;
|
|
35
116
|
}
|
|
36
|
-
function
|
|
37
|
-
let
|
|
117
|
+
function tt(e) {
|
|
118
|
+
let o = 0;
|
|
38
119
|
for (const t of e)
|
|
39
|
-
|
|
40
|
-
return
|
|
120
|
+
o += t;
|
|
121
|
+
return o / e.length;
|
|
41
122
|
}
|
|
42
|
-
function
|
|
43
|
-
return 20 * Math.log10(Math.abs(e) +
|
|
123
|
+
function et(e) {
|
|
124
|
+
return 20 * Math.log10(Math.abs(e) + D);
|
|
44
125
|
}
|
|
45
|
-
function
|
|
126
|
+
function rt(e, o) {
|
|
46
127
|
const t = e.length;
|
|
47
|
-
if (!
|
|
128
|
+
if (!z(t) || o.length !== t)
|
|
48
129
|
throw new Error("FFT input length must be a radix-2 size.");
|
|
49
130
|
for (let r = 1, i = 0; r < t; r += 1) {
|
|
50
|
-
let
|
|
51
|
-
for (; i &
|
|
52
|
-
i ^=
|
|
53
|
-
if (i ^=
|
|
131
|
+
let s = t >> 1;
|
|
132
|
+
for (; i & s; s >>= 1)
|
|
133
|
+
i ^= s;
|
|
134
|
+
if (i ^= s, r < i) {
|
|
54
135
|
const a = e[r];
|
|
55
136
|
e[r] = e[i], e[i] = a;
|
|
56
|
-
const n =
|
|
57
|
-
|
|
137
|
+
const n = o[r];
|
|
138
|
+
o[r] = o[i], o[i] = n;
|
|
58
139
|
}
|
|
59
140
|
}
|
|
60
141
|
for (let r = 2; r <= t; r <<= 1) {
|
|
61
|
-
const i = -2 * Math.PI / r,
|
|
142
|
+
const i = -2 * Math.PI / r, s = Math.cos(i), a = Math.sin(i);
|
|
62
143
|
for (let n = 0; n < t; n += r) {
|
|
63
144
|
let h = 1, l = 0;
|
|
64
145
|
for (let u = 0; u < r / 2; u += 1) {
|
|
65
|
-
const d = e[n + u], m =
|
|
66
|
-
e[n + u] = d +
|
|
67
|
-
const b = h *
|
|
68
|
-
l = h * a + l *
|
|
146
|
+
const d = e[n + u], m = o[n + u], g = e[n + u + r / 2] * h - o[n + u + r / 2] * l, p = e[n + u + r / 2] * l + o[n + u + r / 2] * h;
|
|
147
|
+
e[n + u] = d + g, o[n + u] = m + p, e[n + u + r / 2] = d - g, o[n + u + r / 2] = m - p;
|
|
148
|
+
const b = h * s - l * a;
|
|
149
|
+
l = h * a + l * s, h = b;
|
|
69
150
|
}
|
|
70
151
|
}
|
|
71
152
|
}
|
|
72
153
|
}
|
|
73
|
-
function
|
|
74
|
-
const { fftSize: r, hopSize: i, windowType:
|
|
75
|
-
if (!
|
|
154
|
+
function ot(e, o, t) {
|
|
155
|
+
const { fftSize: r, hopSize: i, windowType: s, minDb: a, maxDb: n } = t;
|
|
156
|
+
if (!z(r))
|
|
76
157
|
throw new Error(`fftSize must be a power of two. Received ${r}.`);
|
|
77
158
|
if (!Number.isInteger(i) || i <= 0)
|
|
78
159
|
throw new Error(`hopSize must be a positive integer. Received ${i}.`);
|
|
79
160
|
if (n <= a)
|
|
80
161
|
throw new Error("maxDb must be greater than minDb.");
|
|
81
|
-
const h = r / 2 + 1, l = Math.max(1, Math.floor(Math.max(0, e.length - r) / i) + 1), u = new Float32Array(l * h), d =
|
|
162
|
+
const h = r / 2 + 1, l = Math.max(1, Math.floor(Math.max(0, e.length - r) / i) + 1), u = new Float32Array(l * h), d = Z(r, s), m = Math.max(D, r * tt(d) / 2), g = new Float32Array(r), p = new Float32Array(r);
|
|
82
163
|
for (let b = 0; b < l; b += 1) {
|
|
83
164
|
const w = b * i;
|
|
84
|
-
|
|
165
|
+
g.fill(0), p.fill(0);
|
|
85
166
|
for (let f = 0; f < r; f += 1)
|
|
86
|
-
|
|
87
|
-
|
|
167
|
+
g[f] = (e[w + f] ?? 0) * d[f];
|
|
168
|
+
rt(g, p);
|
|
88
169
|
for (let f = 0; f < h; f += 1) {
|
|
89
|
-
const
|
|
90
|
-
u[b * h + f] =
|
|
170
|
+
const x = Math.hypot(g[f], p[f]) / m;
|
|
171
|
+
u[b * h + f] = M(et(x), a, n);
|
|
91
172
|
}
|
|
92
173
|
}
|
|
93
|
-
return { values: u, freqBins: h, timeFrames: l, sampleRate:
|
|
174
|
+
return { values: u, freqBins: h, timeFrames: l, sampleRate: o, maxFrequencyHz: o / 2, fftSize: r, hopSize: i, minDb: a, maxDb: n };
|
|
94
175
|
}
|
|
95
|
-
function
|
|
96
|
-
if (
|
|
176
|
+
function N(e, o) {
|
|
177
|
+
if (o === "mix") {
|
|
97
178
|
const t = new Float32Array(e.length);
|
|
98
179
|
for (let r = 0; r < e.numberOfChannels; r += 1) {
|
|
99
180
|
const i = e.getChannelData(r);
|
|
100
|
-
for (let
|
|
101
|
-
t[
|
|
181
|
+
for (let s = 0; s < t.length; s += 1)
|
|
182
|
+
t[s] += i[s] / e.numberOfChannels;
|
|
102
183
|
}
|
|
103
184
|
return t;
|
|
104
185
|
}
|
|
105
|
-
if (!Number.isInteger(
|
|
106
|
-
throw new Error(`Invalid channel ${
|
|
107
|
-
return new Float32Array(e.getChannelData(
|
|
186
|
+
if (!Number.isInteger(o) || o < 0 || o >= e.numberOfChannels)
|
|
187
|
+
throw new Error(`Invalid channel ${o}. Audio has ${e.numberOfChannels} channel(s).`);
|
|
188
|
+
return new Float32Array(e.getChannelData(o));
|
|
108
189
|
}
|
|
109
|
-
function
|
|
110
|
-
const t = Math.max(1, Math.floor(
|
|
190
|
+
function it(e, o) {
|
|
191
|
+
const t = Math.max(1, Math.floor(o)), r = new Float32Array(t), i = new Float32Array(t), s = e.length / t;
|
|
111
192
|
for (let a = 0; a < t; a += 1) {
|
|
112
|
-
const n = Math.floor(a *
|
|
193
|
+
const n = Math.floor(a * s), h = Math.max(n + 1, Math.floor((a + 1) * s));
|
|
113
194
|
let l = 1, u = -1;
|
|
114
195
|
for (let d = n; d < h && d < e.length; d += 1) {
|
|
115
196
|
const m = e[d] ?? 0;
|
|
@@ -119,36 +200,38 @@ function K(e, s) {
|
|
|
119
200
|
}
|
|
120
201
|
return { min: r, max: i };
|
|
121
202
|
}
|
|
122
|
-
function E(e,
|
|
123
|
-
return
|
|
203
|
+
function E(e, o, t) {
|
|
204
|
+
return it(N(e, t), o);
|
|
124
205
|
}
|
|
125
|
-
function
|
|
206
|
+
function y(e, o, t) {
|
|
126
207
|
const r = window.devicePixelRatio || 1;
|
|
127
|
-
e.style.width = "100%", e.style.height = `${t}px`, e.width = Math.max(1, Math.floor(
|
|
208
|
+
e.style.width = "100%", e.style.height = `${t}px`, e.width = Math.max(1, Math.floor(o * r)), e.height = Math.max(1, Math.floor(t * r));
|
|
128
209
|
const i = e.getContext("2d");
|
|
129
210
|
if (!i)
|
|
130
211
|
throw new Error("Canvas 2D context is unavailable.");
|
|
131
212
|
return i.setTransform(r, 0, 0, r, 0, 0), i;
|
|
132
213
|
}
|
|
133
|
-
function
|
|
214
|
+
function B(e, o, t, r, i = "rgba(0, 0, 0, 0.45)") {
|
|
134
215
|
if (!Number.isFinite(t) || t <= 0) return;
|
|
135
|
-
const
|
|
136
|
-
if (!
|
|
137
|
-
const a = e.
|
|
138
|
-
|
|
216
|
+
const s = o / t;
|
|
217
|
+
if (!Number.isFinite(s) || s >= 1) return;
|
|
218
|
+
const a = e.getContext("2d");
|
|
219
|
+
if (!a) return;
|
|
220
|
+
const n = e.clientWidth, h = e.clientHeight, l = Math.max(0, Math.min(n, s * n));
|
|
221
|
+
a.save(), a.strokeStyle = i, a.lineWidth = 2, a.beginPath(), a.moveTo(l, 0), a.lineTo(l, h), a.stroke(), a.strokeStyle = r, a.lineWidth = 1, a.beginPath(), a.moveTo(l, 0), a.lineTo(l, h), a.stroke(), a.restore();
|
|
139
222
|
}
|
|
140
|
-
function
|
|
141
|
-
const t =
|
|
223
|
+
function k(e, o) {
|
|
224
|
+
const t = M(o, 0, 1) * (e.length - 1), r = Math.floor(t), i = Math.min(r + 1, e.length - 1), s = t - r, a = e[r], n = e[i];
|
|
142
225
|
return [
|
|
143
|
-
Math.round(a[0] + (n[0] - a[0]) *
|
|
144
|
-
Math.round(a[1] + (n[1] - a[1]) *
|
|
145
|
-
Math.round(a[2] + (n[2] - a[2]) *
|
|
226
|
+
Math.round(a[0] + (n[0] - a[0]) * s),
|
|
227
|
+
Math.round(a[1] + (n[1] - a[1]) * s),
|
|
228
|
+
Math.round(a[2] + (n[2] - a[2]) * s)
|
|
146
229
|
];
|
|
147
230
|
}
|
|
148
|
-
function
|
|
149
|
-
const t =
|
|
231
|
+
function st(e, o) {
|
|
232
|
+
const t = M(o, 0, 1);
|
|
150
233
|
if (e === "audition")
|
|
151
|
-
return
|
|
234
|
+
return k(
|
|
152
235
|
[
|
|
153
236
|
[0, 0, 0],
|
|
154
237
|
[12, 7, 34],
|
|
@@ -165,7 +248,7 @@ function G(e, s) {
|
|
|
165
248
|
const r = Math.round(t * 255);
|
|
166
249
|
return [r, r, r];
|
|
167
250
|
}
|
|
168
|
-
return
|
|
251
|
+
return k(
|
|
169
252
|
e === "viridis" ? [
|
|
170
253
|
[68, 1, 84],
|
|
171
254
|
[59, 82, 139],
|
|
@@ -188,127 +271,136 @@ function G(e, s) {
|
|
|
188
271
|
t
|
|
189
272
|
);
|
|
190
273
|
}
|
|
191
|
-
function
|
|
274
|
+
function at(e, o, t) {
|
|
192
275
|
const r = e.getContext("2d");
|
|
193
276
|
if (!r) return;
|
|
194
|
-
const i = e.clientWidth,
|
|
195
|
-
if (r.clearRect(0, 0, i,
|
|
196
|
-
const h = r.createImageData(a, n), l =
|
|
277
|
+
const i = e.clientWidth, s = e.clientHeight, a = Math.max(1, e.width), n = Math.max(1, e.height);
|
|
278
|
+
if (r.clearRect(0, 0, i, s), r.fillStyle = t.background, r.fillRect(0, 0, i, s), !o) return;
|
|
279
|
+
const h = r.createImageData(a, n), l = o.maxDb - o.minDb;
|
|
197
280
|
for (let u = 0; u < h.width; u += 1) {
|
|
198
|
-
const d = Math.min(
|
|
281
|
+
const d = Math.min(o.timeFrames - 1, Math.floor(u / h.width * o.timeFrames));
|
|
199
282
|
for (let m = 0; m < h.height; m += 1) {
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
Math.floor((h.height - 1 - m) / h.height *
|
|
203
|
-
),
|
|
204
|
-
h.data[
|
|
283
|
+
const g = Math.min(
|
|
284
|
+
o.freqBins - 1,
|
|
285
|
+
Math.floor((h.height - 1 - m) / h.height * o.freqBins)
|
|
286
|
+
), p = o.values[d * o.freqBins + g], b = M((p - o.minDb) / l, 0, 1), [w, f, x] = st(t.colorMap, b), S = (m * h.width + u) * 4;
|
|
287
|
+
h.data[S] = w, h.data[S + 1] = f, h.data[S + 2] = x, h.data[S + 3] = 255;
|
|
205
288
|
}
|
|
206
289
|
}
|
|
207
|
-
r.putImageData(h, 0, 0),
|
|
290
|
+
r.putImageData(h, 0, 0), ht(r, i, s, o.maxFrequencyHz, t.tickColor);
|
|
208
291
|
}
|
|
209
|
-
function
|
|
292
|
+
function nt(e, o) {
|
|
210
293
|
if (!Number.isFinite(e) || e <= 0) return 1e3;
|
|
211
|
-
const t = Math.max(2, Math.min(6, Math.floor(
|
|
212
|
-
return (
|
|
294
|
+
const t = Math.max(2, Math.min(6, Math.floor(o / 28))), r = e / t, i = 10 ** Math.floor(Math.log10(r)), s = r / i;
|
|
295
|
+
return (s <= 1 ? 1 : s <= 2 ? 2 : s <= 7.5 ? 5 : 10) * i;
|
|
213
296
|
}
|
|
214
|
-
function
|
|
215
|
-
const
|
|
297
|
+
function ht(e, o, t, r, i = "rgba(255, 255, 255, 0.42)") {
|
|
298
|
+
const s = nt(r, t), a = 5;
|
|
216
299
|
e.save(), e.strokeStyle = i, e.fillStyle = i, e.lineWidth = 1, e.font = "10px system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif", e.textAlign = "left", e.textBaseline = "middle";
|
|
217
|
-
for (let
|
|
218
|
-
const
|
|
219
|
-
e.beginPath(), e.moveTo(0,
|
|
300
|
+
for (let n = s; n < r; n += s) {
|
|
301
|
+
const h = t - n / r * t;
|
|
302
|
+
e.beginPath(), e.moveTo(0, h + 0.5), e.lineTo(o, h + 0.5), e.stroke(), e.fillText(W(n), a, h);
|
|
220
303
|
}
|
|
221
|
-
e.restore();
|
|
304
|
+
e.beginPath(), e.moveTo(0, 0.5), e.lineTo(o, 0.5), e.stroke(), e.fillText(W(r), a, 8), e.restore();
|
|
222
305
|
}
|
|
223
|
-
function
|
|
306
|
+
function W(e) {
|
|
224
307
|
if (e >= 1e3) {
|
|
225
|
-
const
|
|
226
|
-
return `${Number.isInteger(
|
|
308
|
+
const o = e / 1e3;
|
|
309
|
+
return `${Number.isInteger(o) ? o.toFixed(0) : o.toFixed(1)}k`;
|
|
227
310
|
}
|
|
228
311
|
return `${Math.round(e)}`;
|
|
229
312
|
}
|
|
230
|
-
function
|
|
313
|
+
function L(e, o, t) {
|
|
231
314
|
const r = e.getContext("2d");
|
|
232
315
|
if (!r) return;
|
|
233
|
-
const
|
|
234
|
-
if (r.clearRect(0, 0, i,
|
|
235
|
-
const a = t.style ?? "waveform", n =
|
|
236
|
-
a === "waveform" ?
|
|
316
|
+
const { width: i, height: s } = lt(e, r);
|
|
317
|
+
if (r.clearRect(0, 0, i, s), r.fillStyle = t.background, r.fillRect(0, 0, i, s), r.strokeStyle = t.centerColor ?? t.color, r.lineWidth = 1, !o) return;
|
|
318
|
+
const a = t.style ?? "waveform", n = ct(o), h = dt(a), l = Math.max(1, t.barWidth ?? h.barWidth), u = Math.max(0, t.barSpacing ?? h.barSpacing);
|
|
319
|
+
a === "waveform" ? mt(r, o, s, {
|
|
237
320
|
unplayedColor: t.color,
|
|
238
321
|
playedColor: t.playedColor ?? t.progressColor ?? t.color,
|
|
239
322
|
centerColor: t.centerColor ?? t.color,
|
|
240
323
|
progress: t.progress ?? 0
|
|
241
|
-
}) : a === "lines" ?
|
|
324
|
+
}) : a === "lines" ? gt(r, n, i, s, t.color) : a === "blocks" ? pt(r, n, i, s, t.color, l, u) : a === "dots" ? bt(r, n, i, s, t.color, l, u) : ft(r, n, i, s, t.color, l, u);
|
|
242
325
|
}
|
|
243
|
-
function
|
|
244
|
-
|
|
326
|
+
function lt(e, o) {
|
|
327
|
+
if (typeof o.getTransform != "function")
|
|
328
|
+
return { width: e.clientWidth, height: e.clientHeight };
|
|
329
|
+
const t = o.getTransform(), r = Math.abs(t.a) || 1, i = Math.abs(t.d) || 1;
|
|
330
|
+
return {
|
|
331
|
+
width: Math.max(e.clientWidth, e.width / r),
|
|
332
|
+
height: Math.max(e.clientHeight, e.height / i)
|
|
333
|
+
};
|
|
245
334
|
}
|
|
246
|
-
function
|
|
247
|
-
|
|
335
|
+
function ut(e, o) {
|
|
336
|
+
return Math.max(Math.abs(e.min[o] ?? 0), Math.abs(e.max[o] ?? 0));
|
|
337
|
+
}
|
|
338
|
+
function ct(e) {
|
|
339
|
+
const o = [];
|
|
248
340
|
for (let t = 0; t < e.max.length; t += 1)
|
|
249
|
-
|
|
250
|
-
return
|
|
341
|
+
o.push(ut(e, t));
|
|
342
|
+
return o;
|
|
251
343
|
}
|
|
252
|
-
function
|
|
253
|
-
if (e.length ===
|
|
254
|
-
if (e.length === 0 ||
|
|
344
|
+
function C(e, o) {
|
|
345
|
+
if (e.length === o) return e;
|
|
346
|
+
if (e.length === 0 || o <= 0) return [];
|
|
255
347
|
const t = [];
|
|
256
|
-
if (
|
|
257
|
-
const r = (e.length - 1) / Math.max(1,
|
|
258
|
-
for (let i = 0; i <
|
|
259
|
-
const
|
|
348
|
+
if (o > e.length) {
|
|
349
|
+
const r = (e.length - 1) / Math.max(1, o - 1);
|
|
350
|
+
for (let i = 0; i < o; i += 1) {
|
|
351
|
+
const s = i * r, a = Math.floor(s), n = Math.ceil(s), h = s - a;
|
|
260
352
|
n >= e.length ? t.push(e[e.length - 1] ?? 0) : a === n ? t.push(e[a] ?? 0) : t.push((e[a] ?? 0) * (1 - h) + (e[n] ?? 0) * h);
|
|
261
353
|
}
|
|
262
354
|
} else {
|
|
263
|
-
const r = e.length /
|
|
264
|
-
for (let i = 0; i <
|
|
265
|
-
const
|
|
355
|
+
const r = e.length / o;
|
|
356
|
+
for (let i = 0; i < o; i += 1) {
|
|
357
|
+
const s = Math.floor(i * r), a = Math.floor((i + 1) * r);
|
|
266
358
|
let n = 0, h = 0;
|
|
267
|
-
for (let l =
|
|
359
|
+
for (let l = s; l <= a && l < e.length; l += 1)
|
|
268
360
|
n = Math.max(n, e[l] ?? 0), h += 1;
|
|
269
361
|
h === 0 && (n = e[Math.min(Math.round(i * r), e.length - 1)] ?? 0), t.push(n);
|
|
270
362
|
}
|
|
271
363
|
}
|
|
272
364
|
return t;
|
|
273
365
|
}
|
|
274
|
-
function
|
|
366
|
+
function dt(e) {
|
|
275
367
|
return e === "bars" ? { barWidth: 3, barSpacing: 1 } : e === "blocks" ? { barWidth: 4, barSpacing: 2 } : e === "dots" ? { barWidth: 3, barSpacing: 3 } : { barWidth: 2, barSpacing: 0 };
|
|
276
368
|
}
|
|
277
|
-
function
|
|
369
|
+
function mt(e, o, t, r) {
|
|
278
370
|
const i = t / 2;
|
|
279
|
-
e.strokeStyle = r.centerColor, e.lineWidth = 1, e.beginPath(), e.moveTo(0, i), e.lineTo(
|
|
280
|
-
const
|
|
281
|
-
|
|
371
|
+
e.strokeStyle = r.centerColor, e.lineWidth = 1, e.beginPath(), e.moveTo(0, i), e.lineTo(o.max.length, i), e.stroke(), H(e, o, t, 0, o.min.length, r.unplayedColor);
|
|
372
|
+
const s = Math.max(0, Math.min(o.min.length, Math.round(o.min.length * r.progress)));
|
|
373
|
+
s > 0 && H(e, o, t, 0, s, r.playedColor);
|
|
282
374
|
}
|
|
283
|
-
function
|
|
375
|
+
function H(e, o, t, r, i, s) {
|
|
284
376
|
const a = t / 2;
|
|
285
|
-
e.strokeStyle =
|
|
377
|
+
e.strokeStyle = s, e.beginPath();
|
|
286
378
|
for (let n = r; n < i; n += 1) {
|
|
287
|
-
const h = a -
|
|
379
|
+
const h = a - o.min[n] * a, l = a - o.max[n] * a;
|
|
288
380
|
e.moveTo(n + 0.5, h), e.lineTo(n + 0.5, l);
|
|
289
381
|
}
|
|
290
382
|
e.stroke();
|
|
291
383
|
}
|
|
292
|
-
function
|
|
293
|
-
const n = Math.floor(t / (
|
|
384
|
+
function ft(e, o, t, r, i, s, a) {
|
|
385
|
+
const n = Math.floor(t / (s + a)), h = C(o, n);
|
|
294
386
|
e.fillStyle = i;
|
|
295
387
|
for (let l = 0; l < h.length; l += 1) {
|
|
296
|
-
const u = l * (
|
|
297
|
-
if (u +
|
|
388
|
+
const u = l * (s + a);
|
|
389
|
+
if (u + s > t) break;
|
|
298
390
|
const d = h[l] * r * 0.9;
|
|
299
|
-
e.fillRect(u, r - d,
|
|
391
|
+
e.fillRect(u, r - d, s, d);
|
|
300
392
|
}
|
|
301
393
|
}
|
|
302
|
-
function
|
|
303
|
-
const
|
|
304
|
-
e.strokeStyle = i, e.lineWidth = 2, e.lineCap = "round", e.lineJoin = "round", e.strokeStyle = "rgba(255, 255, 255, 0.03)", e.lineWidth = 0.5, e.beginPath(), e.moveTo(0,
|
|
394
|
+
function gt(e, o, t, r, i) {
|
|
395
|
+
const s = r / 2, a = C(o, Math.max(2, Math.floor(t / 3)));
|
|
396
|
+
e.strokeStyle = i, e.lineWidth = 2, e.lineCap = "round", e.lineJoin = "round", e.strokeStyle = "rgba(255, 255, 255, 0.03)", e.lineWidth = 0.5, e.beginPath(), e.moveTo(0, s), e.lineTo(t, s), e.stroke();
|
|
305
397
|
for (let h = 0; h <= 10; h += 1) {
|
|
306
398
|
const l = t / 10 * h;
|
|
307
399
|
e.beginPath(), e.moveTo(l, 0), e.lineTo(l, r), e.stroke();
|
|
308
400
|
}
|
|
309
|
-
e.strokeStyle = i, e.lineWidth = 2, e.beginPath(), e.moveTo(0,
|
|
401
|
+
e.strokeStyle = i, e.lineWidth = 2, e.beginPath(), e.moveTo(0, s);
|
|
310
402
|
const n = a.map((h, l) => {
|
|
311
|
-
const u = l / Math.max(1, a.length - 1) * t, d =
|
|
403
|
+
const u = l / Math.max(1, a.length - 1) * t, d = s + Math.sin(l * 0.1) * h * r * 0.35;
|
|
312
404
|
return { x: u, y: d };
|
|
313
405
|
});
|
|
314
406
|
for (let h = 0; h < n.length - 1; h += 1) {
|
|
@@ -317,37 +409,37 @@ function it(e, s, t, r, i) {
|
|
|
317
409
|
}
|
|
318
410
|
e.stroke();
|
|
319
411
|
}
|
|
320
|
-
function
|
|
321
|
-
const n = r / 2, h = Math.floor(t / (
|
|
412
|
+
function pt(e, o, t, r, i, s, a) {
|
|
413
|
+
const n = r / 2, h = Math.floor(t / (s + a)), l = C(o, h), u = 4, d = 2;
|
|
322
414
|
e.fillStyle = i;
|
|
323
415
|
for (let m = 0; m < l.length; m += 1) {
|
|
324
|
-
const
|
|
325
|
-
if (
|
|
326
|
-
const
|
|
416
|
+
const g = m * (s + a);
|
|
417
|
+
if (g + s > t) break;
|
|
418
|
+
const p = l[m] * r * 0.9, b = Math.floor(p / (u + d));
|
|
327
419
|
for (let w = 0; w < b; w += 1) {
|
|
328
420
|
const f = w * (u + d);
|
|
329
|
-
e.fillRect(
|
|
421
|
+
e.fillRect(g, n - f - u, s, u), w > 0 && e.fillRect(g, n + f, s, u);
|
|
330
422
|
}
|
|
331
423
|
}
|
|
332
424
|
}
|
|
333
|
-
function
|
|
334
|
-
const n = r / 2, h = Math.floor(t / (
|
|
425
|
+
function bt(e, o, t, r, i, s, a) {
|
|
426
|
+
const n = r / 2, h = Math.floor(t / (s + a)), l = C(o, h), u = Math.max(1.5, s / 2);
|
|
335
427
|
e.fillStyle = i;
|
|
336
428
|
for (let d = 0; d < l.length; d += 1) {
|
|
337
|
-
const m = d * (
|
|
429
|
+
const m = d * (s + a) + s / 2;
|
|
338
430
|
if (m > t) break;
|
|
339
|
-
const
|
|
340
|
-
e.beginPath(), e.arc(m, n -
|
|
431
|
+
const g = l[d] * r * 0.9;
|
|
432
|
+
e.beginPath(), e.arc(m, n - g / 2, u, 0, Math.PI * 2), e.fill(), e.beginPath(), e.arc(m, n + g / 2, u, 0, Math.PI * 2), e.fill();
|
|
341
433
|
}
|
|
342
434
|
}
|
|
343
|
-
function
|
|
435
|
+
function F(e) {
|
|
344
436
|
if (!Number.isFinite(e) || e < 0)
|
|
345
437
|
return "00:00.000";
|
|
346
|
-
const
|
|
347
|
-
return `${String(
|
|
438
|
+
const o = Math.floor(e * 1e3), t = o % 1e3, r = Math.floor(o / 1e3), i = r % 60, s = Math.floor(r / 60);
|
|
439
|
+
return `${String(s).padStart(2, "0")}:${String(i).padStart(2, "0")}.${String(t).padStart(3, "0")}`;
|
|
348
440
|
}
|
|
349
|
-
const
|
|
350
|
-
|
|
441
|
+
const O = document.createElement("template");
|
|
442
|
+
O.innerHTML = `
|
|
351
443
|
<style>
|
|
352
444
|
:host {
|
|
353
445
|
--ap-bg: #ffffff;
|
|
@@ -538,17 +630,19 @@ L.innerHTML = `
|
|
|
538
630
|
</div>
|
|
539
631
|
</div>
|
|
540
632
|
`;
|
|
541
|
-
class
|
|
633
|
+
class T extends HTMLElement {
|
|
542
634
|
constructor() {
|
|
543
635
|
super();
|
|
544
636
|
c(this, "audio");
|
|
545
637
|
c(this, "audioBuffer");
|
|
638
|
+
c(this, "sourceSampleRate");
|
|
546
639
|
c(this, "waveformPeaks");
|
|
547
640
|
c(this, "spectrogram");
|
|
548
641
|
c(this, "worker");
|
|
549
642
|
c(this, "resizeObserver");
|
|
550
643
|
c(this, "animationFrame", 0);
|
|
551
644
|
c(this, "loadingToken", 0);
|
|
645
|
+
c(this, "waveformPeaksWidth", 0);
|
|
552
646
|
c(this, "blobUrl");
|
|
553
647
|
c(this, "playRequestedAt");
|
|
554
648
|
c(this, "root");
|
|
@@ -571,8 +665,8 @@ class C extends HTMLElement {
|
|
|
571
665
|
});
|
|
572
666
|
c(this, "handleSeekClick", (t) => {
|
|
573
667
|
if (!this.audio || !Number.isFinite(this.duration) || this.duration <= 0) return;
|
|
574
|
-
const i = t.currentTarget.getBoundingClientRect(),
|
|
575
|
-
this.audio.currentTime = Math.max(0, Math.min(this.duration,
|
|
668
|
+
const i = t.currentTarget.getBoundingClientRect(), s = (t.clientX - i.left) / i.width;
|
|
669
|
+
this.audio.currentTime = Math.max(0, Math.min(this.duration, s * this.duration)), this.updateTimeLabels(), this.drawCursors(), this.dispatchTypedEvent("seek"), this.audio.paused ? (this.playRequestedAt = performance.now(), this.audio.play().catch((a) => this.handleError("Audio playback failed.", a))) : this.audio.pause();
|
|
576
670
|
});
|
|
577
671
|
c(this, "handleKeydown", (t) => {
|
|
578
672
|
t.key !== " " && t.key !== "Enter" || (t.preventDefault(), this.handlePlayButton());
|
|
@@ -597,9 +691,9 @@ class C extends HTMLElement {
|
|
|
597
691
|
});
|
|
598
692
|
c(this, "updateTimeLabels", () => {
|
|
599
693
|
var t;
|
|
600
|
-
this.currentEl.textContent =
|
|
694
|
+
this.currentEl.textContent = F(((t = this.audio) == null ? void 0 : t.currentTime) ?? 0), this.durationEl.textContent = F(this.duration);
|
|
601
695
|
});
|
|
602
|
-
this.root = this.attachShadow({ mode: "open" }), this.root.append(
|
|
696
|
+
this.root = this.attachShadow({ mode: "open" }), this.root.append(O.content.cloneNode(!0)), this.button = this.requireElement("button"), this.button.dataset.state = "play", this.toolbar = this.requireElement(".toolbar"), this.timeEl = this.requireElement(".time"), this.currentEl = this.requireElement(".current"), this.durationEl = this.requireElement(".duration"), this.statusEl = this.requireElement(".status"), this.errorEl = this.requireElement(".error"), this.waveformPane = this.requireElement(".waveform-pane"), this.spectrogramPane = this.requireElement(".spectrogram-pane"), this.waveformCanvas = this.requireElement(".waveform"), this.spectrogramCanvas = this.requireElement(".spectrogram"), this.spectrogramOverlay = this.requireElement(".spectrogram-overlay"), this.waveformCursor = this.requireElement(".waveform-cursor"), this.spectrogramCursor = this.requireElement(".spectrogram-cursor");
|
|
603
697
|
}
|
|
604
698
|
get src() {
|
|
605
699
|
return this.getAttribute("src") ?? "";
|
|
@@ -722,7 +816,7 @@ class C extends HTMLElement {
|
|
|
722
816
|
this.setAttribute("channel", String(t));
|
|
723
817
|
}
|
|
724
818
|
connectedCallback() {
|
|
725
|
-
this.button.addEventListener("click", this.handlePlayButton), this.waveformPane.addEventListener("click", this.handleSeekClick), this.spectrogramPane.addEventListener("click", this.handleSeekClick), this.addEventListener("keydown", this.handleKeydown), this.tabIndex = this.tabIndex >= 0 ? this.tabIndex : 0, this.resizeObserver = new ResizeObserver(() => this.
|
|
819
|
+
this.button.addEventListener("click", this.handlePlayButton), this.waveformPane.addEventListener("click", this.handleSeekClick), this.spectrogramPane.addEventListener("click", this.handleSeekClick), this.addEventListener("keydown", this.handleKeydown), this.tabIndex = this.tabIndex >= 0 ? this.tabIndex : 0, this.resizeObserver = new ResizeObserver(() => this.handleResize()), this.resizeObserver.observe(this), this.layoutAndRender(), this.src && this.load();
|
|
726
820
|
}
|
|
727
821
|
disconnectedCallback() {
|
|
728
822
|
var t, r, i;
|
|
@@ -742,23 +836,23 @@ class C extends HTMLElement {
|
|
|
742
836
|
}
|
|
743
837
|
}
|
|
744
838
|
async load() {
|
|
745
|
-
var i,
|
|
839
|
+
var i, s, a;
|
|
746
840
|
const t = this.src, r = ++this.loadingToken;
|
|
747
|
-
if (this.clearError(), this.setStatus(t ? "Loading" : ""), this.dispatchTypedEvent("loadstart"), this.button.disabled = !0, this.waveformPeaks = void 0, this.spectrogram = void 0, this.layoutAndRender(), (i = this.worker) == null || i.terminate(), (
|
|
841
|
+
if (this.clearError(), this.setStatus(t ? "Loading" : ""), this.dispatchTypedEvent("loadstart"), this.button.disabled = !0, this.sourceSampleRate = void 0, this.waveformPeaks = void 0, this.waveformPeaksWidth = 0, this.spectrogram = void 0, this.layoutAndRender(), (i = this.worker) == null || i.terminate(), (s = this.audio) == null || s.pause(), this.revokeBlobUrl(), !t) {
|
|
748
842
|
this.setStatus("");
|
|
749
843
|
return;
|
|
750
844
|
}
|
|
751
845
|
try {
|
|
752
|
-
const n = performance.now(), h = await
|
|
846
|
+
const n = performance.now(), h = await j(t), l = performance.now();
|
|
753
847
|
if (r !== this.loadingToken) return;
|
|
754
|
-
this.blobUrl = URL.createObjectURL(new Blob([h])), this.audio =
|
|
848
|
+
this.sourceSampleRate = X(h), this.blobUrl = URL.createObjectURL(new Blob([h])), this.audio = Y(this.blobUrl, this.autoplay), this.bindAudio();
|
|
755
849
|
const u = this.waitForAudioReady(this.audio);
|
|
756
|
-
this.audioBuffer = await
|
|
850
|
+
this.audioBuffer = await $(h, this.sourceSampleRate);
|
|
757
851
|
const d = performance.now();
|
|
758
852
|
if (r !== this.loadingToken) return;
|
|
759
|
-
const m = Math.max(1, Math.floor(this.getCanvasWidth())),
|
|
760
|
-
this.waveformPeaks = this.showWaveform ? E(this.audioBuffer, m, this.channel) : void 0;
|
|
761
|
-
const
|
|
853
|
+
const m = Math.max(1, Math.floor(this.getCanvasWidth())), g = performance.now();
|
|
854
|
+
this.waveformPeaks = this.showWaveform ? E(this.audioBuffer, m, this.channel) : void 0, this.waveformPeaksWidth = this.waveformPeaks ? m : 0;
|
|
855
|
+
const p = performance.now();
|
|
762
856
|
await u;
|
|
763
857
|
const b = performance.now();
|
|
764
858
|
if (r !== this.loadingToken) return;
|
|
@@ -767,7 +861,7 @@ class C extends HTMLElement {
|
|
|
767
861
|
fetchMs: l - n,
|
|
768
862
|
audioReadyMs: b - l,
|
|
769
863
|
decodeMs: d - l,
|
|
770
|
-
waveformMs:
|
|
864
|
+
waveformMs: p - g,
|
|
771
865
|
firstUsableMs: w - n
|
|
772
866
|
};
|
|
773
867
|
this.dispatchEvent(new CustomEvent("profile", { detail: f })), this.layoutAndRender(), this.computeSpectrogramForCurrentBuffer(r, f, n), this.autoplay && await ((a = this.audio) == null ? void 0 : a.play());
|
|
@@ -779,7 +873,7 @@ class C extends HTMLElement {
|
|
|
779
873
|
async recomputeAnalysis() {
|
|
780
874
|
if (!this.audioBuffer) return;
|
|
781
875
|
const t = Math.max(1, Math.floor(this.getCanvasWidth()));
|
|
782
|
-
this.waveformPeaks = this.showWaveform ? E(this.audioBuffer, t, this.channel) : void 0, this.layoutAndRender(), this.showSpectrogram ? (this.setStatus("Analyzing"), this.spectrogram = await this.computeSpectrogramInWorker(), this.setStatus("")) : this.spectrogram = void 0, this.layoutAndRender();
|
|
876
|
+
this.waveformPeaks = this.showWaveform ? E(this.audioBuffer, t, this.channel) : void 0, this.waveformPeaksWidth = this.waveformPeaks ? t : 0, this.layoutAndRender(), this.showSpectrogram ? (this.setStatus("Analyzing"), this.spectrogram = await this.computeSpectrogramInWorker(), this.setStatus("")) : this.spectrogram = void 0, this.layoutAndRender();
|
|
783
877
|
}
|
|
784
878
|
async computeSpectrogramForCurrentBuffer(t, r, i) {
|
|
785
879
|
if (!this.audioBuffer || !this.showSpectrogram) {
|
|
@@ -787,7 +881,7 @@ class C extends HTMLElement {
|
|
|
787
881
|
return;
|
|
788
882
|
}
|
|
789
883
|
try {
|
|
790
|
-
const
|
|
884
|
+
const s = performance.now();
|
|
791
885
|
this.spectrogram = await this.computeSpectrogramInWorker();
|
|
792
886
|
const a = performance.now();
|
|
793
887
|
if (t !== this.loadingToken) return;
|
|
@@ -795,18 +889,18 @@ class C extends HTMLElement {
|
|
|
795
889
|
new CustomEvent("profile", {
|
|
796
890
|
detail: {
|
|
797
891
|
...r,
|
|
798
|
-
spectrogramMs: a -
|
|
892
|
+
spectrogramMs: a - s,
|
|
799
893
|
totalMs: a - i
|
|
800
894
|
}
|
|
801
895
|
})
|
|
802
896
|
);
|
|
803
|
-
} catch (
|
|
897
|
+
} catch (s) {
|
|
804
898
|
if (t !== this.loadingToken) return;
|
|
805
899
|
this.spectrogram = void 0, this.setStatus("Spectrogram unavailable"), this.dispatchEvent(
|
|
806
900
|
new CustomEvent("error", {
|
|
807
901
|
detail: {
|
|
808
|
-
message:
|
|
809
|
-
cause:
|
|
902
|
+
message: s instanceof Error ? s.message : "Failed to compute spectrogram.",
|
|
903
|
+
cause: s
|
|
810
904
|
}
|
|
811
905
|
})
|
|
812
906
|
);
|
|
@@ -814,28 +908,28 @@ class C extends HTMLElement {
|
|
|
814
908
|
}
|
|
815
909
|
computeSpectrogramInWorker() {
|
|
816
910
|
if (!this.audioBuffer) return Promise.resolve(void 0);
|
|
817
|
-
const t =
|
|
911
|
+
const t = N(this.audioBuffer, this.channel), r = {
|
|
818
912
|
samples: t,
|
|
819
|
-
sampleRate: this.audioBuffer.sampleRate,
|
|
913
|
+
sampleRate: this.sourceSampleRate ?? this.audioBuffer.sampleRate,
|
|
820
914
|
fftSize: this.fftSize,
|
|
821
915
|
hopSize: this.hopSize,
|
|
822
916
|
windowType: this.windowType,
|
|
823
917
|
minDb: this.minDb,
|
|
824
918
|
maxDb: this.maxDb
|
|
825
919
|
};
|
|
826
|
-
return typeof Worker > "u" ? Promise.resolve(
|
|
920
|
+
return typeof Worker > "u" ? Promise.resolve(ot(t, r.sampleRate, r)) : new Promise((i, s) => {
|
|
827
921
|
var a;
|
|
828
922
|
(a = this.worker) == null || a.terminate(), this.worker = new Worker(new URL(
|
|
829
923
|
/* @vite-ignore */
|
|
830
|
-
"/assets/spectrogram.worker-
|
|
924
|
+
"/assets/spectrogram.worker-CJxyA_5B.js",
|
|
831
925
|
import.meta.url
|
|
832
926
|
), { type: "module" }), this.worker.addEventListener(
|
|
833
927
|
"message",
|
|
834
928
|
(n) => {
|
|
835
|
-
"error" in n.data ?
|
|
929
|
+
"error" in n.data ? s(new Error(n.data.error.message)) : i(n.data);
|
|
836
930
|
},
|
|
837
931
|
{ once: !0 }
|
|
838
|
-
), this.worker.addEventListener("error", () =>
|
|
932
|
+
), this.worker.addEventListener("error", () => s(new Error("Spectrogram worker failed.")), { once: !0 }), this.worker.postMessage(r, [r.samples.buffer]);
|
|
839
933
|
});
|
|
840
934
|
}
|
|
841
935
|
bindAudio() {
|
|
@@ -844,9 +938,13 @@ class C extends HTMLElement {
|
|
|
844
938
|
return this.handleError("Audio playback failed.", (t = this.audio) == null ? void 0 : t.error);
|
|
845
939
|
}));
|
|
846
940
|
}
|
|
941
|
+
handleResize() {
|
|
942
|
+
const t = Math.max(1, Math.floor(this.getCanvasWidth()));
|
|
943
|
+
this.audioBuffer && this.showWaveform && t !== this.waveformPeaksWidth ? (this.waveformPeaks = E(this.audioBuffer, t, this.channel), this.waveformPeaksWidth = t) : this.showWaveform || (this.waveformPeaksWidth = 0), this.layoutAndRender();
|
|
944
|
+
}
|
|
847
945
|
layoutAndRender() {
|
|
848
946
|
const t = Math.max(1, Math.floor(this.getCanvasWidth())), { waveformHeight: r, spectrogramHeight: i } = this.getPaneHeights();
|
|
849
|
-
this.toolbar.classList.toggle("hidden", !this.showControls && !this.showTime), this.button.classList.toggle("hidden", !this.showControls), this.timeEl.classList.toggle("hidden", !this.showTime), this.waveformPane.classList.toggle("hidden", !this.showWaveform), this.spectrogramPane.classList.toggle("hidden", !this.showSpectrogram), this.showWaveform && (
|
|
947
|
+
this.toolbar.classList.toggle("hidden", !this.showControls && !this.showTime), this.button.classList.toggle("hidden", !this.showControls), this.timeEl.classList.toggle("hidden", !this.showTime), this.waveformPane.classList.toggle("hidden", !this.showWaveform), this.spectrogramPane.classList.toggle("hidden", !this.showSpectrogram), this.showWaveform && (y(this.waveformCanvas, t, r), y(this.waveformCursor, t, r), L(this.waveformCanvas, this.waveformPeaks, {
|
|
850
948
|
color: this.cssVar("--ap-waveform", "rgba(0, 214, 163, 0.34)"),
|
|
851
949
|
playedColor: this.cssVar("--ap-waveform-played", "#00f0b5"),
|
|
852
950
|
centerColor: this.cssVar("--ap-waveform-center", "rgba(0, 92, 58, 0.7)"),
|
|
@@ -856,7 +954,7 @@ class C extends HTMLElement {
|
|
|
856
954
|
barWidth: this.waveformBarWidth,
|
|
857
955
|
barSpacing: this.waveformBarSpacing,
|
|
858
956
|
progress: this.playbackProgress
|
|
859
|
-
})), this.showSpectrogram && (
|
|
957
|
+
})), this.showSpectrogram && (y(this.spectrogramCanvas, t, i), y(this.spectrogramOverlay, t, i), y(this.spectrogramCursor, t, i), at(this.spectrogramCanvas, this.spectrogram, {
|
|
860
958
|
colorMap: this.colorMap,
|
|
861
959
|
background: this.cssVar("--ap-bg", "#ffffff"),
|
|
862
960
|
tickColor: this.cssVar("--ap-spectrogram-tick", "rgba(255, 255, 255, 0.42)")
|
|
@@ -864,8 +962,8 @@ class C extends HTMLElement {
|
|
|
864
962
|
}
|
|
865
963
|
drawCursors() {
|
|
866
964
|
var a;
|
|
867
|
-
const t = ((a = this.audio) == null ? void 0 : a.currentTime) ?? 0, r = this.duration, i = this.cssVar("--ap-cursor", "#ff0000"),
|
|
868
|
-
this.showWaveform && this.waveformStyle === "waveform" &&
|
|
965
|
+
const t = ((a = this.audio) == null ? void 0 : a.currentTime) ?? 0, r = this.duration, i = this.cssVar("--ap-cursor", "#ff0000"), s = this.cssVar("--ap-cursor-shadow", "rgba(0, 0, 0, 0.45)");
|
|
966
|
+
this.showWaveform && this.waveformStyle === "waveform" && L(this.waveformCanvas, this.waveformPeaks, {
|
|
869
967
|
color: this.cssVar("--ap-waveform", "rgba(0, 214, 163, 0.34)"),
|
|
870
968
|
playedColor: this.cssVar("--ap-waveform-played", "#00f0b5"),
|
|
871
969
|
centerColor: this.cssVar("--ap-waveform-center", "rgba(0, 92, 58, 0.7)"),
|
|
@@ -875,19 +973,21 @@ class C extends HTMLElement {
|
|
|
875
973
|
barWidth: this.waveformBarWidth,
|
|
876
974
|
barSpacing: this.waveformBarSpacing,
|
|
877
975
|
progress: this.playbackProgress
|
|
878
|
-
}), this.drawSpectrogramOverlay(), this.clearCursor(this.waveformCursor), this.clearCursor(this.spectrogramCursor), this.showWaveform &&
|
|
976
|
+
}), this.drawSpectrogramOverlay(), this.clearCursor(this.waveformCursor), this.clearCursor(this.spectrogramCursor), this.showWaveform && B(this.waveformCursor, t, r, i, s), this.showSpectrogram && B(this.spectrogramCursor, t, r, i, s);
|
|
879
977
|
}
|
|
880
978
|
clearCursor(t) {
|
|
881
979
|
const r = t.getContext("2d");
|
|
882
|
-
|
|
980
|
+
if (!r) return;
|
|
981
|
+
const i = typeof r.getTransform == "function" ? r.getTransform() : void 0, s = Math.abs((i == null ? void 0 : i.a) ?? 1) || 1, a = Math.abs((i == null ? void 0 : i.d) ?? 1) || 1, n = Math.max(t.clientWidth, t.width / s), h = Math.max(t.clientHeight, t.height / a);
|
|
982
|
+
r.clearRect(0, 0, n, h);
|
|
883
983
|
}
|
|
884
984
|
drawSpectrogramOverlay() {
|
|
885
985
|
const t = this.spectrogramOverlay.getContext("2d");
|
|
886
986
|
if (!t) return;
|
|
887
987
|
const r = this.spectrogramOverlay.clientWidth, i = this.spectrogramOverlay.clientHeight;
|
|
888
988
|
if (t.clearRect(0, 0, r, i), !this.showSpectrogram || !this.spectrogram) return;
|
|
889
|
-
const
|
|
890
|
-
|
|
989
|
+
const s = r * this.playbackProgress, a = 1 - this.cssNumberVar("--ap-spectrogram-unplayed-opacity", 0.48);
|
|
990
|
+
s < r && (t.fillStyle = `rgba(0, 0, 0, ${Math.max(0, Math.min(1, a))})`, t.fillRect(s, 0, r - s, i));
|
|
891
991
|
}
|
|
892
992
|
startAnimation() {
|
|
893
993
|
this.stopAnimation();
|
|
@@ -942,10 +1042,10 @@ class C extends HTMLElement {
|
|
|
942
1042
|
waveformHeight: this.showWaveform ? this.waveformHeight : 0,
|
|
943
1043
|
spectrogramHeight: this.showSpectrogram ? this.spectrogramHeight : 0
|
|
944
1044
|
};
|
|
945
|
-
const
|
|
946
|
-
return this.showWaveform && !this.showSpectrogram ? { waveformHeight: r ? this.waveformHeight :
|
|
947
|
-
waveformHeight: Math.max(1, Math.round(
|
|
948
|
-
spectrogramHeight: Math.max(1,
|
|
1045
|
+
const s = this.height;
|
|
1046
|
+
return this.showWaveform && !this.showSpectrogram ? { waveformHeight: r ? this.waveformHeight : s, spectrogramHeight: 0 } : !this.showWaveform && this.showSpectrogram ? { waveformHeight: 0, spectrogramHeight: i ? this.spectrogramHeight : s } : r && i ? { waveformHeight: this.waveformHeight, spectrogramHeight: this.spectrogramHeight } : r ? { waveformHeight: this.waveformHeight, spectrogramHeight: Math.max(1, s - this.waveformHeight) } : i ? { waveformHeight: Math.max(1, s - this.spectrogramHeight), spectrogramHeight: this.spectrogramHeight } : {
|
|
1047
|
+
waveformHeight: Math.max(1, Math.round(s * (80 / 200))),
|
|
1048
|
+
spectrogramHeight: Math.max(1, s - Math.round(s * (80 / 200)))
|
|
949
1049
|
};
|
|
950
1050
|
}
|
|
951
1051
|
getNumberAttribute(t, r) {
|
|
@@ -979,12 +1079,12 @@ class C extends HTMLElement {
|
|
|
979
1079
|
}
|
|
980
1080
|
waitForAudioReady(t) {
|
|
981
1081
|
return t.readyState >= HTMLMediaElement.HAVE_METADATA ? Promise.resolve() : new Promise((r, i) => {
|
|
982
|
-
const
|
|
1082
|
+
const s = () => {
|
|
983
1083
|
t.removeEventListener("loadedmetadata", a), t.removeEventListener("error", n);
|
|
984
1084
|
}, a = () => {
|
|
985
|
-
|
|
1085
|
+
s(), r();
|
|
986
1086
|
}, n = () => {
|
|
987
|
-
|
|
1087
|
+
s(), i(t.error ?? new Error("Audio metadata failed to load."));
|
|
988
1088
|
};
|
|
989
1089
|
t.addEventListener("loadedmetadata", a, { once: !0 }), t.addEventListener("error", n, { once: !0 }), t.load();
|
|
990
1090
|
});
|
|
@@ -993,7 +1093,7 @@ class C extends HTMLElement {
|
|
|
993
1093
|
this.blobUrl && (URL.revokeObjectURL(this.blobUrl), this.blobUrl = void 0);
|
|
994
1094
|
}
|
|
995
1095
|
}
|
|
996
|
-
c(
|
|
1096
|
+
c(T, "observedAttributes", [
|
|
997
1097
|
"src",
|
|
998
1098
|
"height",
|
|
999
1099
|
"waveform-height",
|
|
@@ -1014,11 +1114,11 @@ c(C, "observedAttributes", [
|
|
|
1014
1114
|
"color-map",
|
|
1015
1115
|
"channel"
|
|
1016
1116
|
]);
|
|
1017
|
-
class
|
|
1117
|
+
class wt extends T {
|
|
1018
1118
|
}
|
|
1019
|
-
customElements.get("wavegram-player") || customElements.define("wavegram-player",
|
|
1020
|
-
customElements.get("audio-preview-spectrogram") || customElements.define("audio-preview-spectrogram",
|
|
1119
|
+
customElements.get("wavegram-player") || customElements.define("wavegram-player", T);
|
|
1120
|
+
customElements.get("audio-preview-spectrogram") || customElements.define("audio-preview-spectrogram", wt);
|
|
1021
1121
|
export {
|
|
1022
|
-
|
|
1023
|
-
|
|
1122
|
+
wt as AudioPreviewSpectrogram,
|
|
1123
|
+
T as Wavegram
|
|
1024
1124
|
};
|
package/dist/index.umd.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
(function(b,g){typeof exports=="object"&&typeof module<"u"?g(exports):typeof define=="function"&&define.amd?define(["exports"],g):(b=typeof globalThis<"u"?globalThis:b||self,g(b.Wavegram={}))})(this,(function(b){"use strict";var ht=Object.defineProperty;var lt=(b,g,A)=>g in b?ht(b,g,{enumerable:!0,configurable:!0,writable:!0,value:A}):b[g]=A;var c=(b,g,A)=>lt(b,typeof g!="symbol"?g+"":g,A);var g=typeof document<"u"?document.currentScript:null;let A;function z(){return A??(A=new AudioContext),A}async function I(e){return z().decodeAudioData(e.slice(0))}async function O(e){const s=await fetch(e);if(!s.ok)throw new Error(`Failed to load audio: ${s.status} ${s.statusText}`);return s.arrayBuffer()}function U(e,s){const t=new Audio(e);return t.preload="auto",t.autoplay=s,t.crossOrigin="anonymous",t}function M(e,s,t){return Math.min(t,Math.max(s,e))}const P=1e-10;function R(e){return Number.isInteger(e)&&e>0&&(e&e-1)===0}function V(e,s){const t=new Float32Array(e);if(e===1)return t[0]=1,t;for(let r=0;r<e;r+=1)s==="hann"?t[r]=.5-.5*Math.cos(2*Math.PI*r/(e-1)):s==="hamming"?t[r]=.54-.46*Math.cos(2*Math.PI*r/(e-1)):t[r]=1;return t}function $(e){let s=0;for(const t of e)s+=t;return s/e.length}function j(e){return 20*Math.log10(Math.abs(e)+P)}function Y(e,s){const t=e.length;if(!R(t)||s.length!==t)throw new Error("FFT input length must be a radix-2 size.");for(let r=1,i=0;r<t;r+=1){let o=t>>1;for(;i&o;o>>=1)i^=o;if(i^=o,r<i){const a=e[r];e[r]=e[i],e[i]=a;const n=s[r];s[r]=s[i],s[i]=n}}for(let r=2;r<=t;r<<=1){const i=-2*Math.PI/r,o=Math.cos(i),a=Math.sin(i);for(let n=0;n<t;n+=r){let h=1,l=0;for(let u=0;u<r/2;u+=1){const d=e[n+u],m=s[n+u],p=e[n+u+r/2]*h-s[n+u+r/2]*l,w=e[n+u+r/2]*l+s[n+u+r/2]*h;e[n+u]=d+p,s[n+u]=m+w,e[n+u+r/2]=d-p,s[n+u+r/2]=m-w;const v=h*o-l*a;l=h*a+l*o,h=v}}}}function _(e,s,t){const{fftSize:r,hopSize:i,windowType:o,minDb:a,maxDb:n}=t;if(!R(r))throw new Error(`fftSize must be a power of two. Received ${r}.`);if(!Number.isInteger(i)||i<=0)throw new Error(`hopSize must be a positive integer. Received ${i}.`);if(n<=a)throw new Error("maxDb must be greater than minDb.");const h=r/2+1,l=Math.max(1,Math.floor(Math.max(0,e.length-r)/i)+1),u=new Float32Array(l*h),d=V(r,o),m=Math.max(P,r*$(d)/2),p=new Float32Array(r),w=new Float32Array(r);for(let v=0;v<l;v+=1){const y=v*i;p.fill(0),w.fill(0);for(let f=0;f<r;f+=1)p[f]=(e[y+f]??0)*d[f];Y(p,w);for(let f=0;f<h;f+=1){const T=Math.hypot(p[f],w[f])/m;u[v*h+f]=M(j(T),a,n)}}return{values:u,freqBins:h,timeFrames:l,sampleRate:s,fftSize:r,hopSize:i,minDb:a,maxDb:n}}function B(e,s){if(s==="mix"){const t=new Float32Array(e.length);for(let r=0;r<e.numberOfChannels;r+=1){const i=e.getChannelData(r);for(let o=0;o<t.length;o+=1)t[o]+=i[o]/e.numberOfChannels}return t}if(!Number.isInteger(s)||s<0||s>=e.numberOfChannels)throw new Error(`Invalid channel ${s}. Audio has ${e.numberOfChannels} channel(s).`);return new Float32Array(e.getChannelData(s))}function K(e,s){const t=Math.max(1,Math.floor(s)),r=new Float32Array(t),i=new Float32Array(t),o=e.length/t;for(let a=0;a<t;a+=1){const n=Math.floor(a*o),h=Math.max(n+1,Math.floor((a+1)*o));let l=1,u=-1;for(let d=n;d<h&&d<e.length;d+=1){const m=e[d]??0;m<l&&(l=m),m>u&&(u=m)}r[a]=l===1?0:l,i[a]=u===-1?0:u}return{min:r,max:i}}function H(e,s,t){return K(B(e,t),s)}function S(e,s,t){const r=window.devicePixelRatio||1;e.style.width="100%",e.style.height=`${t}px`,e.width=Math.max(1,Math.floor(s*r)),e.height=Math.max(1,Math.floor(t*r));const i=e.getContext("2d");if(!i)throw new Error("Canvas 2D context is unavailable.");return i.setTransform(r,0,0,r,0,0),i}function W(e,s,t,r,i="rgba(0, 0, 0, 0.45)"){if(!Number.isFinite(t)||t<=0)return;const o=e.getContext("2d");if(!o)return;const a=e.clientWidth,n=e.clientHeight,h=Math.max(0,Math.min(a,s/t*a));o.save(),o.strokeStyle=i,o.lineWidth=2,o.beginPath(),o.moveTo(h,0),o.lineTo(h,n),o.stroke(),o.strokeStyle=r,o.lineWidth=1,o.beginPath(),o.moveTo(h,0),o.lineTo(h,n),o.stroke(),o.restore()}function k(e,s){const t=M(s,0,1)*(e.length-1),r=Math.floor(t),i=Math.min(r+1,e.length-1),o=t-r,a=e[r],n=e[i];return[Math.round(a[0]+(n[0]-a[0])*o),Math.round(a[1]+(n[1]-a[1])*o),Math.round(a[2]+(n[2]-a[2])*o)]}function G(e,s){const t=M(s,0,1);if(e==="audition")return k([[0,0,0],[12,7,34],[25,37,114],[18,104,174],[39,178,172],[244,180,43],[252,76,27],[255,238,117]],t);if(e==="gray"){const r=Math.round(t*255);return[r,r,r]}return k(e==="viridis"?[[68,1,84],[59,82,139],[33,145,140],[94,201,98],[253,231,37]]:e==="inferno"?[[0,0,4],[87,15,109],[187,55,84],[249,142,8],[252,255,164]]:[[0,0,4],[73,16,105],[182,54,121],[251,136,97],[252,253,191]],t)}function X(e,s,t){const r=e.getContext("2d");if(!r)return;const i=e.clientWidth,o=e.clientHeight,a=Math.max(1,e.width),n=Math.max(1,e.height);if(r.clearRect(0,0,i,o),r.fillStyle=t.background,r.fillRect(0,0,i,o),!s)return;const h=r.createImageData(a,n),l=s.maxDb-s.minDb;for(let u=0;u<h.width;u+=1){const d=Math.min(s.timeFrames-1,Math.floor(u/h.width*s.timeFrames));for(let m=0;m<h.height;m+=1){const p=Math.min(s.freqBins-1,Math.floor((h.height-1-m)/h.height*s.freqBins)),w=s.values[d*s.freqBins+p],v=M((w-s.minDb)/l,0,1),[y,f,T]=G(t.colorMap,v),E=(m*h.width+u)*4;h.data[E]=y,h.data[E+1]=f,h.data[E+2]=T,h.data[E+3]=255}}r.putImageData(h,0,0),Q(r,i,o,s.sampleRate,t.tickColor)}function J(e,s){if(!Number.isFinite(e)||e<=0)return 1e3;const t=Math.max(2,Math.min(6,Math.floor(s/28))),r=e/t,i=10**Math.floor(Math.log10(r)),o=r/i;return(o<=1?1:o<=2?2:o<=7.5?5:10)*i}function Q(e,s,t,r,i="rgba(255, 255, 255, 0.42)"){const o=r/2,a=J(o,t),n=5;e.save(),e.strokeStyle=i,e.fillStyle=i,e.lineWidth=1,e.font="10px system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif",e.textAlign="left",e.textBaseline="middle";for(let h=a;h<o;h+=a){const l=t-h/o*t;e.beginPath(),e.moveTo(0,l+.5),e.lineTo(s,l+.5),e.stroke(),e.fillText(Z(h),n,l)}e.restore()}function Z(e){if(e>=1e3){const s=e/1e3;return`${Number.isInteger(s)?s.toFixed(0):s.toFixed(1)}k`}return`${Math.round(e)}`}function F(e,s,t){const r=e.getContext("2d");if(!r)return;const i=e.clientWidth,o=e.clientHeight;if(r.clearRect(0,0,i,o),r.fillStyle=t.background,r.fillRect(0,0,i,o),r.strokeStyle=t.centerColor??t.color,r.lineWidth=1,!s)return;const a=t.style??"waveform",n=et(s),h=rt(a),l=Math.max(1,t.barWidth??h.barWidth),u=Math.max(0,t.barSpacing??h.barSpacing);a==="waveform"?ot(r,s,o,{unplayedColor:t.color,playedColor:t.playedColor??t.progressColor??t.color,centerColor:t.centerColor??t.color,progress:t.progress??0}):a==="lines"?st(r,n,i,o,t.color):a==="blocks"?at(r,n,i,o,t.color,l,u):a==="dots"?nt(r,n,i,o,t.color,l,u):it(r,n,i,o,t.color,l,u)}function tt(e,s){return Math.max(Math.abs(e.min[s]??0),Math.abs(e.max[s]??0))}function et(e){const s=[];for(let t=0;t<e.max.length;t+=1)s.push(tt(e,t));return s}function C(e,s){if(e.length===s)return e;if(e.length===0||s<=0)return[];const t=[];if(s>e.length){const r=(e.length-1)/Math.max(1,s-1);for(let i=0;i<s;i+=1){const o=i*r,a=Math.floor(o),n=Math.ceil(o),h=o-a;n>=e.length?t.push(e[e.length-1]??0):a===n?t.push(e[a]??0):t.push((e[a]??0)*(1-h)+(e[n]??0)*h)}}else{const r=e.length/s;for(let i=0;i<s;i+=1){const o=Math.floor(i*r),a=Math.floor((i+1)*r);let n=0,h=0;for(let l=o;l<=a&&l<e.length;l+=1)n=Math.max(n,e[l]??0),h+=1;h===0&&(n=e[Math.min(Math.round(i*r),e.length-1)]??0),t.push(n)}}return t}function rt(e){return e==="bars"?{barWidth:3,barSpacing:1}:e==="blocks"?{barWidth:4,barSpacing:2}:e==="dots"?{barWidth:3,barSpacing:3}:{barWidth:2,barSpacing:0}}function ot(e,s,t,r){const i=t/2;e.strokeStyle=r.centerColor,e.lineWidth=1,e.beginPath(),e.moveTo(0,i),e.lineTo(s.max.length,i),e.stroke(),L(e,s,t,0,s.min.length,r.unplayedColor);const o=Math.max(0,Math.min(s.min.length,Math.round(s.min.length*r.progress)));o>0&&L(e,s,t,0,o,r.playedColor)}function L(e,s,t,r,i,o){const a=t/2;e.strokeStyle=o,e.beginPath();for(let n=r;n<i;n+=1){const h=a-s.min[n]*a,l=a-s.max[n]*a;e.moveTo(n+.5,h),e.lineTo(n+.5,l)}e.stroke()}function it(e,s,t,r,i,o,a){const n=Math.floor(t/(o+a)),h=C(s,n);e.fillStyle=i;for(let l=0;l<h.length;l+=1){const u=l*(o+a);if(u+o>t)break;const d=h[l]*r*.9;e.fillRect(u,r-d,o,d)}}function st(e,s,t,r,i){const o=r/2,a=C(s,Math.max(2,Math.floor(t/3)));e.strokeStyle=i,e.lineWidth=2,e.lineCap="round",e.lineJoin="round",e.strokeStyle="rgba(255, 255, 255, 0.03)",e.lineWidth=.5,e.beginPath(),e.moveTo(0,o),e.lineTo(t,o),e.stroke();for(let h=0;h<=10;h+=1){const l=t/10*h;e.beginPath(),e.moveTo(l,0),e.lineTo(l,r),e.stroke()}e.strokeStyle=i,e.lineWidth=2,e.beginPath(),e.moveTo(0,o);const n=a.map((h,l)=>{const u=l/Math.max(1,a.length-1)*t,d=o+Math.sin(l*.1)*h*r*.35;return{x:u,y:d}});for(let h=0;h<n.length-1;h+=1){const l=n[h],u=n[h+1],d=l.x+(u.x-l.x)*.5,m=u.x-(u.x-l.x)*.5;e.bezierCurveTo(d,l.y,m,u.y,u.x,u.y)}e.stroke()}function at(e,s,t,r,i,o,a){const n=r/2,h=Math.floor(t/(o+a)),l=C(s,h),u=4,d=2;e.fillStyle=i;for(let m=0;m<l.length;m+=1){const p=m*(o+a);if(p+o>t)break;const w=l[m]*r*.9,v=Math.floor(w/(u+d));for(let y=0;y<v;y+=1){const f=y*(u+d);e.fillRect(p,n-f-u,o,u),y>0&&e.fillRect(p,n+f,o,u)}}}function nt(e,s,t,r,i,o,a){const n=r/2,h=Math.floor(t/(o+a)),l=C(s,h),u=Math.max(1.5,o/2);e.fillStyle=i;for(let d=0;d<l.length;d+=1){const m=d*(o+a)+o/2;if(m>t)break;const p=l[d]*r*.9;e.beginPath(),e.arc(m,n-p/2,u,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(m,n+p/2,u,0,Math.PI*2),e.fill()}}function D(e){if(!Number.isFinite(e)||e<0)return"00:00.000";const s=Math.floor(e*1e3),t=s%1e3,r=Math.floor(s/1e3),i=r%60,o=Math.floor(r/60);return`${String(o).padStart(2,"0")}:${String(i).padStart(2,"0")}.${String(t).padStart(3,"0")}`}const N=document.createElement("template");N.innerHTML=`
|
|
1
|
+
(function(b,p){typeof exports=="object"&&typeof module<"u"?p(exports):typeof define=="function"&&define.amd?define(["exports"],p):(b=typeof globalThis<"u"?globalThis:b||self,p(b.Wavegram={}))})(this,(function(b){"use strict";var vt=Object.defineProperty;var yt=(b,p,y)=>p in b?vt(b,p,{enumerable:!0,configurable:!0,writable:!0,value:y}):b[p]=y;var c=(b,p,y)=>yt(b,typeof p!="symbol"?p+"":p,y);var p=typeof document<"u"?document.currentScript:null;let y,B;function $(e){return(!y||B!==e)&&(y==null||y.close(),y=new AudioContext(e?{sampleRate:e}:void 0),B=e),y}async function j(e,o){return $(o).decodeAudioData(e.slice(0))}async function Y(e){const o=await fetch(e);if(!o.ok)throw new Error(`Failed to load audio: ${o.status} ${o.statusText}`);return o.arrayBuffer()}function _(e,o){const t=new Audio(e);return t.preload="auto",t.autoplay=o,t.crossOrigin="anonymous",t}function X(e){const o=new DataView(e);return K(o)??G(o)??J(o)??Q(o)}function K(e){if(e.byteLength<28||!A(e,0,"RIFF")&&!A(e,0,"RF64")||!A(e,8,"WAVE"))return;let o=12;for(;o+8<=e.byteLength;){const t=L(e,o,4),r=e.getUint32(o+4,!0),i=o+8;if(i+r>e.byteLength)return;if(t==="fmt "){if(r<8)return;const s=e.getUint32(i+4,!0);return Number.isFinite(s)&&s>0?s:void 0}o=i+r+r%2}}function G(e){if(!A(e,0,"fLaC"))return;let o=4;for(;o+4<=e.byteLength;){const r=e.getUint8(o)&127,i=e.getUint8(o+1)<<16|e.getUint8(o+2)<<8|e.getUint8(o+3),s=o+4;if(s+i>e.byteLength)return;if(r===0){if(i<13)return;const a=e.getUint8(s+10)<<12|e.getUint8(s+11)<<4|e.getUint8(s+12)>>4;return a>0?a:void 0}o=s+i}}function J(e){const o=W(e,[1,118,111,114,98,105,115]);if(o!==-1&&o+16<=e.byteLength){const r=e.getUint32(o+12,!0);return r>0?r:void 0}const t=W(e,[79,112,117,115,72,101,97,100]);if(t!==-1&&t+16<=e.byteLength){const r=e.getUint32(t+12,!0);return r>0?r:48e3}}function Q(e){let o=0;A(e,0,"ID3")&&e.byteLength>=10&&(o=10+Z(e,6));const t=[44100,48e3,32e3],r=[22050,24e3,16e3],i=[11025,12e3,8e3];for(;o+4<=e.byteLength;o+=1){const s=e.getUint8(o),a=e.getUint8(o+1);if(s!==255||(a&224)!==224)continue;const n=a>>3&3,h=a>>1&3,l=e.getUint8(o+2)>>2&3;if(n===1||h===0||l===3)continue;return(n===3?t:n===2?r:i)[l]}}function W(e,o){const t=e.byteLength-o.length;for(let r=0;r<=t;r+=1){let i=!0;for(let s=0;s<o.length;s+=1)if(e.getUint8(r+s)!==o[s]){i=!1;break}if(i)return r}return-1}function Z(e,o){return e.getUint8(o)<<21|e.getUint8(o+1)<<14|e.getUint8(o+2)<<7|e.getUint8(o+3)}function A(e,o,t){return o+t.length>e.byteLength?!1:L(e,o,t.length)===t}function L(e,o,t){let r="";for(let i=0;i<t;i+=1)r+=String.fromCharCode(e.getUint8(o+i));return r}function M(e,o,t){return Math.min(t,Math.max(o,e))}const F=1e-10;function H(e){return Number.isInteger(e)&&e>0&&(e&e-1)===0}function tt(e,o){const t=new Float32Array(e);if(e===1)return t[0]=1,t;for(let r=0;r<e;r+=1)o==="hann"?t[r]=.5-.5*Math.cos(2*Math.PI*r/(e-1)):o==="hamming"?t[r]=.54-.46*Math.cos(2*Math.PI*r/(e-1)):t[r]=1;return t}function et(e){let o=0;for(const t of e)o+=t;return o/e.length}function rt(e){return 20*Math.log10(Math.abs(e)+F)}function ot(e,o){const t=e.length;if(!H(t)||o.length!==t)throw new Error("FFT input length must be a radix-2 size.");for(let r=1,i=0;r<t;r+=1){let s=t>>1;for(;i&s;s>>=1)i^=s;if(i^=s,r<i){const a=e[r];e[r]=e[i],e[i]=a;const n=o[r];o[r]=o[i],o[i]=n}}for(let r=2;r<=t;r<<=1){const i=-2*Math.PI/r,s=Math.cos(i),a=Math.sin(i);for(let n=0;n<t;n+=r){let h=1,l=0;for(let u=0;u<r/2;u+=1){const d=e[n+u],m=o[n+u],g=e[n+u+r/2]*h-o[n+u+r/2]*l,w=e[n+u+r/2]*l+o[n+u+r/2]*h;e[n+u]=d+g,o[n+u]=m+w,e[n+u+r/2]=d-g,o[n+u+r/2]=m-w;const v=h*s-l*a;l=h*a+l*s,h=v}}}}function it(e,o,t){const{fftSize:r,hopSize:i,windowType:s,minDb:a,maxDb:n}=t;if(!H(r))throw new Error(`fftSize must be a power of two. Received ${r}.`);if(!Number.isInteger(i)||i<=0)throw new Error(`hopSize must be a positive integer. Received ${i}.`);if(n<=a)throw new Error("maxDb must be greater than minDb.");const h=r/2+1,l=Math.max(1,Math.floor(Math.max(0,e.length-r)/i)+1),u=new Float32Array(l*h),d=tt(r,s),m=Math.max(F,r*et(d)/2),g=new Float32Array(r),w=new Float32Array(r);for(let v=0;v<l;v+=1){const S=v*i;g.fill(0),w.fill(0);for(let f=0;f<r;f+=1)g[f]=(e[S+f]??0)*d[f];ot(g,w);for(let f=0;f<h;f+=1){const R=Math.hypot(g[f],w[f])/m;u[v*h+f]=M(rt(R),a,n)}}return{values:u,freqBins:h,timeFrames:l,sampleRate:o,maxFrequencyHz:o/2,fftSize:r,hopSize:i,minDb:a,maxDb:n}}function U(e,o){if(o==="mix"){const t=new Float32Array(e.length);for(let r=0;r<e.numberOfChannels;r+=1){const i=e.getChannelData(r);for(let s=0;s<t.length;s+=1)t[s]+=i[s]/e.numberOfChannels}return t}if(!Number.isInteger(o)||o<0||o>=e.numberOfChannels)throw new Error(`Invalid channel ${o}. Audio has ${e.numberOfChannels} channel(s).`);return new Float32Array(e.getChannelData(o))}function st(e,o){const t=Math.max(1,Math.floor(o)),r=new Float32Array(t),i=new Float32Array(t),s=e.length/t;for(let a=0;a<t;a+=1){const n=Math.floor(a*s),h=Math.max(n+1,Math.floor((a+1)*s));let l=1,u=-1;for(let d=n;d<h&&d<e.length;d+=1){const m=e[d]??0;m<l&&(l=m),m>u&&(u=m)}r[a]=l===1?0:l,i[a]=u===-1?0:u}return{min:r,max:i}}function P(e,o,t){return st(U(e,t),o)}function k(e,o,t){const r=window.devicePixelRatio||1;e.style.width="100%",e.style.height=`${t}px`,e.width=Math.max(1,Math.floor(o*r)),e.height=Math.max(1,Math.floor(t*r));const i=e.getContext("2d");if(!i)throw new Error("Canvas 2D context is unavailable.");return i.setTransform(r,0,0,r,0,0),i}function D(e,o,t,r,i="rgba(0, 0, 0, 0.45)"){if(!Number.isFinite(t)||t<=0)return;const s=o/t;if(!Number.isFinite(s)||s>=1)return;const a=e.getContext("2d");if(!a)return;const n=e.clientWidth,h=e.clientHeight,l=Math.max(0,Math.min(n,s*n));a.save(),a.strokeStyle=i,a.lineWidth=2,a.beginPath(),a.moveTo(l,0),a.lineTo(l,h),a.stroke(),a.strokeStyle=r,a.lineWidth=1,a.beginPath(),a.moveTo(l,0),a.lineTo(l,h),a.stroke(),a.restore()}function C(e,o){const t=M(o,0,1)*(e.length-1),r=Math.floor(t),i=Math.min(r+1,e.length-1),s=t-r,a=e[r],n=e[i];return[Math.round(a[0]+(n[0]-a[0])*s),Math.round(a[1]+(n[1]-a[1])*s),Math.round(a[2]+(n[2]-a[2])*s)]}function at(e,o){const t=M(o,0,1);if(e==="audition")return C([[0,0,0],[12,7,34],[25,37,114],[18,104,174],[39,178,172],[244,180,43],[252,76,27],[255,238,117]],t);if(e==="gray"){const r=Math.round(t*255);return[r,r,r]}return C(e==="viridis"?[[68,1,84],[59,82,139],[33,145,140],[94,201,98],[253,231,37]]:e==="inferno"?[[0,0,4],[87,15,109],[187,55,84],[249,142,8],[252,255,164]]:[[0,0,4],[73,16,105],[182,54,121],[251,136,97],[252,253,191]],t)}function nt(e,o,t){const r=e.getContext("2d");if(!r)return;const i=e.clientWidth,s=e.clientHeight,a=Math.max(1,e.width),n=Math.max(1,e.height);if(r.clearRect(0,0,i,s),r.fillStyle=t.background,r.fillRect(0,0,i,s),!o)return;const h=r.createImageData(a,n),l=o.maxDb-o.minDb;for(let u=0;u<h.width;u+=1){const d=Math.min(o.timeFrames-1,Math.floor(u/h.width*o.timeFrames));for(let m=0;m<h.height;m+=1){const g=Math.min(o.freqBins-1,Math.floor((h.height-1-m)/h.height*o.freqBins)),w=o.values[d*o.freqBins+g],v=M((w-o.minDb)/l,0,1),[S,f,R]=at(t.colorMap,v),T=(m*h.width+u)*4;h.data[T]=S,h.data[T+1]=f,h.data[T+2]=R,h.data[T+3]=255}}r.putImageData(h,0,0),lt(r,i,s,o.maxFrequencyHz,t.tickColor)}function ht(e,o){if(!Number.isFinite(e)||e<=0)return 1e3;const t=Math.max(2,Math.min(6,Math.floor(o/28))),r=e/t,i=10**Math.floor(Math.log10(r)),s=r/i;return(s<=1?1:s<=2?2:s<=7.5?5:10)*i}function lt(e,o,t,r,i="rgba(255, 255, 255, 0.42)"){const s=ht(r,t),a=5;e.save(),e.strokeStyle=i,e.fillStyle=i,e.lineWidth=1,e.font="10px system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif",e.textAlign="left",e.textBaseline="middle";for(let n=s;n<r;n+=s){const h=t-n/r*t;e.beginPath(),e.moveTo(0,h+.5),e.lineTo(o,h+.5),e.stroke(),e.fillText(N(n),a,h)}e.beginPath(),e.moveTo(0,.5),e.lineTo(o,.5),e.stroke(),e.fillText(N(r),a,8),e.restore()}function N(e){if(e>=1e3){const o=e/1e3;return`${Number.isInteger(o)?o.toFixed(0):o.toFixed(1)}k`}return`${Math.round(e)}`}function z(e,o,t){const r=e.getContext("2d");if(!r)return;const{width:i,height:s}=ut(e,r);if(r.clearRect(0,0,i,s),r.fillStyle=t.background,r.fillRect(0,0,i,s),r.strokeStyle=t.centerColor??t.color,r.lineWidth=1,!o)return;const a=t.style??"waveform",n=dt(o),h=mt(a),l=Math.max(1,t.barWidth??h.barWidth),u=Math.max(0,t.barSpacing??h.barSpacing);a==="waveform"?ft(r,o,s,{unplayedColor:t.color,playedColor:t.playedColor??t.progressColor??t.color,centerColor:t.centerColor??t.color,progress:t.progress??0}):a==="lines"?pt(r,n,i,s,t.color):a==="blocks"?bt(r,n,i,s,t.color,l,u):a==="dots"?wt(r,n,i,s,t.color,l,u):gt(r,n,i,s,t.color,l,u)}function ut(e,o){if(typeof o.getTransform!="function")return{width:e.clientWidth,height:e.clientHeight};const t=o.getTransform(),r=Math.abs(t.a)||1,i=Math.abs(t.d)||1;return{width:Math.max(e.clientWidth,e.width/r),height:Math.max(e.clientHeight,e.height/i)}}function ct(e,o){return Math.max(Math.abs(e.min[o]??0),Math.abs(e.max[o]??0))}function dt(e){const o=[];for(let t=0;t<e.max.length;t+=1)o.push(ct(e,t));return o}function x(e,o){if(e.length===o)return e;if(e.length===0||o<=0)return[];const t=[];if(o>e.length){const r=(e.length-1)/Math.max(1,o-1);for(let i=0;i<o;i+=1){const s=i*r,a=Math.floor(s),n=Math.ceil(s),h=s-a;n>=e.length?t.push(e[e.length-1]??0):a===n?t.push(e[a]??0):t.push((e[a]??0)*(1-h)+(e[n]??0)*h)}}else{const r=e.length/o;for(let i=0;i<o;i+=1){const s=Math.floor(i*r),a=Math.floor((i+1)*r);let n=0,h=0;for(let l=s;l<=a&&l<e.length;l+=1)n=Math.max(n,e[l]??0),h+=1;h===0&&(n=e[Math.min(Math.round(i*r),e.length-1)]??0),t.push(n)}}return t}function mt(e){return e==="bars"?{barWidth:3,barSpacing:1}:e==="blocks"?{barWidth:4,barSpacing:2}:e==="dots"?{barWidth:3,barSpacing:3}:{barWidth:2,barSpacing:0}}function ft(e,o,t,r){const i=t/2;e.strokeStyle=r.centerColor,e.lineWidth=1,e.beginPath(),e.moveTo(0,i),e.lineTo(o.max.length,i),e.stroke(),I(e,o,t,0,o.min.length,r.unplayedColor);const s=Math.max(0,Math.min(o.min.length,Math.round(o.min.length*r.progress)));s>0&&I(e,o,t,0,s,r.playedColor)}function I(e,o,t,r,i,s){const a=t/2;e.strokeStyle=s,e.beginPath();for(let n=r;n<i;n+=1){const h=a-o.min[n]*a,l=a-o.max[n]*a;e.moveTo(n+.5,h),e.lineTo(n+.5,l)}e.stroke()}function gt(e,o,t,r,i,s,a){const n=Math.floor(t/(s+a)),h=x(o,n);e.fillStyle=i;for(let l=0;l<h.length;l+=1){const u=l*(s+a);if(u+s>t)break;const d=h[l]*r*.9;e.fillRect(u,r-d,s,d)}}function pt(e,o,t,r,i){const s=r/2,a=x(o,Math.max(2,Math.floor(t/3)));e.strokeStyle=i,e.lineWidth=2,e.lineCap="round",e.lineJoin="round",e.strokeStyle="rgba(255, 255, 255, 0.03)",e.lineWidth=.5,e.beginPath(),e.moveTo(0,s),e.lineTo(t,s),e.stroke();for(let h=0;h<=10;h+=1){const l=t/10*h;e.beginPath(),e.moveTo(l,0),e.lineTo(l,r),e.stroke()}e.strokeStyle=i,e.lineWidth=2,e.beginPath(),e.moveTo(0,s);const n=a.map((h,l)=>{const u=l/Math.max(1,a.length-1)*t,d=s+Math.sin(l*.1)*h*r*.35;return{x:u,y:d}});for(let h=0;h<n.length-1;h+=1){const l=n[h],u=n[h+1],d=l.x+(u.x-l.x)*.5,m=u.x-(u.x-l.x)*.5;e.bezierCurveTo(d,l.y,m,u.y,u.x,u.y)}e.stroke()}function bt(e,o,t,r,i,s,a){const n=r/2,h=Math.floor(t/(s+a)),l=x(o,h),u=4,d=2;e.fillStyle=i;for(let m=0;m<l.length;m+=1){const g=m*(s+a);if(g+s>t)break;const w=l[m]*r*.9,v=Math.floor(w/(u+d));for(let S=0;S<v;S+=1){const f=S*(u+d);e.fillRect(g,n-f-u,s,u),S>0&&e.fillRect(g,n+f,s,u)}}}function wt(e,o,t,r,i,s,a){const n=r/2,h=Math.floor(t/(s+a)),l=x(o,h),u=Math.max(1.5,s/2);e.fillStyle=i;for(let d=0;d<l.length;d+=1){const m=d*(s+a)+s/2;if(m>t)break;const g=l[d]*r*.9;e.beginPath(),e.arc(m,n-g/2,u,0,Math.PI*2),e.fill(),e.beginPath(),e.arc(m,n+g/2,u,0,Math.PI*2),e.fill()}}function O(e){if(!Number.isFinite(e)||e<0)return"00:00.000";const o=Math.floor(e*1e3),t=o%1e3,r=Math.floor(o/1e3),i=r%60,s=Math.floor(r/60);return`${String(s).padStart(2,"0")}:${String(i).padStart(2,"0")}.${String(t).padStart(3,"0")}`}const q=document.createElement("template");q.innerHTML=`
|
|
2
2
|
<style>
|
|
3
3
|
:host {
|
|
4
4
|
--ap-bg: #ffffff;
|
|
@@ -188,4 +188,4 @@
|
|
|
188
188
|
</div>
|
|
189
189
|
</div>
|
|
190
190
|
</div>
|
|
191
|
-
`;class x extends HTMLElement{constructor(){super();c(this,"audio");c(this,"audioBuffer");c(this,"waveformPeaks");c(this,"spectrogram");c(this,"worker");c(this,"resizeObserver");c(this,"animationFrame",0);c(this,"loadingToken",0);c(this,"blobUrl");c(this,"playRequestedAt");c(this,"root");c(this,"button");c(this,"toolbar");c(this,"timeEl");c(this,"currentEl");c(this,"durationEl");c(this,"statusEl");c(this,"errorEl");c(this,"waveformPane");c(this,"spectrogramPane");c(this,"waveformCanvas");c(this,"spectrogramCanvas");c(this,"spectrogramOverlay");c(this,"waveformCursor");c(this,"spectrogramCursor");c(this,"handlePlayButton",()=>{this.audio&&(this.audio.paused?(this.playRequestedAt=performance.now(),this.audio.play().catch(t=>this.handleError("Audio playback failed.",t))):this.audio.pause())});c(this,"handleSeekClick",t=>{if(!this.audio||!Number.isFinite(this.duration)||this.duration<=0)return;const i=t.currentTarget.getBoundingClientRect(),o=(t.clientX-i.left)/i.width;this.audio.currentTime=Math.max(0,Math.min(this.duration,o*this.duration)),this.updateTimeLabels(),this.drawCursors(),this.dispatchTypedEvent("seek"),this.audio.paused?(this.playRequestedAt=performance.now(),this.audio.play().catch(a=>this.handleError("Audio playback failed.",a))):this.audio.pause()});c(this,"handleKeydown",t=>{t.key!==" "&&t.key!=="Enter"||(t.preventDefault(),this.handlePlayButton())});c(this,"handleTimeUpdate",()=>{this.updateTimeLabels(),this.dispatchTypedEvent("timeupdate")});c(this,"handleAudioPlay",()=>{this.button.textContent="Pause",this.button.setAttribute("aria-label","Pause"),this.button.dataset.state="pause",this.dispatchTypedEvent("play")});c(this,"handleAudioPlaying",()=>{if(this.playRequestedAt!==void 0){const t={playToPlayingMs:performance.now()-this.playRequestedAt};this.dispatchEvent(new CustomEvent("playprofile",{detail:t})),this.playRequestedAt=void 0}this.startAnimation()});c(this,"handleAudioPause",()=>{this.button.textContent="Play",this.button.setAttribute("aria-label","Play"),this.button.dataset.state="play",this.dispatchTypedEvent("pause"),this.stopAnimation(),this.drawCursors()});c(this,"updateTimeLabels",()=>{var t;this.currentEl.textContent=D(((t=this.audio)==null?void 0:t.currentTime)??0),this.durationEl.textContent=D(this.duration)});this.root=this.attachShadow({mode:"open"}),this.root.append(N.content.cloneNode(!0)),this.button=this.requireElement("button"),this.button.dataset.state="play",this.toolbar=this.requireElement(".toolbar"),this.timeEl=this.requireElement(".time"),this.currentEl=this.requireElement(".current"),this.durationEl=this.requireElement(".duration"),this.statusEl=this.requireElement(".status"),this.errorEl=this.requireElement(".error"),this.waveformPane=this.requireElement(".waveform-pane"),this.spectrogramPane=this.requireElement(".spectrogram-pane"),this.waveformCanvas=this.requireElement(".waveform"),this.spectrogramCanvas=this.requireElement(".spectrogram"),this.spectrogramOverlay=this.requireElement(".spectrogram-overlay"),this.waveformCursor=this.requireElement(".waveform-cursor"),this.spectrogramCursor=this.requireElement(".spectrogram-cursor")}get src(){return this.getAttribute("src")??""}set src(t){this.setAttribute("src",t)}get height(){return this.getNumberAttribute("height",this.waveformHeight+this.spectrogramHeight)}set height(t){this.setAttribute("height",String(t))}get waveformHeight(){return this.getNumberAttribute("waveform-height",80)}set waveformHeight(t){this.setAttribute("waveform-height",String(t))}get spectrogramHeight(){return this.getNumberAttribute("spectrogram-height",120)}set spectrogramHeight(t){this.setAttribute("spectrogram-height",String(t))}get showWaveform(){return this.getBooleanAttribute("show-waveform",!0)}set showWaveform(t){this.setBooleanAttribute("show-waveform",t)}get showSpectrogram(){return this.getBooleanAttribute("show-spectrogram",!0)}set showSpectrogram(t){this.setBooleanAttribute("show-spectrogram",t)}get showControls(){return this.getBooleanAttribute("show-controls",!1)}set showControls(t){this.setBooleanAttribute("show-controls",t)}get showTime(){return this.getBooleanAttribute("show-time",!1)}set showTime(t){this.setBooleanAttribute("show-time",t)}get waveformStyle(){const t=this.getAttribute("waveform-style");return t==="line"?"lines":t==="waveform"?"waveform":t==="bars"||t==="lines"||t==="blocks"||t==="dots"?t:"waveform"}set waveformStyle(t){this.setAttribute("waveform-style",t)}get waveformBarWidth(){return this.getOptionalNumberAttribute("waveform-bar-width")}set waveformBarWidth(t){this.setAttribute("waveform-bar-width",String(t))}get waveformBarSpacing(){return this.getOptionalNumberAttribute("waveform-bar-spacing")}set waveformBarSpacing(t){this.setAttribute("waveform-bar-spacing",String(t))}get autoplay(){return this.getBooleanAttribute("autoplay",!1)}set autoplay(t){this.setBooleanAttribute("autoplay",t)}get fftSize(){return this.getNumberAttribute("fft-size",1024)}set fftSize(t){this.setAttribute("fft-size",String(t))}get hopSize(){return this.getNumberAttribute("hop-size",256)}set hopSize(t){this.setAttribute("hop-size",String(t))}get windowType(){const t=this.getAttribute("window-type");return t==="hamming"||t==="rectangular"?t:"hann"}set windowType(t){this.setAttribute("window-type",t)}get minDb(){return this.getNumberAttribute("min-db",-80)}set minDb(t){this.setAttribute("min-db",String(t))}get maxDb(){return this.getNumberAttribute("max-db",0)}set maxDb(t){this.setAttribute("max-db",String(t))}get colorMap(){const t=this.getAttribute("color-map");return t==="gray"||t==="magma"||t==="viridis"||t==="inferno"?t:"audition"}set colorMap(t){this.setAttribute("color-map",t)}get channel(){const t=this.getAttribute("channel");if(!t||t==="mix")return"mix";const r=Number(t);return Number.isInteger(r)?r:"mix"}set channel(t){this.setAttribute("channel",String(t))}connectedCallback(){this.button.addEventListener("click",this.handlePlayButton),this.waveformPane.addEventListener("click",this.handleSeekClick),this.spectrogramPane.addEventListener("click",this.handleSeekClick),this.addEventListener("keydown",this.handleKeydown),this.tabIndex=this.tabIndex>=0?this.tabIndex:0,this.resizeObserver=new ResizeObserver(()=>this.layoutAndRender()),this.resizeObserver.observe(this),this.layoutAndRender(),this.src&&this.load()}disconnectedCallback(){var t,r,i;this.button.removeEventListener("click",this.handlePlayButton),this.waveformPane.removeEventListener("click",this.handleSeekClick),this.spectrogramPane.removeEventListener("click",this.handleSeekClick),this.removeEventListener("keydown",this.handleKeydown),(t=this.resizeObserver)==null||t.disconnect(),this.stopAnimation(),(r=this.worker)==null||r.terminate(),(i=this.audio)==null||i.pause(),this.revokeBlobUrl()}attributeChangedCallback(t,r,i){if(!(r===i||!this.isConnected)){if(t==="src"){this.load();return}if(["fft-size","hop-size","window-type","min-db","max-db","channel"].includes(t)){this.audioBuffer&&this.recomputeAnalysis();return}this.layoutAndRender()}}async load(){var i,o,a;const t=this.src,r=++this.loadingToken;if(this.clearError(),this.setStatus(t?"Loading":""),this.dispatchTypedEvent("loadstart"),this.button.disabled=!0,this.waveformPeaks=void 0,this.spectrogram=void 0,this.layoutAndRender(),(i=this.worker)==null||i.terminate(),(o=this.audio)==null||o.pause(),this.revokeBlobUrl(),!t){this.setStatus("");return}try{const n=performance.now(),h=await O(t),l=performance.now();if(r!==this.loadingToken)return;this.blobUrl=URL.createObjectURL(new Blob([h])),this.audio=U(this.blobUrl,this.autoplay),this.bindAudio();const u=this.waitForAudioReady(this.audio);this.audioBuffer=await I(h);const d=performance.now();if(r!==this.loadingToken)return;const m=Math.max(1,Math.floor(this.getCanvasWidth())),p=performance.now();this.waveformPeaks=this.showWaveform?H(this.audioBuffer,m,this.channel):void 0;const w=performance.now();await u;const v=performance.now();if(r!==this.loadingToken)return;this.button.disabled=!1,this.setStatus(this.showSpectrogram?"Analyzing":""),this.updateTimeLabels(),this.dispatchTypedEvent("loaded");const y=performance.now(),f={fetchMs:l-n,audioReadyMs:v-l,decodeMs:d-l,waveformMs:w-p,firstUsableMs:y-n};this.dispatchEvent(new CustomEvent("profile",{detail:f})),this.layoutAndRender(),this.computeSpectrogramForCurrentBuffer(r,f,n),this.autoplay&&await((a=this.audio)==null?void 0:a.play())}catch(n){if(r!==this.loadingToken)return;this.handleError("Failed to load audio.",n)}}async recomputeAnalysis(){if(!this.audioBuffer)return;const t=Math.max(1,Math.floor(this.getCanvasWidth()));this.waveformPeaks=this.showWaveform?H(this.audioBuffer,t,this.channel):void 0,this.layoutAndRender(),this.showSpectrogram?(this.setStatus("Analyzing"),this.spectrogram=await this.computeSpectrogramInWorker(),this.setStatus("")):this.spectrogram=void 0,this.layoutAndRender()}async computeSpectrogramForCurrentBuffer(t,r,i){if(!this.audioBuffer||!this.showSpectrogram){this.spectrogram=void 0,this.setStatus(""),this.layoutAndRender();return}try{const o=performance.now();this.spectrogram=await this.computeSpectrogramInWorker();const a=performance.now();if(t!==this.loadingToken)return;this.setStatus(""),this.layoutAndRender(),this.dispatchEvent(new CustomEvent("profile",{detail:{...r,spectrogramMs:a-o,totalMs:a-i}}))}catch(o){if(t!==this.loadingToken)return;this.spectrogram=void 0,this.setStatus("Spectrogram unavailable"),this.dispatchEvent(new CustomEvent("error",{detail:{message:o instanceof Error?o.message:"Failed to compute spectrogram.",cause:o}}))}}computeSpectrogramInWorker(){if(!this.audioBuffer)return Promise.resolve(void 0);const t=B(this.audioBuffer,this.channel),r={samples:t,sampleRate:this.audioBuffer.sampleRate,fftSize:this.fftSize,hopSize:this.hopSize,windowType:this.windowType,minDb:this.minDb,maxDb:this.maxDb};return typeof Worker>"u"?Promise.resolve(_(t,this.audioBuffer.sampleRate,r)):new Promise((i,o)=>{var a;(a=this.worker)==null||a.terminate(),this.worker=new Worker(new URL("/assets/spectrogram.worker-Burn7NUr.js",typeof document>"u"&&typeof location>"u"?require("url").pathToFileURL(__filename).href:typeof document>"u"?location.href:g&&g.tagName.toUpperCase()==="SCRIPT"&&g.src||new URL("index.umd.js",document.baseURI).href),{type:"module"}),this.worker.addEventListener("message",n=>{"error"in n.data?o(new Error(n.data.error.message)):i(n.data)},{once:!0}),this.worker.addEventListener("error",()=>o(new Error("Spectrogram worker failed.")),{once:!0}),this.worker.postMessage(r,[r.samples.buffer])})}bindAudio(){this.audio&&(this.audio.addEventListener("loadedmetadata",this.updateTimeLabels),this.audio.addEventListener("timeupdate",this.handleTimeUpdate),this.audio.addEventListener("play",this.handleAudioPlay),this.audio.addEventListener("playing",this.handleAudioPlaying),this.audio.addEventListener("pause",this.handleAudioPause),this.audio.addEventListener("ended",this.handleAudioPause),this.audio.addEventListener("error",()=>{var t;return this.handleError("Audio playback failed.",(t=this.audio)==null?void 0:t.error)}))}layoutAndRender(){const t=Math.max(1,Math.floor(this.getCanvasWidth())),{waveformHeight:r,spectrogramHeight:i}=this.getPaneHeights();this.toolbar.classList.toggle("hidden",!this.showControls&&!this.showTime),this.button.classList.toggle("hidden",!this.showControls),this.timeEl.classList.toggle("hidden",!this.showTime),this.waveformPane.classList.toggle("hidden",!this.showWaveform),this.spectrogramPane.classList.toggle("hidden",!this.showSpectrogram),this.showWaveform&&(S(this.waveformCanvas,t,r),S(this.waveformCursor,t,r),F(this.waveformCanvas,this.waveformPeaks,{color:this.cssVar("--ap-waveform","rgba(0, 214, 163, 0.34)"),playedColor:this.cssVar("--ap-waveform-played","#00f0b5"),centerColor:this.cssVar("--ap-waveform-center","rgba(0, 92, 58, 0.7)"),progressColor:this.cssVar("--ap-waveform-progress","#00f0b5"),background:this.cssVar("--ap-waveform-bg","#020604"),style:this.waveformStyle,barWidth:this.waveformBarWidth,barSpacing:this.waveformBarSpacing,progress:this.playbackProgress})),this.showSpectrogram&&(S(this.spectrogramCanvas,t,i),S(this.spectrogramOverlay,t,i),S(this.spectrogramCursor,t,i),X(this.spectrogramCanvas,this.spectrogram,{colorMap:this.colorMap,background:this.cssVar("--ap-bg","#ffffff"),tickColor:this.cssVar("--ap-spectrogram-tick","rgba(255, 255, 255, 0.42)")}),this.drawSpectrogramOverlay()),this.drawCursors()}drawCursors(){var a;const t=((a=this.audio)==null?void 0:a.currentTime)??0,r=this.duration,i=this.cssVar("--ap-cursor","#ff0000"),o=this.cssVar("--ap-cursor-shadow","rgba(0, 0, 0, 0.45)");this.showWaveform&&this.waveformStyle==="waveform"&&F(this.waveformCanvas,this.waveformPeaks,{color:this.cssVar("--ap-waveform","rgba(0, 214, 163, 0.34)"),playedColor:this.cssVar("--ap-waveform-played","#00f0b5"),centerColor:this.cssVar("--ap-waveform-center","rgba(0, 92, 58, 0.7)"),progressColor:this.cssVar("--ap-waveform-progress","#00f0b5"),background:this.cssVar("--ap-waveform-bg","#020604"),style:this.waveformStyle,barWidth:this.waveformBarWidth,barSpacing:this.waveformBarSpacing,progress:this.playbackProgress}),this.drawSpectrogramOverlay(),this.clearCursor(this.waveformCursor),this.clearCursor(this.spectrogramCursor),this.showWaveform&&W(this.waveformCursor,t,r,i,o),this.showSpectrogram&&W(this.spectrogramCursor,t,r,i,o)}clearCursor(t){const r=t.getContext("2d");r==null||r.clearRect(0,0,t.clientWidth,t.clientHeight)}drawSpectrogramOverlay(){const t=this.spectrogramOverlay.getContext("2d");if(!t)return;const r=this.spectrogramOverlay.clientWidth,i=this.spectrogramOverlay.clientHeight;if(t.clearRect(0,0,r,i),!this.showSpectrogram||!this.spectrogram)return;const o=r*this.playbackProgress,a=1-this.cssNumberVar("--ap-spectrogram-unplayed-opacity",.48);o<r&&(t.fillStyle=`rgba(0, 0, 0, ${Math.max(0,Math.min(1,a))})`,t.fillRect(o,0,r-o,i))}startAnimation(){this.stopAnimation();const t=()=>{this.updateTimeLabels(),this.drawCursors(),this.animationFrame=requestAnimationFrame(t)};this.animationFrame=requestAnimationFrame(t)}stopAnimation(){this.animationFrame&&(cancelAnimationFrame(this.animationFrame),this.animationFrame=0)}get duration(){var t,r;return((t=this.audio)==null?void 0:t.duration)||((r=this.audioBuffer)==null?void 0:r.duration)||0}get playbackProgress(){var r;const t=this.duration;return!Number.isFinite(t)||t<=0?0:Math.max(0,Math.min(1,(((r=this.audio)==null?void 0:r.currentTime)??0)/t))}dispatchTypedEvent(t){var i;const r={currentTime:((i=this.audio)==null?void 0:i.currentTime)??0,duration:this.duration};this.dispatchEvent(new CustomEvent(t,{detail:r}))}handleError(t,r){this.button.disabled=!0,this.setStatus("");const i={message:r instanceof Error?`${t} ${r.message}`:t,cause:r};this.errorEl.textContent=i.message,this.errorEl.classList.remove("hidden"),this.dispatchEvent(new CustomEvent("error",{detail:i}))}clearError(){this.errorEl.textContent="",this.errorEl.classList.add("hidden")}setStatus(t){this.statusEl.textContent=t}getCanvasWidth(){return this.clientWidth||this.getBoundingClientRect().width||640}getPaneHeights(){if(!this.showWaveform&&!this.showSpectrogram)return{waveformHeight:0,spectrogramHeight:0};const t=this.hasAttribute("height"),r=this.hasAttribute("waveform-height"),i=this.hasAttribute("spectrogram-height");if(!t)return{waveformHeight:this.showWaveform?this.waveformHeight:0,spectrogramHeight:this.showSpectrogram?this.spectrogramHeight:0};const o=this.height;return this.showWaveform&&!this.showSpectrogram?{waveformHeight:r?this.waveformHeight:o,spectrogramHeight:0}:!this.showWaveform&&this.showSpectrogram?{waveformHeight:0,spectrogramHeight:i?this.spectrogramHeight:o}:r&&i?{waveformHeight:this.waveformHeight,spectrogramHeight:this.spectrogramHeight}:r?{waveformHeight:this.waveformHeight,spectrogramHeight:Math.max(1,o-this.waveformHeight)}:i?{waveformHeight:Math.max(1,o-this.spectrogramHeight),spectrogramHeight:this.spectrogramHeight}:{waveformHeight:Math.max(1,Math.round(o*(80/200))),spectrogramHeight:Math.max(1,o-Math.round(o*(80/200)))}}getNumberAttribute(t,r){const i=Number(this.getAttribute(t));return Number.isFinite(i)&&i>0?i:r}getOptionalNumberAttribute(t){if(!this.hasAttribute(t))return;const r=Number(this.getAttribute(t));return Number.isFinite(r)&&r>0?r:void 0}getBooleanAttribute(t,r){if(!this.hasAttribute(t))return r;const i=this.getAttribute(t);return i===""||i==="true"||i===t}setBooleanAttribute(t,r){r?this.setAttribute(t,""):this.setAttribute(t,"false")}cssVar(t,r){return getComputedStyle(this).getPropertyValue(t).trim()||r}cssNumberVar(t,r){const i=Number(getComputedStyle(this).getPropertyValue(t).trim());return Number.isFinite(i)?i:r}requireElement(t){const r=this.root.querySelector(t);if(!r)throw new Error(`Missing template element: ${t}`);return r}waitForAudioReady(t){return t.readyState>=HTMLMediaElement.HAVE_METADATA?Promise.resolve():new Promise((r,i)=>{const o=()=>{t.removeEventListener("loadedmetadata",a),t.removeEventListener("error",n)},a=()=>{o(),r()},n=()=>{o(),i(t.error??new Error("Audio metadata failed to load."))};t.addEventListener("loadedmetadata",a,{once:!0}),t.addEventListener("error",n,{once:!0}),t.load()})}revokeBlobUrl(){this.blobUrl&&(URL.revokeObjectURL(this.blobUrl),this.blobUrl=void 0)}}c(x,"observedAttributes",["src","height","waveform-height","spectrogram-height","show-waveform","show-spectrogram","show-controls","show-time","waveform-style","waveform-bar-width","waveform-bar-spacing","autoplay","fft-size","hop-size","window-type","min-db","max-db","color-map","channel"]);class q extends x{}customElements.get("wavegram-player")||customElements.define("wavegram-player",x),customElements.get("audio-preview-spectrogram")||customElements.define("audio-preview-spectrogram",q),b.AudioPreviewSpectrogram=q,b.Wavegram=x,Object.defineProperty(b,Symbol.toStringTag,{value:"Module"})}));
|
|
191
|
+
`;class E extends HTMLElement{constructor(){super();c(this,"audio");c(this,"audioBuffer");c(this,"sourceSampleRate");c(this,"waveformPeaks");c(this,"spectrogram");c(this,"worker");c(this,"resizeObserver");c(this,"animationFrame",0);c(this,"loadingToken",0);c(this,"waveformPeaksWidth",0);c(this,"blobUrl");c(this,"playRequestedAt");c(this,"root");c(this,"button");c(this,"toolbar");c(this,"timeEl");c(this,"currentEl");c(this,"durationEl");c(this,"statusEl");c(this,"errorEl");c(this,"waveformPane");c(this,"spectrogramPane");c(this,"waveformCanvas");c(this,"spectrogramCanvas");c(this,"spectrogramOverlay");c(this,"waveformCursor");c(this,"spectrogramCursor");c(this,"handlePlayButton",()=>{this.audio&&(this.audio.paused?(this.playRequestedAt=performance.now(),this.audio.play().catch(t=>this.handleError("Audio playback failed.",t))):this.audio.pause())});c(this,"handleSeekClick",t=>{if(!this.audio||!Number.isFinite(this.duration)||this.duration<=0)return;const i=t.currentTarget.getBoundingClientRect(),s=(t.clientX-i.left)/i.width;this.audio.currentTime=Math.max(0,Math.min(this.duration,s*this.duration)),this.updateTimeLabels(),this.drawCursors(),this.dispatchTypedEvent("seek"),this.audio.paused?(this.playRequestedAt=performance.now(),this.audio.play().catch(a=>this.handleError("Audio playback failed.",a))):this.audio.pause()});c(this,"handleKeydown",t=>{t.key!==" "&&t.key!=="Enter"||(t.preventDefault(),this.handlePlayButton())});c(this,"handleTimeUpdate",()=>{this.updateTimeLabels(),this.dispatchTypedEvent("timeupdate")});c(this,"handleAudioPlay",()=>{this.button.textContent="Pause",this.button.setAttribute("aria-label","Pause"),this.button.dataset.state="pause",this.dispatchTypedEvent("play")});c(this,"handleAudioPlaying",()=>{if(this.playRequestedAt!==void 0){const t={playToPlayingMs:performance.now()-this.playRequestedAt};this.dispatchEvent(new CustomEvent("playprofile",{detail:t})),this.playRequestedAt=void 0}this.startAnimation()});c(this,"handleAudioPause",()=>{this.button.textContent="Play",this.button.setAttribute("aria-label","Play"),this.button.dataset.state="play",this.dispatchTypedEvent("pause"),this.stopAnimation(),this.drawCursors()});c(this,"updateTimeLabels",()=>{var t;this.currentEl.textContent=O(((t=this.audio)==null?void 0:t.currentTime)??0),this.durationEl.textContent=O(this.duration)});this.root=this.attachShadow({mode:"open"}),this.root.append(q.content.cloneNode(!0)),this.button=this.requireElement("button"),this.button.dataset.state="play",this.toolbar=this.requireElement(".toolbar"),this.timeEl=this.requireElement(".time"),this.currentEl=this.requireElement(".current"),this.durationEl=this.requireElement(".duration"),this.statusEl=this.requireElement(".status"),this.errorEl=this.requireElement(".error"),this.waveformPane=this.requireElement(".waveform-pane"),this.spectrogramPane=this.requireElement(".spectrogram-pane"),this.waveformCanvas=this.requireElement(".waveform"),this.spectrogramCanvas=this.requireElement(".spectrogram"),this.spectrogramOverlay=this.requireElement(".spectrogram-overlay"),this.waveformCursor=this.requireElement(".waveform-cursor"),this.spectrogramCursor=this.requireElement(".spectrogram-cursor")}get src(){return this.getAttribute("src")??""}set src(t){this.setAttribute("src",t)}get height(){return this.getNumberAttribute("height",this.waveformHeight+this.spectrogramHeight)}set height(t){this.setAttribute("height",String(t))}get waveformHeight(){return this.getNumberAttribute("waveform-height",80)}set waveformHeight(t){this.setAttribute("waveform-height",String(t))}get spectrogramHeight(){return this.getNumberAttribute("spectrogram-height",120)}set spectrogramHeight(t){this.setAttribute("spectrogram-height",String(t))}get showWaveform(){return this.getBooleanAttribute("show-waveform",!0)}set showWaveform(t){this.setBooleanAttribute("show-waveform",t)}get showSpectrogram(){return this.getBooleanAttribute("show-spectrogram",!0)}set showSpectrogram(t){this.setBooleanAttribute("show-spectrogram",t)}get showControls(){return this.getBooleanAttribute("show-controls",!1)}set showControls(t){this.setBooleanAttribute("show-controls",t)}get showTime(){return this.getBooleanAttribute("show-time",!1)}set showTime(t){this.setBooleanAttribute("show-time",t)}get waveformStyle(){const t=this.getAttribute("waveform-style");return t==="line"?"lines":t==="waveform"?"waveform":t==="bars"||t==="lines"||t==="blocks"||t==="dots"?t:"waveform"}set waveformStyle(t){this.setAttribute("waveform-style",t)}get waveformBarWidth(){return this.getOptionalNumberAttribute("waveform-bar-width")}set waveformBarWidth(t){this.setAttribute("waveform-bar-width",String(t))}get waveformBarSpacing(){return this.getOptionalNumberAttribute("waveform-bar-spacing")}set waveformBarSpacing(t){this.setAttribute("waveform-bar-spacing",String(t))}get autoplay(){return this.getBooleanAttribute("autoplay",!1)}set autoplay(t){this.setBooleanAttribute("autoplay",t)}get fftSize(){return this.getNumberAttribute("fft-size",1024)}set fftSize(t){this.setAttribute("fft-size",String(t))}get hopSize(){return this.getNumberAttribute("hop-size",256)}set hopSize(t){this.setAttribute("hop-size",String(t))}get windowType(){const t=this.getAttribute("window-type");return t==="hamming"||t==="rectangular"?t:"hann"}set windowType(t){this.setAttribute("window-type",t)}get minDb(){return this.getNumberAttribute("min-db",-80)}set minDb(t){this.setAttribute("min-db",String(t))}get maxDb(){return this.getNumberAttribute("max-db",0)}set maxDb(t){this.setAttribute("max-db",String(t))}get colorMap(){const t=this.getAttribute("color-map");return t==="gray"||t==="magma"||t==="viridis"||t==="inferno"?t:"audition"}set colorMap(t){this.setAttribute("color-map",t)}get channel(){const t=this.getAttribute("channel");if(!t||t==="mix")return"mix";const r=Number(t);return Number.isInteger(r)?r:"mix"}set channel(t){this.setAttribute("channel",String(t))}connectedCallback(){this.button.addEventListener("click",this.handlePlayButton),this.waveformPane.addEventListener("click",this.handleSeekClick),this.spectrogramPane.addEventListener("click",this.handleSeekClick),this.addEventListener("keydown",this.handleKeydown),this.tabIndex=this.tabIndex>=0?this.tabIndex:0,this.resizeObserver=new ResizeObserver(()=>this.handleResize()),this.resizeObserver.observe(this),this.layoutAndRender(),this.src&&this.load()}disconnectedCallback(){var t,r,i;this.button.removeEventListener("click",this.handlePlayButton),this.waveformPane.removeEventListener("click",this.handleSeekClick),this.spectrogramPane.removeEventListener("click",this.handleSeekClick),this.removeEventListener("keydown",this.handleKeydown),(t=this.resizeObserver)==null||t.disconnect(),this.stopAnimation(),(r=this.worker)==null||r.terminate(),(i=this.audio)==null||i.pause(),this.revokeBlobUrl()}attributeChangedCallback(t,r,i){if(!(r===i||!this.isConnected)){if(t==="src"){this.load();return}if(["fft-size","hop-size","window-type","min-db","max-db","channel"].includes(t)){this.audioBuffer&&this.recomputeAnalysis();return}this.layoutAndRender()}}async load(){var i,s,a;const t=this.src,r=++this.loadingToken;if(this.clearError(),this.setStatus(t?"Loading":""),this.dispatchTypedEvent("loadstart"),this.button.disabled=!0,this.sourceSampleRate=void 0,this.waveformPeaks=void 0,this.waveformPeaksWidth=0,this.spectrogram=void 0,this.layoutAndRender(),(i=this.worker)==null||i.terminate(),(s=this.audio)==null||s.pause(),this.revokeBlobUrl(),!t){this.setStatus("");return}try{const n=performance.now(),h=await Y(t),l=performance.now();if(r!==this.loadingToken)return;this.sourceSampleRate=X(h),this.blobUrl=URL.createObjectURL(new Blob([h])),this.audio=_(this.blobUrl,this.autoplay),this.bindAudio();const u=this.waitForAudioReady(this.audio);this.audioBuffer=await j(h,this.sourceSampleRate);const d=performance.now();if(r!==this.loadingToken)return;const m=Math.max(1,Math.floor(this.getCanvasWidth())),g=performance.now();this.waveformPeaks=this.showWaveform?P(this.audioBuffer,m,this.channel):void 0,this.waveformPeaksWidth=this.waveformPeaks?m:0;const w=performance.now();await u;const v=performance.now();if(r!==this.loadingToken)return;this.button.disabled=!1,this.setStatus(this.showSpectrogram?"Analyzing":""),this.updateTimeLabels(),this.dispatchTypedEvent("loaded");const S=performance.now(),f={fetchMs:l-n,audioReadyMs:v-l,decodeMs:d-l,waveformMs:w-g,firstUsableMs:S-n};this.dispatchEvent(new CustomEvent("profile",{detail:f})),this.layoutAndRender(),this.computeSpectrogramForCurrentBuffer(r,f,n),this.autoplay&&await((a=this.audio)==null?void 0:a.play())}catch(n){if(r!==this.loadingToken)return;this.handleError("Failed to load audio.",n)}}async recomputeAnalysis(){if(!this.audioBuffer)return;const t=Math.max(1,Math.floor(this.getCanvasWidth()));this.waveformPeaks=this.showWaveform?P(this.audioBuffer,t,this.channel):void 0,this.waveformPeaksWidth=this.waveformPeaks?t:0,this.layoutAndRender(),this.showSpectrogram?(this.setStatus("Analyzing"),this.spectrogram=await this.computeSpectrogramInWorker(),this.setStatus("")):this.spectrogram=void 0,this.layoutAndRender()}async computeSpectrogramForCurrentBuffer(t,r,i){if(!this.audioBuffer||!this.showSpectrogram){this.spectrogram=void 0,this.setStatus(""),this.layoutAndRender();return}try{const s=performance.now();this.spectrogram=await this.computeSpectrogramInWorker();const a=performance.now();if(t!==this.loadingToken)return;this.setStatus(""),this.layoutAndRender(),this.dispatchEvent(new CustomEvent("profile",{detail:{...r,spectrogramMs:a-s,totalMs:a-i}}))}catch(s){if(t!==this.loadingToken)return;this.spectrogram=void 0,this.setStatus("Spectrogram unavailable"),this.dispatchEvent(new CustomEvent("error",{detail:{message:s instanceof Error?s.message:"Failed to compute spectrogram.",cause:s}}))}}computeSpectrogramInWorker(){if(!this.audioBuffer)return Promise.resolve(void 0);const t=U(this.audioBuffer,this.channel),r={samples:t,sampleRate:this.sourceSampleRate??this.audioBuffer.sampleRate,fftSize:this.fftSize,hopSize:this.hopSize,windowType:this.windowType,minDb:this.minDb,maxDb:this.maxDb};return typeof Worker>"u"?Promise.resolve(it(t,r.sampleRate,r)):new Promise((i,s)=>{var a;(a=this.worker)==null||a.terminate(),this.worker=new Worker(new URL("/assets/spectrogram.worker-CJxyA_5B.js",typeof document>"u"&&typeof location>"u"?require("url").pathToFileURL(__filename).href:typeof document>"u"?location.href:p&&p.tagName.toUpperCase()==="SCRIPT"&&p.src||new URL("index.umd.js",document.baseURI).href),{type:"module"}),this.worker.addEventListener("message",n=>{"error"in n.data?s(new Error(n.data.error.message)):i(n.data)},{once:!0}),this.worker.addEventListener("error",()=>s(new Error("Spectrogram worker failed.")),{once:!0}),this.worker.postMessage(r,[r.samples.buffer])})}bindAudio(){this.audio&&(this.audio.addEventListener("loadedmetadata",this.updateTimeLabels),this.audio.addEventListener("timeupdate",this.handleTimeUpdate),this.audio.addEventListener("play",this.handleAudioPlay),this.audio.addEventListener("playing",this.handleAudioPlaying),this.audio.addEventListener("pause",this.handleAudioPause),this.audio.addEventListener("ended",this.handleAudioPause),this.audio.addEventListener("error",()=>{var t;return this.handleError("Audio playback failed.",(t=this.audio)==null?void 0:t.error)}))}handleResize(){const t=Math.max(1,Math.floor(this.getCanvasWidth()));this.audioBuffer&&this.showWaveform&&t!==this.waveformPeaksWidth?(this.waveformPeaks=P(this.audioBuffer,t,this.channel),this.waveformPeaksWidth=t):this.showWaveform||(this.waveformPeaksWidth=0),this.layoutAndRender()}layoutAndRender(){const t=Math.max(1,Math.floor(this.getCanvasWidth())),{waveformHeight:r,spectrogramHeight:i}=this.getPaneHeights();this.toolbar.classList.toggle("hidden",!this.showControls&&!this.showTime),this.button.classList.toggle("hidden",!this.showControls),this.timeEl.classList.toggle("hidden",!this.showTime),this.waveformPane.classList.toggle("hidden",!this.showWaveform),this.spectrogramPane.classList.toggle("hidden",!this.showSpectrogram),this.showWaveform&&(k(this.waveformCanvas,t,r),k(this.waveformCursor,t,r),z(this.waveformCanvas,this.waveformPeaks,{color:this.cssVar("--ap-waveform","rgba(0, 214, 163, 0.34)"),playedColor:this.cssVar("--ap-waveform-played","#00f0b5"),centerColor:this.cssVar("--ap-waveform-center","rgba(0, 92, 58, 0.7)"),progressColor:this.cssVar("--ap-waveform-progress","#00f0b5"),background:this.cssVar("--ap-waveform-bg","#020604"),style:this.waveformStyle,barWidth:this.waveformBarWidth,barSpacing:this.waveformBarSpacing,progress:this.playbackProgress})),this.showSpectrogram&&(k(this.spectrogramCanvas,t,i),k(this.spectrogramOverlay,t,i),k(this.spectrogramCursor,t,i),nt(this.spectrogramCanvas,this.spectrogram,{colorMap:this.colorMap,background:this.cssVar("--ap-bg","#ffffff"),tickColor:this.cssVar("--ap-spectrogram-tick","rgba(255, 255, 255, 0.42)")}),this.drawSpectrogramOverlay()),this.drawCursors()}drawCursors(){var a;const t=((a=this.audio)==null?void 0:a.currentTime)??0,r=this.duration,i=this.cssVar("--ap-cursor","#ff0000"),s=this.cssVar("--ap-cursor-shadow","rgba(0, 0, 0, 0.45)");this.showWaveform&&this.waveformStyle==="waveform"&&z(this.waveformCanvas,this.waveformPeaks,{color:this.cssVar("--ap-waveform","rgba(0, 214, 163, 0.34)"),playedColor:this.cssVar("--ap-waveform-played","#00f0b5"),centerColor:this.cssVar("--ap-waveform-center","rgba(0, 92, 58, 0.7)"),progressColor:this.cssVar("--ap-waveform-progress","#00f0b5"),background:this.cssVar("--ap-waveform-bg","#020604"),style:this.waveformStyle,barWidth:this.waveformBarWidth,barSpacing:this.waveformBarSpacing,progress:this.playbackProgress}),this.drawSpectrogramOverlay(),this.clearCursor(this.waveformCursor),this.clearCursor(this.spectrogramCursor),this.showWaveform&&D(this.waveformCursor,t,r,i,s),this.showSpectrogram&&D(this.spectrogramCursor,t,r,i,s)}clearCursor(t){const r=t.getContext("2d");if(!r)return;const i=typeof r.getTransform=="function"?r.getTransform():void 0,s=Math.abs((i==null?void 0:i.a)??1)||1,a=Math.abs((i==null?void 0:i.d)??1)||1,n=Math.max(t.clientWidth,t.width/s),h=Math.max(t.clientHeight,t.height/a);r.clearRect(0,0,n,h)}drawSpectrogramOverlay(){const t=this.spectrogramOverlay.getContext("2d");if(!t)return;const r=this.spectrogramOverlay.clientWidth,i=this.spectrogramOverlay.clientHeight;if(t.clearRect(0,0,r,i),!this.showSpectrogram||!this.spectrogram)return;const s=r*this.playbackProgress,a=1-this.cssNumberVar("--ap-spectrogram-unplayed-opacity",.48);s<r&&(t.fillStyle=`rgba(0, 0, 0, ${Math.max(0,Math.min(1,a))})`,t.fillRect(s,0,r-s,i))}startAnimation(){this.stopAnimation();const t=()=>{this.updateTimeLabels(),this.drawCursors(),this.animationFrame=requestAnimationFrame(t)};this.animationFrame=requestAnimationFrame(t)}stopAnimation(){this.animationFrame&&(cancelAnimationFrame(this.animationFrame),this.animationFrame=0)}get duration(){var t,r;return((t=this.audio)==null?void 0:t.duration)||((r=this.audioBuffer)==null?void 0:r.duration)||0}get playbackProgress(){var r;const t=this.duration;return!Number.isFinite(t)||t<=0?0:Math.max(0,Math.min(1,(((r=this.audio)==null?void 0:r.currentTime)??0)/t))}dispatchTypedEvent(t){var i;const r={currentTime:((i=this.audio)==null?void 0:i.currentTime)??0,duration:this.duration};this.dispatchEvent(new CustomEvent(t,{detail:r}))}handleError(t,r){this.button.disabled=!0,this.setStatus("");const i={message:r instanceof Error?`${t} ${r.message}`:t,cause:r};this.errorEl.textContent=i.message,this.errorEl.classList.remove("hidden"),this.dispatchEvent(new CustomEvent("error",{detail:i}))}clearError(){this.errorEl.textContent="",this.errorEl.classList.add("hidden")}setStatus(t){this.statusEl.textContent=t}getCanvasWidth(){return this.clientWidth||this.getBoundingClientRect().width||640}getPaneHeights(){if(!this.showWaveform&&!this.showSpectrogram)return{waveformHeight:0,spectrogramHeight:0};const t=this.hasAttribute("height"),r=this.hasAttribute("waveform-height"),i=this.hasAttribute("spectrogram-height");if(!t)return{waveformHeight:this.showWaveform?this.waveformHeight:0,spectrogramHeight:this.showSpectrogram?this.spectrogramHeight:0};const s=this.height;return this.showWaveform&&!this.showSpectrogram?{waveformHeight:r?this.waveformHeight:s,spectrogramHeight:0}:!this.showWaveform&&this.showSpectrogram?{waveformHeight:0,spectrogramHeight:i?this.spectrogramHeight:s}:r&&i?{waveformHeight:this.waveformHeight,spectrogramHeight:this.spectrogramHeight}:r?{waveformHeight:this.waveformHeight,spectrogramHeight:Math.max(1,s-this.waveformHeight)}:i?{waveformHeight:Math.max(1,s-this.spectrogramHeight),spectrogramHeight:this.spectrogramHeight}:{waveformHeight:Math.max(1,Math.round(s*(80/200))),spectrogramHeight:Math.max(1,s-Math.round(s*(80/200)))}}getNumberAttribute(t,r){const i=Number(this.getAttribute(t));return Number.isFinite(i)&&i>0?i:r}getOptionalNumberAttribute(t){if(!this.hasAttribute(t))return;const r=Number(this.getAttribute(t));return Number.isFinite(r)&&r>0?r:void 0}getBooleanAttribute(t,r){if(!this.hasAttribute(t))return r;const i=this.getAttribute(t);return i===""||i==="true"||i===t}setBooleanAttribute(t,r){r?this.setAttribute(t,""):this.setAttribute(t,"false")}cssVar(t,r){return getComputedStyle(this).getPropertyValue(t).trim()||r}cssNumberVar(t,r){const i=Number(getComputedStyle(this).getPropertyValue(t).trim());return Number.isFinite(i)?i:r}requireElement(t){const r=this.root.querySelector(t);if(!r)throw new Error(`Missing template element: ${t}`);return r}waitForAudioReady(t){return t.readyState>=HTMLMediaElement.HAVE_METADATA?Promise.resolve():new Promise((r,i)=>{const s=()=>{t.removeEventListener("loadedmetadata",a),t.removeEventListener("error",n)},a=()=>{s(),r()},n=()=>{s(),i(t.error??new Error("Audio metadata failed to load."))};t.addEventListener("loadedmetadata",a,{once:!0}),t.addEventListener("error",n,{once:!0}),t.load()})}revokeBlobUrl(){this.blobUrl&&(URL.revokeObjectURL(this.blobUrl),this.blobUrl=void 0)}}c(E,"observedAttributes",["src","height","waveform-height","spectrogram-height","show-waveform","show-spectrogram","show-controls","show-time","waveform-style","waveform-bar-width","waveform-bar-spacing","autoplay","fft-size","hop-size","window-type","min-db","max-db","color-map","channel"]);class V extends E{}customElements.get("wavegram-player")||customElements.define("wavegram-player",E),customElements.get("audio-preview-spectrogram")||customElements.define("audio-preview-spectrogram",V),b.AudioPreviewSpectrogram=V,b.Wavegram=E,Object.defineProperty(b,Symbol.toStringTag,{value:"Module"})}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drawCursor.d.ts","sourceRoot":"","sources":["../../src/render/drawCursor.ts"],"names":[],"mappings":"AAAA,wBAAgB,UAAU,CACxB,MAAM,EAAE,iBAAiB,EACzB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,WAAW,SAAwB,GAClC,IAAI,
|
|
1
|
+
{"version":3,"file":"drawCursor.d.ts","sourceRoot":"","sources":["../../src/render/drawCursor.ts"],"names":[],"mappings":"AAAA,wBAAgB,UAAU,CACxB,MAAM,EAAE,iBAAiB,EACzB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,WAAW,SAAwB,GAClC,IAAI,CA0BN"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drawWaveform.d.ts","sourceRoot":"","sources":["../../src/render/drawWaveform.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE7D,wBAAgB,YAAY,CAC1B,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,aAAa,GAAG,SAAS,EAChC,OAAO,EAAE;IACP,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GACA,IAAI,
|
|
1
|
+
{"version":3,"file":"drawWaveform.d.ts","sourceRoot":"","sources":["../../src/render/drawWaveform.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE7D,wBAAgB,YAAY,CAC1B,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE,aAAa,GAAG,SAAS,EAChC,OAAO,EAAE;IACP,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GACA,IAAI,CAoCN"}
|
package/dist/types.d.ts
CHANGED
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,SAAS,GAAG,aAAa,CAAC;AAC5D,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;AACjF,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,KAAK,CAAC;AAC9C,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE9E,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,EAAE,YAAY,CAAC;IAClB,GAAG,EAAE,YAAY,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,UAAU,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG,kBAAkB,GAAG;IAC1D,OAAO,EAAE,YAAY,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,SAAS,GAAG,aAAa,CAAC;AAC5D,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;AACjF,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,KAAK,CAAC;AAC9C,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE9E,MAAM,MAAM,aAAa,GAAG;IAC1B,GAAG,EAAE,YAAY,CAAC;IAClB,GAAG,EAAE,YAAY,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,YAAY,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,UAAU,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG,kBAAkB,GAAG;IAC1D,OAAO,EAAE,YAAY,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC"}
|