wavesurfer.js 7.0.0-beta.1 → 7.0.0-beta.10
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/LICENSE +29 -0
- package/README.md +81 -36
- package/dist/decoder.d.ts +1 -1
- package/dist/draggable.d.ts +1 -0
- package/dist/draggable.js +59 -0
- package/dist/fetcher.d.ts +2 -0
- package/dist/fetcher.js +4 -0
- package/dist/player.d.ts +1 -1
- package/dist/player.js +2 -2
- package/dist/plugins/envelope.js +4 -25
- package/dist/plugins/envelope.min.cjs +1 -0
- package/dist/plugins/minimap.js +0 -3
- package/dist/plugins/minimap.min.cjs +1 -0
- package/dist/plugins/record.d.ts +3 -1
- package/dist/plugins/record.js +11 -5
- package/dist/plugins/record.min.cjs +1 -0
- package/dist/plugins/regions.d.ts +1 -0
- package/dist/plugins/regions.js +17 -52
- package/dist/plugins/regions.min.cjs +1 -0
- package/dist/plugins/spectrogram-fft.d.ts +9 -0
- package/dist/plugins/spectrogram-fft.js +150 -0
- package/dist/plugins/spectrogram.d.ts +3 -0
- package/dist/plugins/spectrogram.js +3 -2
- package/dist/plugins/{spectrogram.min.js → spectrogram.min.cjs} +1 -1
- package/dist/plugins/timeline.min.cjs +1 -0
- package/dist/renderer.d.ts +11 -21
- package/dist/renderer.js +213 -136
- package/dist/wavesurfer.d.ts +17 -14
- package/dist/wavesurfer.js +54 -65
- package/dist/wavesurfer.min.cjs +1 -0
- package/package.json +17 -11
- package/dist/plugins/envelope.min.js +0 -1
- package/dist/plugins/minimap.min.js +0 -1
- package/dist/plugins/multitrack.d.ts +0 -117
- package/dist/plugins/multitrack.js +0 -507
- package/dist/plugins/multitrack.min.js +0 -1
- package/dist/plugins/record.min.js +0 -1
- package/dist/plugins/regions.min.js +0 -1
- package/dist/plugins/timeline.min.js +0 -1
- package/dist/wavesurfer.min.js +0 -1
package/dist/plugins/regions.js
CHANGED
|
@@ -4,47 +4,8 @@
|
|
|
4
4
|
* You can set the color and content of each region, as well as their HTML content.
|
|
5
5
|
*/
|
|
6
6
|
import BasePlugin from '../base-plugin.js';
|
|
7
|
+
import { makeDraggable } from '../draggable.js';
|
|
7
8
|
import EventEmitter from '../event-emitter.js';
|
|
8
|
-
function makeDraggable(element, onStart, onMove, onEnd, threshold = 5) {
|
|
9
|
-
if (!element)
|
|
10
|
-
return () => undefined;
|
|
11
|
-
let isDragging = false;
|
|
12
|
-
const onClick = (e) => {
|
|
13
|
-
isDragging && e.stopPropagation();
|
|
14
|
-
};
|
|
15
|
-
const onMouseDown = (e) => {
|
|
16
|
-
e.stopPropagation();
|
|
17
|
-
let x = e.clientX;
|
|
18
|
-
let sumDx = 0;
|
|
19
|
-
onStart(x);
|
|
20
|
-
const onMouseMove = (e) => {
|
|
21
|
-
const newX = e.clientX;
|
|
22
|
-
const dx = newX - x;
|
|
23
|
-
sumDx += dx;
|
|
24
|
-
x = newX;
|
|
25
|
-
if (isDragging || Math.abs(sumDx) >= threshold) {
|
|
26
|
-
onMove(isDragging ? dx : sumDx);
|
|
27
|
-
isDragging = true;
|
|
28
|
-
}
|
|
29
|
-
};
|
|
30
|
-
const onMouseUp = () => {
|
|
31
|
-
if (isDragging) {
|
|
32
|
-
onEnd();
|
|
33
|
-
setTimeout(() => (isDragging = false), 10);
|
|
34
|
-
}
|
|
35
|
-
document.removeEventListener('mousemove', onMouseMove);
|
|
36
|
-
document.removeEventListener('mouseup', onMouseUp);
|
|
37
|
-
};
|
|
38
|
-
document.addEventListener('mousemove', onMouseMove);
|
|
39
|
-
document.addEventListener('mouseup', onMouseUp);
|
|
40
|
-
};
|
|
41
|
-
element.addEventListener('click', onClick);
|
|
42
|
-
element.addEventListener('mousedown', onMouseDown);
|
|
43
|
-
return () => {
|
|
44
|
-
element.removeEventListener('click', onClick);
|
|
45
|
-
element.removeEventListener('mousedown', onMouseDown);
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
9
|
export class Region extends EventEmitter {
|
|
49
10
|
constructor(params, totalDuration) {
|
|
50
11
|
super();
|
|
@@ -126,16 +87,18 @@ export class Region extends EventEmitter {
|
|
|
126
87
|
}
|
|
127
88
|
initMouseEvents() {
|
|
128
89
|
const { element } = this;
|
|
90
|
+
if (!element)
|
|
91
|
+
return;
|
|
129
92
|
element.addEventListener('click', (e) => this.emit('click', e));
|
|
130
93
|
element.addEventListener('mouseenter', (e) => this.emit('over', e));
|
|
131
94
|
element.addEventListener('mouseleave', (e) => this.emit('leave', e));
|
|
132
95
|
element.addEventListener('dblclick', (e) => this.emit('dblclick', e));
|
|
133
96
|
// Drag
|
|
134
|
-
makeDraggable(element, () => this.
|
|
97
|
+
makeDraggable(element, (dx) => this.onMove(dx), () => this.onStartMoving(), () => this.onEndMoving());
|
|
135
98
|
// Resize
|
|
136
99
|
const resizeThreshold = 1;
|
|
137
|
-
makeDraggable(element.querySelector('[data-resize="left"]'), (
|
|
138
|
-
makeDraggable(element.querySelector('[data-resize="right"]'), (
|
|
100
|
+
makeDraggable(element.querySelector('[data-resize="left"]'), (dx) => this.onResize(dx, 'start'), () => null, () => this.onEndResizing(), resizeThreshold);
|
|
101
|
+
makeDraggable(element.querySelector('[data-resize="right"]'), (dx) => this.onResize(dx, 'end'), () => null, () => this.onEndResizing(), resizeThreshold);
|
|
139
102
|
}
|
|
140
103
|
onStartMoving() {
|
|
141
104
|
if (!this.drag)
|
|
@@ -291,6 +254,9 @@ class RegionsPlugin extends BasePlugin {
|
|
|
291
254
|
region.on('click', (e) => {
|
|
292
255
|
this.emit('region-clicked', region, e);
|
|
293
256
|
}),
|
|
257
|
+
region.on('dblclick', (e) => {
|
|
258
|
+
this.emit('region-double-clicked', region, e);
|
|
259
|
+
}),
|
|
294
260
|
// Remove the region from the list when it's removed
|
|
295
261
|
region.once('remove', () => {
|
|
296
262
|
regionSubscriptions.forEach((unsubscribe) => unsubscribe());
|
|
@@ -307,7 +273,7 @@ class RegionsPlugin extends BasePlugin {
|
|
|
307
273
|
const duration = this.wavesurfer.getDuration();
|
|
308
274
|
const region = new Region(options, duration);
|
|
309
275
|
if (!duration) {
|
|
310
|
-
this.subscriptions.push(this.wavesurfer.once('
|
|
276
|
+
this.subscriptions.push(this.wavesurfer.once('ready', (duration) => {
|
|
311
277
|
region._setTotalDuration(duration);
|
|
312
278
|
this.saveRegion(region);
|
|
313
279
|
}));
|
|
@@ -326,20 +292,17 @@ class RegionsPlugin extends BasePlugin {
|
|
|
326
292
|
if (!wrapper)
|
|
327
293
|
return () => undefined;
|
|
328
294
|
let region = null;
|
|
329
|
-
let startX = 0;
|
|
330
295
|
let sumDx = 0;
|
|
331
296
|
return makeDraggable(wrapper,
|
|
332
|
-
// On
|
|
333
|
-
(x) =>
|
|
334
|
-
// On mousemove
|
|
335
|
-
(dx) => {
|
|
297
|
+
// On drag move
|
|
298
|
+
(dx, _, x) => {
|
|
336
299
|
if (!this.wavesurfer)
|
|
337
300
|
return;
|
|
338
301
|
if (!region) {
|
|
339
302
|
const duration = this.wavesurfer.getDuration();
|
|
340
303
|
const box = wrapper.getBoundingClientRect();
|
|
341
|
-
let start = (
|
|
342
|
-
let end = ((
|
|
304
|
+
let start = (x / box.width) * duration;
|
|
305
|
+
let end = ((x - box.left) / box.width) * duration;
|
|
343
306
|
if (start > end)
|
|
344
307
|
[start, end] = [end, start];
|
|
345
308
|
region = new Region({
|
|
@@ -355,7 +318,9 @@ class RegionsPlugin extends BasePlugin {
|
|
|
355
318
|
privateRegion.onUpdate(dx, [sumDx > 0 ? 'end' : 'start']);
|
|
356
319
|
}
|
|
357
320
|
},
|
|
358
|
-
// On
|
|
321
|
+
// On drag start
|
|
322
|
+
() => null,
|
|
323
|
+
// On drag end
|
|
359
324
|
() => {
|
|
360
325
|
if (region) {
|
|
361
326
|
this.saveRegion(region);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.Regions=t():e.Regions=t()}(WaveSurfer,(()=>(()=>{"use strict";var e={d:(t,i)=>{for(var n in i)e.o(i,n)&&!e.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:i[n]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t)},t={};e.d(t,{default:()=>a});const i=class{constructor(){this.listeners={}}on(e,t){return this.listeners[e]||(this.listeners[e]=new Set),this.listeners[e].add(t),()=>this.un(e,t)}once(e,t){const i=this.on(e,t),n=this.on(e,(()=>{i(),n()}));return i}un(e,t){this.listeners[e]&&(t?this.listeners[e].delete(t):delete this.listeners[e])}unAll(){this.listeners={}}emit(e,...t){this.listeners[e]&&this.listeners[e].forEach((e=>e(...t)))}},n=class extends i{constructor(e){super(),this.subscriptions=[],this.options=e}onInit(){}init(e){this.wavesurfer=e,this.onInit()}destroy(){this.subscriptions.forEach((e=>e()))}};function s(e,t,i,n,s=5){let r=()=>{};if(!e)return r;const o=o=>{o.preventDefault(),o.stopPropagation();let a=o.clientX,l=o.clientY,d=!1;const h=n=>{n.preventDefault(),n.stopPropagation();const r=n.clientX,o=n.clientY;if(d||Math.abs(r-a)>=s||Math.abs(o-l)>=s){d||(d=!0,i?.(a,l));const{left:n,top:s}=e.getBoundingClientRect();t(r-a,o-l,r-n,o-s),a=r,l=o}},c=e=>{d&&(e.preventDefault(),e.stopPropagation())},u=()=>{d&&n?.(),r()};r=()=>{document.removeEventListener("pointermove",h),document.removeEventListener("pointerup",u),document.removeEventListener("pointerleave",u),setTimeout((()=>{document.removeEventListener("click",c,!0)}),10)},document.addEventListener("pointermove",h),document.addEventListener("pointerup",u),document.addEventListener("pointerleave",u),document.addEventListener("click",c,!0)};return e.addEventListener("pointerdown",o),()=>{r(),e.removeEventListener("pointerdown",o)}}class r extends i{constructor(e,t){super(),this.totalDuration=t,this.id=e.id||`region-${Math.random().toString(32).slice(2)}`,this.start=e.start,this.end=e.end??e.start,this.drag=e.drag??!0,this.resize=e.resize??!0,this.color=e.color??"rgba(0, 0, 0, 0.1)",this.element=this.initElement(e.content),this.renderPosition(),this.initMouseEvents()}initElement(e){const t=document.createElement("div"),i=this.start===this.end;if(t.setAttribute("part",`${i?"marker":"region"} ${this.id}`),t.setAttribute("style",`\n position: absolute;\n height: 100%;\n background-color: ${i?"none":this.color};\n border-left: ${i?"2px solid "+this.color:"none"};\n border-radius: 2px;\n box-sizing: border-box;\n transition: background-color 0.2s ease;\n cursor: ${this.drag?"grab":"default"};\n pointer-events: all;\n padding: 0.2em ${i?.2:.4}em;\n pointer-events: all;\n `),e&&("string"==typeof e?(this.content=document.createElement("div"),this.content.textContent=e):this.content=e,this.content.setAttribute("part","region-content"),t.appendChild(this.content)),!i){const e=document.createElement("div");e.setAttribute("data-resize","left"),e.setAttribute("style",`\n position: absolute;\n z-index: 2;\n width: 6px;\n height: 100%;\n top: 0;\n left: 0;\n border-left: 2px solid rgba(0, 0, 0, 0.5);\n border-radius: 2px 0 0 2px;\n cursor: ${this.resize?"ew-resize":"default"};\n word-break: keep-all;\n `),e.setAttribute("part","region-handle region-handle-left");const i=e.cloneNode();i.setAttribute("data-resize","right"),i.style.left="",i.style.right="0",i.style.borderRight=i.style.borderLeft,i.style.borderLeft="",i.style.borderRadius="0 2px 2px 0",i.setAttribute("part","region-handle region-handle-right"),t.appendChild(e),t.appendChild(i)}return t}renderPosition(){const e=this.start/this.totalDuration,t=this.end/this.totalDuration;this.element.style.left=100*e+"%",this.element.style.width=100*(t-e)+"%"}initMouseEvents(){const{element:e}=this;e&&(e.addEventListener("click",(e=>this.emit("click",e))),e.addEventListener("mouseenter",(e=>this.emit("over",e))),e.addEventListener("mouseleave",(e=>this.emit("leave",e))),e.addEventListener("dblclick",(e=>this.emit("dblclick",e))),s(e,(e=>this.onMove(e)),(()=>this.onStartMoving()),(()=>this.onEndMoving())),s(e.querySelector('[data-resize="left"]'),(e=>this.onResize(e,"start")),(()=>null),(()=>this.onEndResizing()),1),s(e.querySelector('[data-resize="right"]'),(e=>this.onResize(e,"end")),(()=>null),(()=>this.onEndResizing()),1))}onStartMoving(){this.drag&&(this.element.style.cursor="grabbing")}onEndMoving(){this.drag&&(this.element.style.cursor="grab",this.emit("update-end"))}onUpdate(e,t){if(!this.element.parentElement)return;const i=e/this.element.parentElement.clientWidth*this.totalDuration;t.forEach((e=>{this[e]+=i,"start"===e?this.start=Math.max(0,Math.min(this.start,this.end)):this.end=Math.max(this.start,Math.min(this.end,this.totalDuration))})),this.renderPosition(),this.emit("update")}onMove(e){this.drag&&this.onUpdate(e,["start","end"])}onResize(e,t){this.resize&&this.onUpdate(e,[t])}onEndResizing(){this.resize&&this.emit("update-end")}_setTotalDuration(e){this.totalDuration=e,this.renderPosition()}play(){this.emit("play")}setOptions(e){e.color&&(this.color=e.color,this.element.style.backgroundColor=this.color),void 0!==e.drag&&(this.drag=e.drag,this.element.style.cursor=this.drag?"grab":"default"),void 0!==e.resize&&(this.resize=e.resize,this.element.querySelectorAll("[data-resize]").forEach((e=>{e.style.cursor=this.resize?"ew-resize":"default"}))),void 0===e.start&&void 0===e.end||(this.start=e.start??this.start,this.end=e.end??this.end,this.renderPosition())}remove(){this.emit("remove"),this.element.remove(),this.element=null}}class o extends n{constructor(e){super(e),this.regions=[],this.regionsContainer=this.initRegionsContainer()}static create(e){return new o(e)}onInit(){if(!this.wavesurfer)throw Error("WaveSurfer is not initialized");this.wavesurfer.getWrapper().appendChild(this.regionsContainer)}initRegionsContainer(){const e=document.createElement("div");return e.setAttribute("style","\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n z-index: 3;\n pointer-events: none;\n "),e}getRegions(){return this.regions}avoidOverlapping(e){if(!e.content)return;const t=e.content,i=t.getBoundingClientRect().left,n=e.element.scrollWidth,s=this.regions.filter((t=>{if(t===e||!t.content)return!1;const s=t.content.getBoundingClientRect().left,r=t.element.scrollWidth;return i<s+r&&s<i+n})).map((e=>e.content?.getBoundingClientRect().height||0)).reduce(((e,t)=>e+t),0);t.style.marginTop=`${s}px`}saveRegion(e){this.regionsContainer.appendChild(e.element),this.avoidOverlapping(e),this.regions.push(e),this.emit("region-created",e);const t=[e.on("update-end",(()=>{this.avoidOverlapping(e),this.emit("region-updated",e)})),e.on("play",(()=>{this.wavesurfer?.play(),this.wavesurfer?.setTime(e.start)})),e.on("click",(t=>{this.emit("region-clicked",e,t)})),e.on("dblclick",(t=>{this.emit("region-double-clicked",e,t)})),e.once("remove",(()=>{t.forEach((e=>e())),this.regions=this.regions.filter((t=>t!==e))}))];this.subscriptions.push(...t)}addRegion(e){if(!this.wavesurfer)throw Error("WaveSurfer is not initialized");const t=this.wavesurfer.getDuration(),i=new r(e,t);return t?this.saveRegion(i):this.subscriptions.push(this.wavesurfer.once("ready",(e=>{i._setTotalDuration(e),this.saveRegion(i)}))),i}enableDragSelection(e){const t=this.wavesurfer?.getWrapper()?.querySelector("div");if(!t)return()=>{};let i=null,n=0;return s(t,((s,o,a)=>{if(this.wavesurfer){if(!i){const n=this.wavesurfer.getDuration(),s=t.getBoundingClientRect();let o=a/s.width*n,l=(a-s.left)/s.width*n;o>l&&([o,l]=[l,o]),i=new r({...e,start:o,end:l},n),this.regionsContainer.appendChild(i.element)}n+=s,i&&i.onUpdate(s,[n>0?"end":"start"])}}),(()=>null),(()=>{if(i&&(this.saveRegion(i),i=null,n=0,this.wavesurfer)){const{interact:e}=this.wavesurfer.options;e&&(this.wavesurfer.toggleInteraction(!1),setTimeout((()=>this.wavesurfer?.toggleInteraction(e)),10))}}))}clearRegions(){this.regions.forEach((e=>e.remove()))}destroy(){this.clearRegions(),super.destroy()}}const a=o;return t.default})()));
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Calculate FFT - Based on https://github.com/corbanbrook/dsp.js
|
|
3
|
+
*
|
|
4
|
+
* @param {Number} bufferSize Buffer size
|
|
5
|
+
* @param {Number} sampleRate Sample rate
|
|
6
|
+
* @param {Function} windowFunc Window function
|
|
7
|
+
* @param {Number} alpha Alpha channel
|
|
8
|
+
*/
|
|
9
|
+
export default function FFT(bufferSize: any, sampleRate: any, windowFunc: any, alpha: any): void;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
/**
|
|
3
|
+
* Calculate FFT - Based on https://github.com/corbanbrook/dsp.js
|
|
4
|
+
*
|
|
5
|
+
* @param {Number} bufferSize Buffer size
|
|
6
|
+
* @param {Number} sampleRate Sample rate
|
|
7
|
+
* @param {Function} windowFunc Window function
|
|
8
|
+
* @param {Number} alpha Alpha channel
|
|
9
|
+
*/
|
|
10
|
+
export default function FFT(bufferSize, sampleRate, windowFunc, alpha) {
|
|
11
|
+
this.bufferSize = bufferSize;
|
|
12
|
+
this.sampleRate = sampleRate;
|
|
13
|
+
this.bandwidth = (2 / bufferSize) * (sampleRate / 2);
|
|
14
|
+
this.sinTable = new Float32Array(bufferSize);
|
|
15
|
+
this.cosTable = new Float32Array(bufferSize);
|
|
16
|
+
this.windowValues = new Float32Array(bufferSize);
|
|
17
|
+
this.reverseTable = new Uint32Array(bufferSize);
|
|
18
|
+
this.peakBand = 0;
|
|
19
|
+
this.peak = 0;
|
|
20
|
+
var i;
|
|
21
|
+
switch (windowFunc) {
|
|
22
|
+
case 'bartlett':
|
|
23
|
+
for (i = 0; i < bufferSize; i++) {
|
|
24
|
+
this.windowValues[i] = (2 / (bufferSize - 1)) * ((bufferSize - 1) / 2 - Math.abs(i - (bufferSize - 1) / 2));
|
|
25
|
+
}
|
|
26
|
+
break;
|
|
27
|
+
case 'bartlettHann':
|
|
28
|
+
for (i = 0; i < bufferSize; i++) {
|
|
29
|
+
this.windowValues[i] =
|
|
30
|
+
0.62 - 0.48 * Math.abs(i / (bufferSize - 1) - 0.5) - 0.38 * Math.cos((Math.PI * 2 * i) / (bufferSize - 1));
|
|
31
|
+
}
|
|
32
|
+
break;
|
|
33
|
+
case 'blackman':
|
|
34
|
+
alpha = alpha || 0.16;
|
|
35
|
+
for (i = 0; i < bufferSize; i++) {
|
|
36
|
+
this.windowValues[i] =
|
|
37
|
+
(1 - alpha) / 2 -
|
|
38
|
+
0.5 * Math.cos((Math.PI * 2 * i) / (bufferSize - 1)) +
|
|
39
|
+
(alpha / 2) * Math.cos((4 * Math.PI * i) / (bufferSize - 1));
|
|
40
|
+
}
|
|
41
|
+
break;
|
|
42
|
+
case 'cosine':
|
|
43
|
+
for (i = 0; i < bufferSize; i++) {
|
|
44
|
+
this.windowValues[i] = Math.cos((Math.PI * i) / (bufferSize - 1) - Math.PI / 2);
|
|
45
|
+
}
|
|
46
|
+
break;
|
|
47
|
+
case 'gauss':
|
|
48
|
+
alpha = alpha || 0.25;
|
|
49
|
+
for (i = 0; i < bufferSize; i++) {
|
|
50
|
+
this.windowValues[i] = Math.pow(Math.E, -0.5 * Math.pow((i - (bufferSize - 1) / 2) / ((alpha * (bufferSize - 1)) / 2), 2));
|
|
51
|
+
}
|
|
52
|
+
break;
|
|
53
|
+
case 'hamming':
|
|
54
|
+
for (i = 0; i < bufferSize; i++) {
|
|
55
|
+
this.windowValues[i] = 0.54 - 0.46 * Math.cos((Math.PI * 2 * i) / (bufferSize - 1));
|
|
56
|
+
}
|
|
57
|
+
break;
|
|
58
|
+
case 'hann':
|
|
59
|
+
case undefined:
|
|
60
|
+
for (i = 0; i < bufferSize; i++) {
|
|
61
|
+
this.windowValues[i] = 0.5 * (1 - Math.cos((Math.PI * 2 * i) / (bufferSize - 1)));
|
|
62
|
+
}
|
|
63
|
+
break;
|
|
64
|
+
case 'lanczoz':
|
|
65
|
+
for (i = 0; i < bufferSize; i++) {
|
|
66
|
+
this.windowValues[i] =
|
|
67
|
+
Math.sin(Math.PI * ((2 * i) / (bufferSize - 1) - 1)) / (Math.PI * ((2 * i) / (bufferSize - 1) - 1));
|
|
68
|
+
}
|
|
69
|
+
break;
|
|
70
|
+
case 'rectangular':
|
|
71
|
+
for (i = 0; i < bufferSize; i++) {
|
|
72
|
+
this.windowValues[i] = 1;
|
|
73
|
+
}
|
|
74
|
+
break;
|
|
75
|
+
case 'triangular':
|
|
76
|
+
for (i = 0; i < bufferSize; i++) {
|
|
77
|
+
this.windowValues[i] = (2 / bufferSize) * (bufferSize / 2 - Math.abs(i - (bufferSize - 1) / 2));
|
|
78
|
+
}
|
|
79
|
+
break;
|
|
80
|
+
default:
|
|
81
|
+
throw Error("No such window function '" + windowFunc + "'");
|
|
82
|
+
}
|
|
83
|
+
var limit = 1;
|
|
84
|
+
var bit = bufferSize >> 1;
|
|
85
|
+
var i;
|
|
86
|
+
while (limit < bufferSize) {
|
|
87
|
+
for (i = 0; i < limit; i++) {
|
|
88
|
+
this.reverseTable[i + limit] = this.reverseTable[i] + bit;
|
|
89
|
+
}
|
|
90
|
+
limit = limit << 1;
|
|
91
|
+
bit = bit >> 1;
|
|
92
|
+
}
|
|
93
|
+
for (i = 0; i < bufferSize; i++) {
|
|
94
|
+
this.sinTable[i] = Math.sin(-Math.PI / i);
|
|
95
|
+
this.cosTable[i] = Math.cos(-Math.PI / i);
|
|
96
|
+
}
|
|
97
|
+
this.calculateSpectrum = function (buffer) {
|
|
98
|
+
// Locally scope variables for speed up
|
|
99
|
+
var bufferSize = this.bufferSize, cosTable = this.cosTable, sinTable = this.sinTable, reverseTable = this.reverseTable, real = new Float32Array(bufferSize), imag = new Float32Array(bufferSize), bSi = 2 / this.bufferSize, sqrt = Math.sqrt, rval, ival, mag, spectrum = new Float32Array(bufferSize / 2);
|
|
100
|
+
var k = Math.floor(Math.log(bufferSize) / Math.LN2);
|
|
101
|
+
if (Math.pow(2, k) !== bufferSize) {
|
|
102
|
+
throw 'Invalid buffer size, must be a power of 2.';
|
|
103
|
+
}
|
|
104
|
+
if (bufferSize !== buffer.length) {
|
|
105
|
+
throw ('Supplied buffer is not the same size as defined FFT. FFT Size: ' +
|
|
106
|
+
bufferSize +
|
|
107
|
+
' Buffer Size: ' +
|
|
108
|
+
buffer.length);
|
|
109
|
+
}
|
|
110
|
+
var halfSize = 1, phaseShiftStepReal, phaseShiftStepImag, currentPhaseShiftReal, currentPhaseShiftImag, off, tr, ti, tmpReal;
|
|
111
|
+
for (var i = 0; i < bufferSize; i++) {
|
|
112
|
+
real[i] = buffer[reverseTable[i]] * this.windowValues[reverseTable[i]];
|
|
113
|
+
imag[i] = 0;
|
|
114
|
+
}
|
|
115
|
+
while (halfSize < bufferSize) {
|
|
116
|
+
phaseShiftStepReal = cosTable[halfSize];
|
|
117
|
+
phaseShiftStepImag = sinTable[halfSize];
|
|
118
|
+
currentPhaseShiftReal = 1;
|
|
119
|
+
currentPhaseShiftImag = 0;
|
|
120
|
+
for (var fftStep = 0; fftStep < halfSize; fftStep++) {
|
|
121
|
+
var i = fftStep;
|
|
122
|
+
while (i < bufferSize) {
|
|
123
|
+
off = i + halfSize;
|
|
124
|
+
tr = currentPhaseShiftReal * real[off] - currentPhaseShiftImag * imag[off];
|
|
125
|
+
ti = currentPhaseShiftReal * imag[off] + currentPhaseShiftImag * real[off];
|
|
126
|
+
real[off] = real[i] - tr;
|
|
127
|
+
imag[off] = imag[i] - ti;
|
|
128
|
+
real[i] += tr;
|
|
129
|
+
imag[i] += ti;
|
|
130
|
+
i += halfSize << 1;
|
|
131
|
+
}
|
|
132
|
+
tmpReal = currentPhaseShiftReal;
|
|
133
|
+
currentPhaseShiftReal = tmpReal * phaseShiftStepReal - currentPhaseShiftImag * phaseShiftStepImag;
|
|
134
|
+
currentPhaseShiftImag = tmpReal * phaseShiftStepImag + currentPhaseShiftImag * phaseShiftStepReal;
|
|
135
|
+
}
|
|
136
|
+
halfSize = halfSize << 1;
|
|
137
|
+
}
|
|
138
|
+
for (var i = 0, N = bufferSize / 2; i < N; i++) {
|
|
139
|
+
rval = real[i];
|
|
140
|
+
ival = imag[i];
|
|
141
|
+
mag = bSi * sqrt(rval * rval + ival * ival);
|
|
142
|
+
if (mag > this.peak) {
|
|
143
|
+
this.peakBand = i;
|
|
144
|
+
this.peak = mag;
|
|
145
|
+
}
|
|
146
|
+
spectrum[i] = mag;
|
|
147
|
+
}
|
|
148
|
+
return spectrum;
|
|
149
|
+
};
|
|
150
|
+
}
|
|
@@ -27,6 +27,9 @@ export type SpectrogramPluginOptions = {
|
|
|
27
27
|
height?: number;
|
|
28
28
|
/** Set to true to display frequency labels. */
|
|
29
29
|
labels?: boolean;
|
|
30
|
+
labelsBackground?: string;
|
|
31
|
+
labelsColor?: string;
|
|
32
|
+
labelsHzColor?: string;
|
|
30
33
|
/** Size of the overlapping window. Must be < fftSamples. Auto deduced from canvas size by default. */
|
|
31
34
|
noverlap?: number;
|
|
32
35
|
/** The window function to be used. */
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
*/
|
|
20
20
|
// @ts-nocheck
|
|
21
21
|
import BasePlugin from '../base-plugin.js';
|
|
22
|
-
import FFT from './spectrogram-fft.
|
|
22
|
+
import FFT from './spectrogram-fft.js';
|
|
23
23
|
export default class SpectrogramPlugin extends BasePlugin {
|
|
24
24
|
static create(options) {
|
|
25
25
|
return new SpectrogramPlugin(options || {});
|
|
@@ -140,6 +140,7 @@ export default class SpectrogramPlugin extends BasePlugin {
|
|
|
140
140
|
// if labels are active
|
|
141
141
|
if (this.options.labels) {
|
|
142
142
|
const labelsEl = document.createElement('canvas');
|
|
143
|
+
labelsEl.setAttribute('part', 'spec-labels');
|
|
143
144
|
labelsEl.classList.add('spec-labels');
|
|
144
145
|
this.utils.style(labelsEl, {
|
|
145
146
|
position: 'absolute',
|
|
@@ -180,7 +181,7 @@ export default class SpectrogramPlugin extends BasePlugin {
|
|
|
180
181
|
else {
|
|
181
182
|
this.getFrequencies(this.drawSpectrogram);
|
|
182
183
|
}
|
|
183
|
-
this.loadLabels('rgba(68,68,68,0.5)', '12px', '10px', '', '#fff', '#f7f7f7', 'center', '#specLabels');
|
|
184
|
+
this.loadLabels(this.options.labelsBackground || 'rgba(68,68,68,0.5)', '12px', '10px', '', this.options.labelsColor || '#fff', this.options.labelsHzColor || this.options.labelsColor || '#f7f7f7', 'center', '#specLabels');
|
|
184
185
|
}
|
|
185
186
|
getFrequencies(callback) {
|
|
186
187
|
const fftSamples = this.fftSamples;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Spectrogram=e():t.Spectrogram=e()}(WaveSurfer,(()=>(()=>{"use strict";var t={d:(e,s)=>{for(var i in s)t.o(s,i)&&!t.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:s[i]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)},e={};t.d(e,{default:()=>r});const s=class{constructor(){this.listeners={}}on(t,e){return this.listeners[t]||(this.listeners[t]=new Set),this.listeners[t].add(e),()=>this.un(t,e)}once(t,e){const s=this.on(t,e),i=this.on(t,(()=>{s(),i()}));return s}un(t,e){this.listeners[t]&&(e?this.listeners[t].delete(e):delete this.listeners[t])}unAll(){this.listeners={}}emit(t,...e){this.listeners[t]&&this.listeners[t].forEach((t=>t(...e)))}},i=class extends s{constructor(t){super(),this.subscriptions=[],this.options=t}onInit(){}init(t){this.wavesurfer=t,this.onInit()}destroy(){this.subscriptions.forEach((t=>t()))}};function a(t,e,s,i){switch(this.bufferSize=t,this.sampleRate=e,this.bandwidth=2/t*(e/2),this.sinTable=new Float32Array(t),this.cosTable=new Float32Array(t),this.windowValues=new Float32Array(t),this.reverseTable=new Uint32Array(t),this.peakBand=0,this.peak=0,s){case"bartlett":for(a=0;a<t;a++)this.windowValues[a]=2/(t-1)*((t-1)/2-Math.abs(a-(t-1)/2));break;case"bartlettHann":for(a=0;a<t;a++)this.windowValues[a]=.62-.48*Math.abs(a/(t-1)-.5)-.38*Math.cos(2*Math.PI*a/(t-1));break;case"blackman":for(i=i||.16,a=0;a<t;a++)this.windowValues[a]=(1-i)/2-.5*Math.cos(2*Math.PI*a/(t-1))+i/2*Math.cos(4*Math.PI*a/(t-1));break;case"cosine":for(a=0;a<t;a++)this.windowValues[a]=Math.cos(Math.PI*a/(t-1)-Math.PI/2);break;case"gauss":for(i=i||.25,a=0;a<t;a++)this.windowValues[a]=Math.pow(Math.E,-.5*Math.pow((a-(t-1)/2)/(i*(t-1)/2),2));break;case"hamming":for(a=0;a<t;a++)this.windowValues[a]=.54-.46*Math.cos(2*Math.PI*a/(t-1));break;case"hann":case void 0:for(a=0;a<t;a++)this.windowValues[a]=.5*(1-Math.cos(2*Math.PI*a/(t-1)));break;case"lanczoz":for(a=0;a<t;a++)this.windowValues[a]=Math.sin(Math.PI*(2*a/(t-1)-1))/(Math.PI*(2*a/(t-1)-1));break;case"rectangular":for(a=0;a<t;a++)this.windowValues[a]=1;break;case"triangular":for(a=0;a<t;a++)this.windowValues[a]=2/t*(t/2-Math.abs(a-(t-1)/2));break;default:throw Error("No such window function '"+s+"'")}for(var a,r=1,n=t>>1;r<t;){for(a=0;a<r;a++)this.reverseTable[a+r]=this.reverseTable[a]+n;r<<=1,n>>=1}for(a=0;a<t;a++)this.sinTable[a]=Math.sin(-Math.PI/a),this.cosTable[a]=Math.cos(-Math.PI/a);this.calculateSpectrum=function(t){var e,s,i,a=this.bufferSize,r=this.cosTable,n=this.sinTable,h=this.reverseTable,l=new Float32Array(a),o=new Float32Array(a),c=2/this.bufferSize,f=Math.sqrt,p=new Float32Array(a/2),u=Math.floor(Math.log(a)/Math.LN2);if(Math.pow(2,u)!==a)throw"Invalid buffer size, must be a power of 2.";if(a!==t.length)throw"Supplied buffer is not the same size as defined FFT. FFT Size: "+a+" Buffer Size: "+t.length;for(var d,w,M,
|
|
1
|
+
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Spectrogram=e():t.Spectrogram=e()}(WaveSurfer,(()=>(()=>{"use strict";var t={d:(e,s)=>{for(var i in s)t.o(s,i)&&!t.o(e,i)&&Object.defineProperty(e,i,{enumerable:!0,get:s[i]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)},e={};t.d(e,{default:()=>r});const s=class{constructor(){this.listeners={}}on(t,e){return this.listeners[t]||(this.listeners[t]=new Set),this.listeners[t].add(e),()=>this.un(t,e)}once(t,e){const s=this.on(t,e),i=this.on(t,(()=>{s(),i()}));return s}un(t,e){this.listeners[t]&&(e?this.listeners[t].delete(e):delete this.listeners[t])}unAll(){this.listeners={}}emit(t,...e){this.listeners[t]&&this.listeners[t].forEach((t=>t(...e)))}},i=class extends s{constructor(t){super(),this.subscriptions=[],this.options=t}onInit(){}init(t){this.wavesurfer=t,this.onInit()}destroy(){this.subscriptions.forEach((t=>t()))}};function a(t,e,s,i){switch(this.bufferSize=t,this.sampleRate=e,this.bandwidth=2/t*(e/2),this.sinTable=new Float32Array(t),this.cosTable=new Float32Array(t),this.windowValues=new Float32Array(t),this.reverseTable=new Uint32Array(t),this.peakBand=0,this.peak=0,s){case"bartlett":for(a=0;a<t;a++)this.windowValues[a]=2/(t-1)*((t-1)/2-Math.abs(a-(t-1)/2));break;case"bartlettHann":for(a=0;a<t;a++)this.windowValues[a]=.62-.48*Math.abs(a/(t-1)-.5)-.38*Math.cos(2*Math.PI*a/(t-1));break;case"blackman":for(i=i||.16,a=0;a<t;a++)this.windowValues[a]=(1-i)/2-.5*Math.cos(2*Math.PI*a/(t-1))+i/2*Math.cos(4*Math.PI*a/(t-1));break;case"cosine":for(a=0;a<t;a++)this.windowValues[a]=Math.cos(Math.PI*a/(t-1)-Math.PI/2);break;case"gauss":for(i=i||.25,a=0;a<t;a++)this.windowValues[a]=Math.pow(Math.E,-.5*Math.pow((a-(t-1)/2)/(i*(t-1)/2),2));break;case"hamming":for(a=0;a<t;a++)this.windowValues[a]=.54-.46*Math.cos(2*Math.PI*a/(t-1));break;case"hann":case void 0:for(a=0;a<t;a++)this.windowValues[a]=.5*(1-Math.cos(2*Math.PI*a/(t-1)));break;case"lanczoz":for(a=0;a<t;a++)this.windowValues[a]=Math.sin(Math.PI*(2*a/(t-1)-1))/(Math.PI*(2*a/(t-1)-1));break;case"rectangular":for(a=0;a<t;a++)this.windowValues[a]=1;break;case"triangular":for(a=0;a<t;a++)this.windowValues[a]=2/t*(t/2-Math.abs(a-(t-1)/2));break;default:throw Error("No such window function '"+s+"'")}for(var a,r=1,n=t>>1;r<t;){for(a=0;a<r;a++)this.reverseTable[a+r]=this.reverseTable[a]+n;r<<=1,n>>=1}for(a=0;a<t;a++)this.sinTable[a]=Math.sin(-Math.PI/a),this.cosTable[a]=Math.cos(-Math.PI/a);this.calculateSpectrum=function(t){var e,s,i,a=this.bufferSize,r=this.cosTable,n=this.sinTable,h=this.reverseTable,l=new Float32Array(a),o=new Float32Array(a),c=2/this.bufferSize,f=Math.sqrt,p=new Float32Array(a/2),u=Math.floor(Math.log(a)/Math.LN2);if(Math.pow(2,u)!==a)throw"Invalid buffer size, must be a power of 2.";if(a!==t.length)throw"Supplied buffer is not the same size as defined FFT. FFT Size: "+a+" Buffer Size: "+t.length;for(var d,w,b,M,g,m,y,v,x=1,S=0;S<a;S++)l[S]=t[h[S]]*this.windowValues[h[S]],o[S]=0;for(;x<a;){d=r[x],w=n[x],b=1,M=0;for(var k=0;k<x;k++){for(S=k;S<a;)m=b*l[g=S+x]-M*o[g],y=b*o[g]+M*l[g],l[g]=l[S]-m,o[g]=o[S]-y,l[S]+=m,o[S]+=y,S+=x<<1;b=(v=b)*d-M*w,M=v*w+M*d}x<<=1}S=0;for(var q=a/2;S<q;S++)(i=c*f((e=l[S])*e+(s=o[S])*s))>this.peak&&(this.peakBand=S,this.peak=i),p[S]=i;return p}}class r extends i{static create(t){return new r(t||{})}constructor(t){if(super(t),this.utils={style:(t,e)=>Object.assign(t.style,e)},this.drawSpectrogram=t=>{isNaN(t[0][0])||(t=[t]);const e=this.spectrCc,s=this.height,i=this.width,a=this.buffer.sampleRate/2,r=this.frequencyMin,n=this.frequencyMax;if(e){for(let h=0;h<t.length;h++){const l=this.resample(t[h]),o=new ImageData(i,s);for(let t=0;t<l.length;t++)for(let e=0;e<l[t].length;e++){const a=this.colorMap[l[t][e]],r=4*((s-e)*i+t);o.data[r]=255*a[0],o.data[r+1]=255*a[1],o.data[r+2]=255*a[2],o.data[r+3]=255*a[3]}createImageBitmap(o).then((t=>{e.drawImage(t,0,s*(1-n/a),i,s*(n-r)/a,0,s*h,i,s)}))}this.emit("ready")}},this.frequenciesDataUrl=t.frequenciesDataUrl,this.container="string"==typeof t.container?document.querySelector(t.container):t.container,t.colorMap){if(t.colorMap.length<256)throw new Error("Colormap must contain 256 elements");for(let e=0;e<t.colorMap.length;e++)if(4!==t.colorMap[e].length)throw new Error("ColorMap entries must contain 4 values");this.colorMap=t.colorMap}else{this.colorMap=[];for(let t=0;t<256;t++){const e=(255-t)/256;this.colorMap.push([e,e,e,1])}}this.fftSamples=t.fftSamples||512,this.height=t.height||this.fftSamples/2,this.noverlap=t.noverlap,this.windowFunc=t.windowFunc,this.alpha=t.alpha,this.channels=1,this.frequencyMin=t.frequencyMin||0,this.frequencyMax=t.frequencyMax||0,this.createWrapper(),this.createCanvas()}onInit(){this.container=this.container||this.wavesurfer.getWrapper(),this.container.appendChild(this.wrapper),this.wavesurfer.options.fillParent&&this.utils.style(this.wrapper,{width:"100%",overflowX:"hidden",overflowY:"hidden"}),this.width=this.wavesurfer.getWrapper().offsetWidth,this.subscriptions.push(this.wavesurfer.on("redraw",(()=>this.render())))}destroy(){this.unAll(),this.wavesurfer.un("ready",this._onReady),this.wavesurfer.un("redraw",this._onRender),this.wavesurfer=null,this.util=null,this.options=null,this.wrapper&&(this.wrapper.remove(),this.wrapper=null)}createWrapper(){if(this.wrapper=document.createElement("div"),this.utils.style(this.wrapper,{display:"block",position:"relative",userSelect:"none",webkitUserSelect:"none",height:this.height*this.channels+"px"}),this.options.labels){const t=document.createElement("canvas");t.setAttribute("part","spec-labels"),t.classList.add("spec-labels"),this.utils.style(t,{position:"absolute",zIndex:9,width:"55px",height:"100%"}),this.wrapper.appendChild(t),this.labelsEl=t}this.wrapper.addEventListener("click",this._onWrapperClick)}_wrapperClickHandler(t){t.preventDefault();const e="offsetX"in t?t.offsetX:t.layerX;this.emit("click",e/this.width||0)}createCanvas(){const t=document.createElement("canvas");this.wrapper.appendChild(t),this.spectrCc=t.getContext("2d"),this.utils.style(t,{position:"absolute",left:0,top:0,width:"100%",height:"100%",zIndex:4}),this.canvas=t}render(){this.canvas.width=this.width,this.canvas.height=this.height,this.frequenciesDataUrl?this.loadFrequenciesData(this.frequenciesDataUrl):this.getFrequencies(this.drawSpectrogram),this.loadLabels(this.options.labelsBackground||"rgba(68,68,68,0.5)","12px","10px","",this.options.labelsColor||"#fff",this.options.labelsHzColor||this.options.labelsColor||"#f7f7f7","center","#specLabels")}getFrequencies(t){const e=this.fftSamples,s=this.wavesurfer.getDecodedData(),i=this.channels;if(this.frequencyMax=this.frequencyMax||s.sampleRate/2,!s)return;this.buffer=s;const r=s.sampleRate,n=[];let h=this.noverlap;if(!h){const t=s.length/this.canvas.width;h=Math.max(0,Math.round(e-t))}const l=new a(e,r,this.windowFunc,this.alpha);for(let t=0;t<i;t++){const i=s.getChannelData(t),a=[];let r=0;for(;r+e<i.length;){const t=i.slice(r,r+e),s=l.calculateSpectrum(t),n=new Uint8Array(e/2);let o;for(o=0;o<e/2;o++)n[o]=Math.max(-255,45*Math.log10(s[o]));a.push(n),r+=e-h}n.push(a)}t(n,this)}loadFrequenciesData(t){return fetch(t).then((t=>t.json())).then(this.drawSpectrogram)}freqType(t){return t>=1e3?(t/1e3).toFixed(1):Math.round(t)}unitType(t){return t>=1e3?"KHz":"Hz"}loadLabels(t,e,s,i,a,r,n,h){t=t||"rgba(68,68,68,0)",e=e||"12px",s=s||"10px",i=i||"Helvetica",a=a||"#fff",r=r||"#fff",n=n||"center",h=h||"#specLabels";const l=this.height||512,o=l/256*5,c=this.frequencyMin,f=(this.frequencyMax-c)/o,p=this.labelsEl.getContext("2d"),u=window.devicePixelRatio;if(this.labelsEl.height=this.height*this.channels*u,this.labelsEl.width=55*u,p.scale(u,u),p)for(let h=0;h<this.channels;h++){let u;for(p.fillStyle=t,p.fillRect(0,h*l,55,(1+h)*l),p.fill(),u=0;u<=o;u++){p.textAlign=n,p.textBaseline="middle";const t=c+f*u,o=this.freqType(t),d=this.unitType(t),w=2,b=16;let M;0==u?(M=(1+h)*l+u-10,p.fillStyle=r,p.font=s+" "+i,p.fillText(d,b+24,M),p.fillStyle=a,p.font=e+" "+i,p.fillText(o,b,M)):(M=(1+h)*l-50*u+w,p.fillStyle=r,p.font=s+" "+i,p.fillText(d,b+24,M),p.fillStyle=a,p.font=e+" "+i,p.fillText(o,b,M))}}}resample(t){const e=this.width,s=[],i=1/t.length,a=1/e;let r;for(r=0;r<e;r++){const e=new Array(t[0].length);let n;for(n=0;n<t.length;n++){const s=n*i,h=s+i,l=r*a,o=l+a,c=h<=l||o<=s?0:Math.min(Math.max(h,l),Math.max(o,s))-Math.max(Math.min(h,l),Math.min(o,s));let f;if(c>0)for(f=0;f<t[0].length;f++)null==e[f]&&(e[f]=0),e[f]+=c/a*t[n][f]}const h=new Uint8Array(t[0].length);let l;for(l=0;l<t[0].length;l++)h[l]=e[l];s.push(h)}return s}}return e.default})()));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.Timeline=e():t.Timeline=e()}(WaveSurfer,(()=>(()=>{"use strict";var t={d:(e,i)=>{for(var n in i)t.o(i,n)&&!t.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:i[n]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)},e={};t.d(e,{default:()=>o});const i=class{constructor(){this.listeners={}}on(t,e){return this.listeners[t]||(this.listeners[t]=new Set),this.listeners[t].add(e),()=>this.un(t,e)}once(t,e){const i=this.on(t,e),n=this.on(t,(()=>{i(),n()}));return i}un(t,e){this.listeners[t]&&(e?this.listeners[t].delete(e):delete this.listeners[t])}unAll(){this.listeners={}}emit(t,...e){this.listeners[t]&&this.listeners[t].forEach((t=>t(...e)))}},n=class extends i{constructor(t){super(),this.subscriptions=[],this.options=t}onInit(){}init(t){this.wavesurfer=t,this.onInit()}destroy(){this.subscriptions.forEach((t=>t()))}},s={height:20};class r extends n{constructor(t){super(t||{}),this.options=Object.assign({},s,t),this.timelineWrapper=this.initTimelineWrapper()}static create(t){return new r(t)}onInit(){if(!this.wavesurfer)throw Error("WaveSurfer is not initialized");const t=this.options.container??this.wavesurfer.getWrapper();this.options.insertPosition?(t.firstElementChild||t).insertAdjacentElement(this.options.insertPosition,this.timelineWrapper):t.appendChild(this.timelineWrapper),this.options.duration?this.initTimeline(this.options.duration):this.subscriptions.push(this.wavesurfer.on("redraw",(()=>{this.initTimeline(this.wavesurfer?.getDuration()||0)})))}destroy(){this.timelineWrapper.remove(),super.destroy()}initTimelineWrapper(){const t=document.createElement("div");return t.setAttribute("part","timeline"),t}formatTime(t){return t/60>1?`${Math.floor(t/60)}:${(t=Math.round(t%60))<10?"0":""}${t}`:""+Math.round(1e3*t)/1e3}defaultTimeInterval(t){return t>=25?1:5*t>=25?5:15*t>=25?15:60*Math.ceil(.5/t)}defaultPrimaryLabelInterval(t){return t>=25?10:5*t>=25?6:4}defaultSecondaryLabelInterval(t){return t>=25?5:2}initTimeline(t){const e=this.timelineWrapper.scrollWidth/t,i=this.options.timeInterval??this.defaultTimeInterval(e),n=this.options.primaryLabelInterval??this.defaultPrimaryLabelInterval(e),s=this.options.secondaryLabelInterval??this.defaultSecondaryLabelInterval(e),r="beforebegin"===this.options.insertPosition,o=document.createElement("div");if(o.setAttribute("style",`\n height: ${this.options.height}px;\n overflow: hidden;\n display: flex;\n justify-content: space-between;\n align-items: ${r?"flex-start":"flex-end"};\n font-size: ${this.options.height/2}px;\n white-space: nowrap;\n `),r){const t="\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n z-index: 2;\n ";o.setAttribute("style",o.getAttribute("style")+t)}"string"==typeof this.options.style?o.setAttribute("style",o.getAttribute("style")+this.options.style):"object"==typeof this.options.style&&Object.assign(o.style,this.options.style);const l=document.createElement("div");l.setAttribute("style",`\n width: 1px;\n height: 50%;\n display: flex;\n flex-direction: column;\n justify-content: ${r?"flex-start":"flex-end"};\n overflow: visible;\n border-left: 1px solid currentColor;\n opacity: 0.25;\n `);for(let e=0;e<t;e+=i){const t=l.cloneNode(),i=Math.round(100*e)/100%n==0,r=Math.round(100*e)/100%s==0;(i||r)&&(t.style.height="100%",t.style.textIndent="3px",t.textContent=this.formatTime(e),i&&(t.style.opacity="1")),o.appendChild(t)}this.timelineWrapper.innerHTML="",this.timelineWrapper.appendChild(o),this.emit("ready")}}const o=r;return e.default})()));
|
package/dist/renderer.d.ts
CHANGED
|
@@ -1,20 +1,5 @@
|
|
|
1
1
|
import EventEmitter from './event-emitter.js';
|
|
2
|
-
|
|
3
|
-
height: number;
|
|
4
|
-
waveColor: string;
|
|
5
|
-
progressColor: string;
|
|
6
|
-
cursorColor?: string;
|
|
7
|
-
cursorWidth: number;
|
|
8
|
-
minPxPerSec: number;
|
|
9
|
-
fillParent: boolean;
|
|
10
|
-
barWidth?: number;
|
|
11
|
-
barGap?: number;
|
|
12
|
-
barRadius?: number;
|
|
13
|
-
barHeight?: number;
|
|
14
|
-
hideScrollbar?: boolean;
|
|
15
|
-
autoCenter?: boolean;
|
|
16
|
-
autoScroll?: boolean;
|
|
17
|
-
};
|
|
2
|
+
import type { WaveSurferOptions } from './wavesurfer.js';
|
|
18
3
|
type RendererEvents = {
|
|
19
4
|
click: [relativeX: number];
|
|
20
5
|
drag: [relativeX: number];
|
|
@@ -24,27 +9,32 @@ type RendererEvents = {
|
|
|
24
9
|
declare class Renderer extends EventEmitter<RendererEvents> {
|
|
25
10
|
private static MAX_CANVAS_WIDTH;
|
|
26
11
|
private options;
|
|
12
|
+
private parent;
|
|
27
13
|
private container;
|
|
28
14
|
private scrollContainer;
|
|
29
15
|
private wrapper;
|
|
30
16
|
private canvasWrapper;
|
|
31
17
|
private progressWrapper;
|
|
32
18
|
private cursor;
|
|
33
|
-
private
|
|
19
|
+
private timeouts;
|
|
34
20
|
private isScrolling;
|
|
35
21
|
private audioData;
|
|
36
22
|
private resizeObserver;
|
|
37
23
|
private isDragging;
|
|
38
|
-
constructor(
|
|
24
|
+
constructor(options: WaveSurferOptions);
|
|
39
25
|
private initEvents;
|
|
40
26
|
private initDrag;
|
|
27
|
+
private getHeight;
|
|
41
28
|
private initHtml;
|
|
42
|
-
setOptions(options:
|
|
29
|
+
setOptions(options: WaveSurferOptions): void;
|
|
43
30
|
getWrapper(): HTMLElement;
|
|
44
31
|
getScroll(): number;
|
|
45
32
|
destroy(): void;
|
|
46
|
-
private
|
|
47
|
-
private
|
|
33
|
+
private createDelay;
|
|
34
|
+
private convertColorValues;
|
|
35
|
+
private renderBars;
|
|
36
|
+
private renderSingleCanvas;
|
|
37
|
+
private renderWaveform;
|
|
48
38
|
render(audioData: AudioBuffer): void;
|
|
49
39
|
reRender(): void;
|
|
50
40
|
zoom(minPxPerSec: number): void;
|