wavesurfer.js 7.0.0-beta.10 → 7.0.0-beta.12
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 +26 -7
- package/dist/draggable.js +2 -2
- package/dist/fetcher.d.ts +1 -3
- package/dist/fetcher.js +2 -6
- package/dist/player.d.ts +2 -2
- package/dist/player.js +10 -8
- package/dist/plugins/envelope.d.ts +1 -1
- package/dist/plugins/envelope.js +1 -1
- package/dist/plugins/envelope.min.cjs +1 -1
- package/dist/plugins/minimap.d.ts +1 -1
- package/dist/plugins/minimap.js +1 -1
- package/dist/plugins/minimap.min.cjs +1 -1
- package/dist/plugins/record.d.ts +1 -1
- package/dist/plugins/record.js +1 -1
- package/dist/plugins/record.min.cjs +1 -1
- package/dist/plugins/regions.d.ts +2 -2
- package/dist/plugins/regions.js +29 -35
- package/dist/plugins/regions.min.cjs +1 -1
- package/dist/plugins/spectrogram.d.ts +5 -1
- package/dist/plugins/spectrogram.js +164 -20
- package/dist/plugins/spectrogram.min.cjs +1 -1
- package/dist/plugins/timeline.d.ts +1 -1
- package/dist/plugins/timeline.js +1 -1
- package/dist/plugins/timeline.min.cjs +1 -1
- package/dist/renderer.js +5 -4
- package/dist/wavesurfer.d.ts +3 -1
- package/dist/wavesurfer.js +2 -2
- package/dist/wavesurfer.min.cjs +1 -1
- package/package.json +3 -3
- package/dist/plugins/spectrogram-fft.d.ts +0 -9
- package/dist/plugins/spectrogram-fft.js +0 -150
|
@@ -18,9 +18,160 @@
|
|
|
18
18
|
* });
|
|
19
19
|
*/
|
|
20
20
|
// @ts-nocheck
|
|
21
|
+
/**
|
|
22
|
+
* Calculate FFT - Based on https://github.com/corbanbrook/dsp.js
|
|
23
|
+
*
|
|
24
|
+
* @param {Number} bufferSize Buffer size
|
|
25
|
+
* @param {Number} sampleRate Sample rate
|
|
26
|
+
* @param {Function} windowFunc Window function
|
|
27
|
+
* @param {Number} alpha Alpha channel
|
|
28
|
+
*/
|
|
29
|
+
function FFT(bufferSize, sampleRate, windowFunc, alpha) {
|
|
30
|
+
this.bufferSize = bufferSize;
|
|
31
|
+
this.sampleRate = sampleRate;
|
|
32
|
+
this.bandwidth = (2 / bufferSize) * (sampleRate / 2);
|
|
33
|
+
this.sinTable = new Float32Array(bufferSize);
|
|
34
|
+
this.cosTable = new Float32Array(bufferSize);
|
|
35
|
+
this.windowValues = new Float32Array(bufferSize);
|
|
36
|
+
this.reverseTable = new Uint32Array(bufferSize);
|
|
37
|
+
this.peakBand = 0;
|
|
38
|
+
this.peak = 0;
|
|
39
|
+
var i;
|
|
40
|
+
switch (windowFunc) {
|
|
41
|
+
case 'bartlett':
|
|
42
|
+
for (i = 0; i < bufferSize; i++) {
|
|
43
|
+
this.windowValues[i] = (2 / (bufferSize - 1)) * ((bufferSize - 1) / 2 - Math.abs(i - (bufferSize - 1) / 2));
|
|
44
|
+
}
|
|
45
|
+
break;
|
|
46
|
+
case 'bartlettHann':
|
|
47
|
+
for (i = 0; i < bufferSize; i++) {
|
|
48
|
+
this.windowValues[i] =
|
|
49
|
+
0.62 - 0.48 * Math.abs(i / (bufferSize - 1) - 0.5) - 0.38 * Math.cos((Math.PI * 2 * i) / (bufferSize - 1));
|
|
50
|
+
}
|
|
51
|
+
break;
|
|
52
|
+
case 'blackman':
|
|
53
|
+
alpha = alpha || 0.16;
|
|
54
|
+
for (i = 0; i < bufferSize; i++) {
|
|
55
|
+
this.windowValues[i] =
|
|
56
|
+
(1 - alpha) / 2 -
|
|
57
|
+
0.5 * Math.cos((Math.PI * 2 * i) / (bufferSize - 1)) +
|
|
58
|
+
(alpha / 2) * Math.cos((4 * Math.PI * i) / (bufferSize - 1));
|
|
59
|
+
}
|
|
60
|
+
break;
|
|
61
|
+
case 'cosine':
|
|
62
|
+
for (i = 0; i < bufferSize; i++) {
|
|
63
|
+
this.windowValues[i] = Math.cos((Math.PI * i) / (bufferSize - 1) - Math.PI / 2);
|
|
64
|
+
}
|
|
65
|
+
break;
|
|
66
|
+
case 'gauss':
|
|
67
|
+
alpha = alpha || 0.25;
|
|
68
|
+
for (i = 0; i < bufferSize; i++) {
|
|
69
|
+
this.windowValues[i] = Math.pow(Math.E, -0.5 * Math.pow((i - (bufferSize - 1) / 2) / ((alpha * (bufferSize - 1)) / 2), 2));
|
|
70
|
+
}
|
|
71
|
+
break;
|
|
72
|
+
case 'hamming':
|
|
73
|
+
for (i = 0; i < bufferSize; i++) {
|
|
74
|
+
this.windowValues[i] = 0.54 - 0.46 * Math.cos((Math.PI * 2 * i) / (bufferSize - 1));
|
|
75
|
+
}
|
|
76
|
+
break;
|
|
77
|
+
case 'hann':
|
|
78
|
+
case undefined:
|
|
79
|
+
for (i = 0; i < bufferSize; i++) {
|
|
80
|
+
this.windowValues[i] = 0.5 * (1 - Math.cos((Math.PI * 2 * i) / (bufferSize - 1)));
|
|
81
|
+
}
|
|
82
|
+
break;
|
|
83
|
+
case 'lanczoz':
|
|
84
|
+
for (i = 0; i < bufferSize; i++) {
|
|
85
|
+
this.windowValues[i] =
|
|
86
|
+
Math.sin(Math.PI * ((2 * i) / (bufferSize - 1) - 1)) / (Math.PI * ((2 * i) / (bufferSize - 1) - 1));
|
|
87
|
+
}
|
|
88
|
+
break;
|
|
89
|
+
case 'rectangular':
|
|
90
|
+
for (i = 0; i < bufferSize; i++) {
|
|
91
|
+
this.windowValues[i] = 1;
|
|
92
|
+
}
|
|
93
|
+
break;
|
|
94
|
+
case 'triangular':
|
|
95
|
+
for (i = 0; i < bufferSize; i++) {
|
|
96
|
+
this.windowValues[i] = (2 / bufferSize) * (bufferSize / 2 - Math.abs(i - (bufferSize - 1) / 2));
|
|
97
|
+
}
|
|
98
|
+
break;
|
|
99
|
+
default:
|
|
100
|
+
throw Error("No such window function '" + windowFunc + "'");
|
|
101
|
+
}
|
|
102
|
+
var limit = 1;
|
|
103
|
+
var bit = bufferSize >> 1;
|
|
104
|
+
var i;
|
|
105
|
+
while (limit < bufferSize) {
|
|
106
|
+
for (i = 0; i < limit; i++) {
|
|
107
|
+
this.reverseTable[i + limit] = this.reverseTable[i] + bit;
|
|
108
|
+
}
|
|
109
|
+
limit = limit << 1;
|
|
110
|
+
bit = bit >> 1;
|
|
111
|
+
}
|
|
112
|
+
for (i = 0; i < bufferSize; i++) {
|
|
113
|
+
this.sinTable[i] = Math.sin(-Math.PI / i);
|
|
114
|
+
this.cosTable[i] = Math.cos(-Math.PI / i);
|
|
115
|
+
}
|
|
116
|
+
this.calculateSpectrum = function (buffer) {
|
|
117
|
+
// Locally scope variables for speed up
|
|
118
|
+
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);
|
|
119
|
+
var k = Math.floor(Math.log(bufferSize) / Math.LN2);
|
|
120
|
+
if (Math.pow(2, k) !== bufferSize) {
|
|
121
|
+
throw 'Invalid buffer size, must be a power of 2.';
|
|
122
|
+
}
|
|
123
|
+
if (bufferSize !== buffer.length) {
|
|
124
|
+
throw ('Supplied buffer is not the same size as defined FFT. FFT Size: ' +
|
|
125
|
+
bufferSize +
|
|
126
|
+
' Buffer Size: ' +
|
|
127
|
+
buffer.length);
|
|
128
|
+
}
|
|
129
|
+
var halfSize = 1, phaseShiftStepReal, phaseShiftStepImag, currentPhaseShiftReal, currentPhaseShiftImag, off, tr, ti, tmpReal;
|
|
130
|
+
for (var i = 0; i < bufferSize; i++) {
|
|
131
|
+
real[i] = buffer[reverseTable[i]] * this.windowValues[reverseTable[i]];
|
|
132
|
+
imag[i] = 0;
|
|
133
|
+
}
|
|
134
|
+
while (halfSize < bufferSize) {
|
|
135
|
+
phaseShiftStepReal = cosTable[halfSize];
|
|
136
|
+
phaseShiftStepImag = sinTable[halfSize];
|
|
137
|
+
currentPhaseShiftReal = 1;
|
|
138
|
+
currentPhaseShiftImag = 0;
|
|
139
|
+
for (var fftStep = 0; fftStep < halfSize; fftStep++) {
|
|
140
|
+
var i = fftStep;
|
|
141
|
+
while (i < bufferSize) {
|
|
142
|
+
off = i + halfSize;
|
|
143
|
+
tr = currentPhaseShiftReal * real[off] - currentPhaseShiftImag * imag[off];
|
|
144
|
+
ti = currentPhaseShiftReal * imag[off] + currentPhaseShiftImag * real[off];
|
|
145
|
+
real[off] = real[i] - tr;
|
|
146
|
+
imag[off] = imag[i] - ti;
|
|
147
|
+
real[i] += tr;
|
|
148
|
+
imag[i] += ti;
|
|
149
|
+
i += halfSize << 1;
|
|
150
|
+
}
|
|
151
|
+
tmpReal = currentPhaseShiftReal;
|
|
152
|
+
currentPhaseShiftReal = tmpReal * phaseShiftStepReal - currentPhaseShiftImag * phaseShiftStepImag;
|
|
153
|
+
currentPhaseShiftImag = tmpReal * phaseShiftStepImag + currentPhaseShiftImag * phaseShiftStepReal;
|
|
154
|
+
}
|
|
155
|
+
halfSize = halfSize << 1;
|
|
156
|
+
}
|
|
157
|
+
for (var i = 0, N = bufferSize / 2; i < N; i++) {
|
|
158
|
+
rval = real[i];
|
|
159
|
+
ival = imag[i];
|
|
160
|
+
mag = bSi * sqrt(rval * rval + ival * ival);
|
|
161
|
+
if (mag > this.peak) {
|
|
162
|
+
this.peakBand = i;
|
|
163
|
+
this.peak = mag;
|
|
164
|
+
}
|
|
165
|
+
spectrum[i] = mag;
|
|
166
|
+
}
|
|
167
|
+
return spectrum;
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Spectrogram plugin for wavesurfer.
|
|
172
|
+
*/
|
|
21
173
|
import BasePlugin from '../base-plugin.js';
|
|
22
|
-
|
|
23
|
-
export default class SpectrogramPlugin extends BasePlugin {
|
|
174
|
+
export class SpectrogramPlugin extends BasePlugin {
|
|
24
175
|
static create(options) {
|
|
25
176
|
return new SpectrogramPlugin(options || {});
|
|
26
177
|
}
|
|
@@ -181,7 +332,7 @@ export default class SpectrogramPlugin extends BasePlugin {
|
|
|
181
332
|
else {
|
|
182
333
|
this.getFrequencies(this.drawSpectrogram);
|
|
183
334
|
}
|
|
184
|
-
this.loadLabels(this.options.labelsBackground
|
|
335
|
+
this.loadLabels(this.options.labelsBackground, '12px', '12px', '', this.options.labelsColor, this.options.labelsHzColor || this.options.labelsColor, 'center', '#specLabels');
|
|
185
336
|
}
|
|
186
337
|
getFrequencies(callback) {
|
|
187
338
|
const fftSamples = this.fftSamples;
|
|
@@ -237,7 +388,7 @@ export default class SpectrogramPlugin extends BasePlugin {
|
|
|
237
388
|
const frequenciesHeight = this.height;
|
|
238
389
|
bgFill = bgFill || 'rgba(68,68,68,0)';
|
|
239
390
|
fontSizeFreq = fontSizeFreq || '12px';
|
|
240
|
-
fontSizeUnit = fontSizeUnit || '
|
|
391
|
+
fontSizeUnit = fontSizeUnit || '12px';
|
|
241
392
|
fontType = fontType || 'Helvetica';
|
|
242
393
|
textColorFreq = textColorFreq || '#fff';
|
|
243
394
|
textColorUnit = textColorUnit || '#fff';
|
|
@@ -276,26 +427,18 @@ export default class SpectrogramPlugin extends BasePlugin {
|
|
|
276
427
|
let y;
|
|
277
428
|
if (i == 0) {
|
|
278
429
|
y = (1 + c) * getMaxY + i - 10;
|
|
279
|
-
// unit label
|
|
280
|
-
ctx.fillStyle = textColorUnit;
|
|
281
|
-
ctx.font = fontSizeUnit + ' ' + fontType;
|
|
282
|
-
ctx.fillText(units, x + 24, y);
|
|
283
|
-
// freq label
|
|
284
|
-
ctx.fillStyle = textColorFreq;
|
|
285
|
-
ctx.font = fontSizeFreq + ' ' + fontType;
|
|
286
|
-
ctx.fillText(label, x, y);
|
|
287
430
|
}
|
|
288
431
|
else {
|
|
289
432
|
y = (1 + c) * getMaxY - i * 50 + yLabelOffset;
|
|
290
|
-
// unit label
|
|
291
|
-
ctx.fillStyle = textColorUnit;
|
|
292
|
-
ctx.font = fontSizeUnit + ' ' + fontType;
|
|
293
|
-
ctx.fillText(units, x + 24, y);
|
|
294
|
-
// freq label
|
|
295
|
-
ctx.fillStyle = textColorFreq;
|
|
296
|
-
ctx.font = fontSizeFreq + ' ' + fontType;
|
|
297
|
-
ctx.fillText(label, x, y);
|
|
298
433
|
}
|
|
434
|
+
// unit label
|
|
435
|
+
ctx.fillStyle = textColorUnit;
|
|
436
|
+
ctx.font = fontSizeUnit + ' ' + fontType;
|
|
437
|
+
ctx.fillText(units, x + 24, y);
|
|
438
|
+
// freq label
|
|
439
|
+
ctx.fillStyle = textColorFreq;
|
|
440
|
+
ctx.font = fontSizeFreq + ' ' + fontType;
|
|
441
|
+
ctx.fillText(label, x, y);
|
|
299
442
|
}
|
|
300
443
|
}
|
|
301
444
|
}
|
|
@@ -339,3 +482,4 @@ export default class SpectrogramPlugin extends BasePlugin {
|
|
|
339
482
|
return newMatrix;
|
|
340
483
|
}
|
|
341
484
|
}
|
|
485
|
+
export default SpectrogramPlugin;
|
|
@@ -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:()=>
|
|
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()}("undefined"!=typeof WaveSurfer?WaveSurfer:this,(()=>(()=>{"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:()=>n});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,o=new Float32Array(a),l=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++)o[S]=t[h[S]]*this.windowValues[h[S]],l[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*o[g=S+x]-M*l[g],y=b*l[g]+M*o[g],o[g]=o[S]-m,l[g]=l[S]-y,o[S]+=m,l[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=o[S])*e+(s=l[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 o=this.resample(t[h]),l=new ImageData(i,s);for(let t=0;t<o.length;t++)for(let e=0;e<o[t].length;e++){const a=this.colorMap[o[t][e]],r=4*((s-e)*i+t);l.data[r]=255*a[0],l.data[r+1]=255*a[1],l.data[r+2]=255*a[2],l.data[r+3]=255*a[3]}createImageBitmap(l).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,"12px","12px","",this.options.labelsColor,this.options.labelsHzColor||this.options.labelsColor,"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 o=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=o.calculateSpectrum(t),n=new Uint8Array(e/2);let l;for(l=0;l<e/2;l++)n[l]=Math.max(-255,45*Math.log10(s[l]));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||"12px",i=i||"Helvetica",a=a||"#fff",r=r||"#fff",n=n||"center",h=h||"#specLabels";const o=this.height||512,l=o/256*5,c=this.frequencyMin,f=(this.frequencyMax-c)/l,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*o,55,(1+h)*o),p.fill(),u=0;u<=l;u++){p.textAlign=n,p.textBaseline="middle";const t=c+f*u,l=this.freqType(t),d=this.unitType(t),w=16;let b;b=0==u?(1+h)*o+u-10:(1+h)*o-50*u+2,p.fillStyle=r,p.font=s+" "+i,p.fillText(d,w+24,b),p.fillStyle=a,p.font=e+" "+i,p.fillText(l,w,b)}}}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,o=r*a,l=o+a,c=h<=o||l<=s?0:Math.min(Math.max(h,o),Math.max(l,s))-Math.max(Math.min(h,o),Math.min(l,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 o;for(o=0;o<t[0].length;o++)h[o]=e[o];s.push(h)}return s}}const n=r;return e.default})()));
|
|
@@ -26,7 +26,7 @@ declare const defaultOptions: {
|
|
|
26
26
|
export type TimelinePluginEvents = {
|
|
27
27
|
ready: [];
|
|
28
28
|
};
|
|
29
|
-
declare class TimelinePlugin extends BasePlugin<TimelinePluginEvents, TimelinePluginOptions> {
|
|
29
|
+
export declare class TimelinePlugin extends BasePlugin<TimelinePluginEvents, TimelinePluginOptions> {
|
|
30
30
|
private timelineWrapper;
|
|
31
31
|
protected options: TimelinePluginOptions & typeof defaultOptions;
|
|
32
32
|
constructor(options?: TimelinePluginOptions);
|
package/dist/plugins/timeline.js
CHANGED
|
@@ -5,7 +5,7 @@ import BasePlugin from '../base-plugin.js';
|
|
|
5
5
|
const defaultOptions = {
|
|
6
6
|
height: 20,
|
|
7
7
|
};
|
|
8
|
-
class TimelinePlugin extends BasePlugin {
|
|
8
|
+
export class TimelinePlugin extends BasePlugin {
|
|
9
9
|
constructor(options) {
|
|
10
10
|
super(options || {});
|
|
11
11
|
this.options = Object.assign({}, defaultOptions, options);
|
|
@@ -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.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})()));
|
|
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()}("undefined"!=typeof WaveSurfer?WaveSurfer:this,(()=>(()=>{"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.js
CHANGED
|
@@ -330,6 +330,10 @@ class Renderer extends EventEmitter {
|
|
|
330
330
|
// Clear previous timeouts
|
|
331
331
|
this.timeouts.forEach((context) => context.timeout && clearTimeout(context.timeout));
|
|
332
332
|
this.timeouts = [];
|
|
333
|
+
// Clear the canvases
|
|
334
|
+
this.canvasWrapper.innerHTML = '';
|
|
335
|
+
this.progressWrapper.innerHTML = '';
|
|
336
|
+
this.wrapper.style.width = '';
|
|
333
337
|
// Determine the width of the waveform
|
|
334
338
|
const pixelRatio = window.devicePixelRatio || 1;
|
|
335
339
|
const parentWidth = this.scrollContainer.clientWidth;
|
|
@@ -337,7 +341,7 @@ class Renderer extends EventEmitter {
|
|
|
337
341
|
// Whether the container should scroll
|
|
338
342
|
this.isScrolling = scrollWidth > parentWidth;
|
|
339
343
|
const useParentWidth = this.options.fillParent && !this.isScrolling;
|
|
340
|
-
// Width
|
|
344
|
+
// Width of the waveform in pixels
|
|
341
345
|
const width = (useParentWidth ? parentWidth : scrollWidth) * pixelRatio;
|
|
342
346
|
// Set the width of the wrapper
|
|
343
347
|
this.wrapper.style.width = useParentWidth ? '100%' : `${scrollWidth}px`;
|
|
@@ -346,9 +350,6 @@ class Renderer extends EventEmitter {
|
|
|
346
350
|
this.scrollContainer.classList.toggle('noScrollbar', !!this.options.hideScrollbar);
|
|
347
351
|
this.cursor.style.backgroundColor = `${this.options.cursorColor || this.options.progressColor}`;
|
|
348
352
|
this.cursor.style.width = `${this.options.cursorWidth}px`;
|
|
349
|
-
// Clear the canvases
|
|
350
|
-
this.canvasWrapper.innerHTML = '';
|
|
351
|
-
this.progressWrapper.innerHTML = '';
|
|
352
353
|
// Render the waveform
|
|
353
354
|
if (this.options.splitChannels) {
|
|
354
355
|
// Render a waveform for each channel
|
package/dist/wavesurfer.d.ts
CHANGED
|
@@ -57,6 +57,8 @@ export type WaveSurferOptions = {
|
|
|
57
57
|
plugins?: GenericPlugin[];
|
|
58
58
|
/** Custom render function */
|
|
59
59
|
renderFunction?: (peaks: Array<Float32Array | number[]>, ctx: CanvasRenderingContext2D) => void;
|
|
60
|
+
/** Options to pass to the fetch method */
|
|
61
|
+
fetchParams?: RequestInit;
|
|
60
62
|
};
|
|
61
63
|
declare const defaultOptions: {
|
|
62
64
|
waveColor: string;
|
|
@@ -103,7 +105,7 @@ export type WaveSurferEvents = {
|
|
|
103
105
|
/** Just before the waveform is destroyed so you can clean up your events */
|
|
104
106
|
destroy: [];
|
|
105
107
|
};
|
|
106
|
-
declare class WaveSurfer extends Player<WaveSurferEvents> {
|
|
108
|
+
export declare class WaveSurfer extends Player<WaveSurferEvents> {
|
|
107
109
|
options: WaveSurferOptions & typeof defaultOptions;
|
|
108
110
|
private renderer;
|
|
109
111
|
private timer;
|
package/dist/wavesurfer.js
CHANGED
|
@@ -14,7 +14,7 @@ const defaultOptions = {
|
|
|
14
14
|
autoCenter: true,
|
|
15
15
|
sampleRate: 8000,
|
|
16
16
|
};
|
|
17
|
-
class WaveSurfer extends Player {
|
|
17
|
+
export class WaveSurfer extends Player {
|
|
18
18
|
/** Create a new WaveSurfer instance */
|
|
19
19
|
static create(options) {
|
|
20
20
|
return new WaveSurfer(options);
|
|
@@ -143,7 +143,7 @@ class WaveSurfer extends Player {
|
|
|
143
143
|
this.duration = null;
|
|
144
144
|
this.emit('load', url);
|
|
145
145
|
// Fetch the entire audio as a blob if pre-decoded data is not provided
|
|
146
|
-
const blob = channelData ? undefined : await Fetcher.fetchBlob(url);
|
|
146
|
+
const blob = channelData ? undefined : await Fetcher.fetchBlob(url, this.options.fetchParams);
|
|
147
147
|
// Set the mediaelement source to the URL
|
|
148
148
|
this.setSrc(url, blob);
|
|
149
149
|
// Wait for the audio duration
|
package/dist/wavesurfer.min.cjs
CHANGED
|
@@ -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.WaveSurfer=e():t.WaveSurfer=e()}(this,(()=>(()=>{"use strict";var t={d:(e,i)=>{for(var s in i)t.o(i,s)&&!t.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:i[s]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)},e={};t.d(e,{default:()=>d});const i={decode:async function(t,e){const i=new AudioContext({sampleRate:e}),s=i.decodeAudioData(t);return s.finally((()=>i.close())),s},createBuffer:function(t,e){return"number"==typeof t[0]&&(t=[t]),function(t){const e=t[0];if(e.some((t=>t>1||t<-1))){const i=e.length;let s=0;for(let t=0;t<i;t++){const i=Math.abs(e[t]);i>s&&(s=i)}for(const e of t)for(let t=0;t<i;t++)e[t]/=s}}(t),{duration:e,length:t[0].length,sampleRate:t[0].length/e,numberOfChannels:t.length,getChannelData:e=>t?.[e],copyFromChannel:AudioBuffer.prototype.copyFromChannel,copyToChannel:AudioBuffer.prototype.copyToChannel}}},s=async function(t){return fetch(t).then((t=>t.blob()))},r=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),s=this.on(t,(()=>{i(),s()}));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 r{constructor(t){super(),this.isExternalMedia=!1,t.media?(this.media=t.media,this.isExternalMedia=!0):this.media=document.createElement("audio"),t.autoplay&&(this.media.autoplay=!0),null!=t.playbackRate&&(this.media.playbackRate=t.playbackRate)}onMediaEvent(t,e,i){return this.media.addEventListener(t,e,i),()=>this.media.removeEventListener(t,e)}onceMediaEvent(t,e){return this.onMediaEvent(t,e,{once:!0})}revokeSrc(){(this.media.currentSrc||this.media.src||"").startsWith("blob:")&&URL.revokeObjectURL(this.media.currentSrc)}setSrc(t,e){if((this.media.currentSrc||this.media.src||"")===t)return;this.revokeSrc();const i=e instanceof Blob?URL.createObjectURL(e):t;this.media.src=i}destroy(){this.media.pause(),this.revokeSrc(),this.isExternalMedia||this.media.remove()}play(){return this.media.play()}pause(){this.media.pause()}isPlaying(){return this.media.currentTime>0&&!this.media.paused&&!this.media.ended}setTime(t){this.media.currentTime=t}getDuration(){return this.media.duration}getCurrentTime(){return this.media.currentTime}getVolume(){return this.media.volume}setVolume(t){this.media.volume=t}getMuted(){return this.media.muted}setMuted(t){this.media.muted=t}getPlaybackRate(){return this.media.playbackRate}setPlaybackRate(t,e){null!=e&&(this.media.preservesPitch=e),this.media.playbackRate=t}getMediaElement(){return this.media}setSinkId(t){return this.media.setSinkId(t)}};class o extends r{constructor(t){let e;if(super(),this.timeouts=[],this.isScrolling=!1,this.audioData=null,this.resizeObserver=null,this.isDragging=!1,this.options=t,"string"==typeof t.container?e=document.querySelector(t.container):t.container instanceof HTMLElement&&(e=t.container),!e)throw new Error("Container not found");this.parent=e;const[i,s]=this.initHtml();e.appendChild(i),this.container=i,this.scrollContainer=s.querySelector(".scroll"),this.wrapper=s.querySelector(".wrapper"),this.canvasWrapper=s.querySelector(".canvases"),this.progressWrapper=s.querySelector(".progress"),this.cursor=s.querySelector(".cursor"),this.initEvents()}initEvents(){this.wrapper.addEventListener("click",(t=>{const e=this.wrapper.getBoundingClientRect(),i=(t.clientX-e.left)/e.width;this.emit("click",i)})),this.initDrag(),this.scrollContainer.addEventListener("scroll",(()=>{const{scrollLeft:t,scrollWidth:e,clientWidth:i}=this.scrollContainer,s=t/e,r=(t+i)/e;this.emit("scroll",s,r)}));const t=this.createDelay(100);this.resizeObserver=new ResizeObserver((()=>{t((()=>this.reRender()))})),this.resizeObserver.observe(this.scrollContainer)}initDrag(){!function(t,e,i,s,r=5){let n=()=>{};if(!t)return n;t.addEventListener("pointerdown",(o=>{o.preventDefault(),o.stopPropagation();let a=o.clientX,h=o.clientY,l=!1;const c=s=>{s.preventDefault(),s.stopPropagation();const n=s.clientX,o=s.clientY;if(l||Math.abs(n-a)>=r||Math.abs(o-h)>=r){l||(l=!0,i?.(a,h));const{left:s,top:r}=t.getBoundingClientRect();e(n-a,o-h,n-s,o-r),a=n,h=o}},d=t=>{l&&(t.preventDefault(),t.stopPropagation())},u=()=>{l&&s?.(),n()};n=()=>{document.removeEventListener("pointermove",c),document.removeEventListener("pointerup",u),document.removeEventListener("pointerleave",u),setTimeout((()=>{document.removeEventListener("click",d,!0)}),10)},document.addEventListener("pointermove",c),document.addEventListener("pointerup",u),document.addEventListener("pointerleave",u),document.addEventListener("click",d,!0)}))}(this.wrapper,((t,e,i)=>{this.emit("drag",Math.max(0,Math.min(1,i/this.wrapper.clientWidth)))}),(()=>this.isDragging=!0),(()=>this.isDragging=!1))}getHeight(){return null==this.options.height?128:isNaN(Number(this.options.height))?"auto"===this.options.height&&this.parent.clientHeight||128:Number(this.options.height)}initHtml(){const t=document.createElement("div"),e=t.attachShadow({mode:"open"});return e.innerHTML=`\n <style>\n :host {\n user-select: none;\n }\n :host .scroll {\n overflow-x: auto;\n overflow-y: hidden;\n width: 100%;\n position: relative;\n }\n :host .noScrollbar {\n scrollbar-color: transparent;\n scrollbar-width: none;\n }\n :host .noScrollbar::-webkit-scrollbar {\n display: none;\n -webkit-appearance: none;\n }\n :host .wrapper {\n position: relative;\n overflow: visible;\n z-index: 2;\n }\n :host .canvases {\n min-height: ${this.getHeight()}px;\n }\n :host .canvases > div {\n position: relative;\n }\n :host canvas {\n display: block;\n position: absolute;\n top: 0;\n image-rendering: pixelated;\n }\n :host .progress {\n pointer-events: none;\n position: absolute;\n z-index: 2;\n top: 0;\n left: 0;\n width: 0;\n height: 100%;\n overflow: hidden;\n }\n :host .progress > div {\n position: relative;\n }\n :host .cursor {\n pointer-events: none;\n position: absolute;\n z-index: 5;\n top: 0;\n left: 0;\n height: 100%;\n border-radius: 2px;\n }\n </style>\n\n <div class="scroll" part="scroll">\n <div class="wrapper">\n <div class="canvases"></div>\n <div class="progress" part="progress"></div>\n <div class="cursor" part="cursor"></div>\n </div>\n </div>\n `,[t,e]}setOptions(t){this.options=t,this.reRender()}getWrapper(){return this.wrapper}getScroll(){return this.scrollContainer.scrollLeft}destroy(){this.container.remove(),this.resizeObserver?.disconnect()}createDelay(t=10){const e={};return this.timeouts.push(e),i=>{e.timeout&&clearTimeout(e.timeout),e.timeout=setTimeout(i,t)}}convertColorValues(t){if(!Array.isArray(t))return t||"";if(t.length<2)return t[0]||"";const e=document.createElement("canvas"),i=e.getContext("2d").createLinearGradient(0,0,0,e.height),s=1/(t.length-1);return t.forEach(((t,e)=>{const r=e*s;i.addColorStop(r,t)})),i}renderBars(t,e,i){if(i.fillStyle=this.convertColorValues(e.waveColor),e.renderFunction)return void e.renderFunction(t,i);const s=t[0],r=t[1]||t[0],n=s.length,o=window.devicePixelRatio||1,{width:a,height:h}=i.canvas,l=h/2,c=e.barHeight||1,d=e.barWidth?e.barWidth*o:1,u=e.barGap?e.barGap*o:e.barWidth?d/2:0,p=e.barRadius||0,m=a/(d+u)/n;let g=1;if(e.normalize){g=0;for(let t=0;t<n;t++){const e=Math.abs(s[t]);e>g&&(g=e)}}const v=l/g*c;i.beginPath();let f=0,b=0,y=0;for(let t=0;t<=n;t++){const n=Math.round(t*m);if(n>f){const t=Math.round(b*v),s=t+Math.round(y*v)||1;let r=l-t;"top"===e.barAlign?r=0:"bottom"===e.barAlign&&(r=h-s),i.roundRect(f*(d+u),r,d,s,p),f=n,b=0,y=0}const o=Math.abs(s[t]||0),a=Math.abs(r[t]||0);o>b&&(b=o),a>y&&(y=a)}i.fill(),i.closePath()}renderSingleCanvas(t,e,i,s,r,n,o,a){const h=window.devicePixelRatio||1,l=document.createElement("canvas"),c=t[0].length;l.width=Math.round(i*(n-r)/c),l.height=s*h,l.style.width=`${Math.floor(l.width/h)}px`,l.style.height=`${s}px`,l.style.left=`${Math.floor(r*i/h/c)}px`,o.appendChild(l);const d=l.getContext("2d");this.renderBars(t.map((t=>t.slice(r,n))),e,d);const u=l.cloneNode();a.appendChild(u);const p=u.getContext("2d");l.width>0&&l.height>0&&p.drawImage(l,0,0),p.globalCompositeOperation="source-in",p.fillStyle=this.convertColorValues(e.progressColor),p.fillRect(0,0,l.width,l.height)}renderWaveform(t,e,i){const s=document.createElement("div"),r=this.getHeight();s.style.height=`${r}px`,this.canvasWrapper.style.minHeight=`${r}px`,this.canvasWrapper.appendChild(s);const n=s.cloneNode();this.progressWrapper.appendChild(n);const{scrollLeft:a,scrollWidth:h,clientWidth:l}=this.scrollContainer,c=t[0].length,d=c/h;let u=Math.min(o.MAX_CANVAS_WIDTH,l);if(e.barWidth||e.barGap){const t=e.barWidth||.5,i=t+(e.barGap||t/2);u%i!=0&&(u=Math.floor(u/i)*i)}const p=Math.floor(Math.abs(a)*d),m=Math.floor(p+u*d),g=m-p,v=(o,a)=>{this.renderSingleCanvas(t,e,i,r,Math.max(0,o),Math.min(a,c),s,n)},f=this.createDelay(),b=this.createDelay(),y=(t,e)=>{v(t,e),t>0&&f((()=>{y(t-g,e-g)}))},C=(t,e)=>{v(t,e),e<c&&b((()=>{C(t+g,e+g)}))};y(p,m),m<c&&C(m,m+g)}render(t){this.timeouts.forEach((t=>t.timeout&&clearTimeout(t.timeout))),this.timeouts=[];const e=window.devicePixelRatio||1,i=this.scrollContainer.clientWidth,s=Math.ceil(t.duration*(this.options.minPxPerSec||0));this.isScrolling=s>i;const r=this.options.fillParent&&!this.isScrolling,n=(r?i:s)*e;if(this.wrapper.style.width=r?"100%":`${s}px`,this.scrollContainer.style.overflowX=this.isScrolling?"auto":"hidden",this.scrollContainer.classList.toggle("noScrollbar",!!this.options.hideScrollbar),this.cursor.style.backgroundColor=`${this.options.cursorColor||this.options.progressColor}`,this.cursor.style.width=`${this.options.cursorWidth}px`,this.canvasWrapper.innerHTML="",this.progressWrapper.innerHTML="",this.options.splitChannels)for(let e=0;e<t.numberOfChannels;e++){const i={...this.options,...this.options.splitChannels[e]};this.renderWaveform([t.getChannelData(e)],i,n)}else{const e=[t.getChannelData(0)];t.numberOfChannels>1&&e.push(t.getChannelData(1)),this.renderWaveform(e,this.options,n)}this.audioData=t,this.emit("render")}reRender(){if(!this.audioData)return;const t=this.progressWrapper.clientWidth;this.render(this.audioData);const e=this.progressWrapper.clientWidth;this.scrollContainer.scrollLeft+=e-t}zoom(t){this.options.minPxPerSec=t,this.reRender()}scrollIntoView(t,e=!1){const{clientWidth:i,scrollLeft:s,scrollWidth:r}=this.scrollContainer,n=r*t,o=i/2;if(n>s+(e&&this.options.autoCenter&&!this.isDragging?o:i)||n<s)if(this.options.autoCenter&&!this.isDragging){const t=o/20;n-(s+o)>=t&&n<s+i?this.scrollContainer.scrollLeft+=t:this.scrollContainer.scrollLeft=n-o}else if(this.isDragging){const t=10;this.scrollContainer.scrollLeft=n<s?n-t:n-i+t}else this.scrollContainer.scrollLeft=n;{const{scrollLeft:t}=this.scrollContainer,e=t/r,s=(t+i)/r;this.emit("scroll",e,s)}}renderProgress(t,e){isNaN(t)||(this.progressWrapper.style.width=100*t+"%",this.cursor.style.left=100*t+"%",this.cursor.style.marginLeft=100===Math.round(100*t)?`-${this.options.cursorWidth}px`:"",this.isScrolling&&this.options.autoScroll&&this.scrollIntoView(t,e))}}o.MAX_CANVAS_WIDTH=4e3;const a=o,h=class extends r{constructor(){super(...arguments),this.unsubscribe=()=>{}}start(){this.unsubscribe=this.on("tick",(()=>{requestAnimationFrame((()=>{this.emit("tick")}))})),this.emit("tick")}stop(){this.unsubscribe()}destroy(){this.unsubscribe()}},l={waveColor:"#999",progressColor:"#555",cursorWidth:1,minPxPerSec:0,fillParent:!0,interact:!0,autoScroll:!0,autoCenter:!0,sampleRate:8e3};class c extends n{static create(t){return new c(t)}constructor(t){super({media:t.media,autoplay:t.autoplay,playbackRate:t.audioRate}),this.plugins=[],this.decodedData=null,this.duration=null,this.subscriptions=[],this.options=Object.assign({},l,t),this.timer=new h,this.renderer=new a(this.options),this.initPlayerEvents(),this.initRendererEvents(),this.initTimerEvents(),this.initPlugins();const e=this.options.url||this.options.media?.currentSrc||this.options.media?.src;e&&this.load(e,this.options.peaks,this.options.duration)}setOptions(t){this.options=Object.assign({},this.options,t),this.renderer.setOptions(this.options),t.audioRate&&this.setPlaybackRate(t.audioRate)}initTimerEvents(){this.subscriptions.push(this.timer.on("tick",(()=>{const t=this.getCurrentTime();this.renderer.renderProgress(t/this.getDuration(),!0),this.emit("timeupdate",t),this.emit("audioprocess",t)})))}initPlayerEvents(){this.subscriptions.push(this.onMediaEvent("timeupdate",(()=>{const t=this.getCurrentTime();this.renderer.renderProgress(t/this.getDuration(),this.isPlaying()),this.emit("timeupdate",t)})),this.onMediaEvent("play",(()=>{this.emit("play"),this.timer.start()})),this.onMediaEvent("pause",(()=>{this.emit("pause"),this.timer.stop()})),this.onMediaEvent("ended",(()=>{this.emit("finish")})),this.onMediaEvent("seeking",(()=>{this.emit("seeking",this.getCurrentTime())})))}initRendererEvents(){this.subscriptions.push(this.renderer.on("click",(t=>{this.options.interact&&(this.seekTo(t),this.emit("interaction",this.getCurrentTime()),this.emit("click",t))})),this.renderer.on("scroll",((t,e)=>{const i=this.getDuration();this.emit("scroll",t*i,e*i)})),this.renderer.on("render",(()=>{this.emit("redraw")})));{let t;this.subscriptions.push(this.renderer.on("drag",(e=>{this.options.interact&&(this.renderer.renderProgress(e),clearTimeout(t),t=setTimeout((()=>{this.seekTo(e)}),this.isPlaying()?0:200),this.emit("interaction",e*this.getDuration()),this.emit("drag",e))})))}}initPlugins(){this.options.plugins?.length&&this.options.plugins.forEach((t=>{this.registerPlugin(t)}))}registerPlugin(t){return t.init(this),this.plugins.push(t),t}getWrapper(){return this.renderer.getWrapper()}getScroll(){return this.renderer.getScroll()}getActivePlugins(){return this.plugins}async load(t,e,r){this.decodedData=null,this.duration=null,this.emit("load",t);const n=e?void 0:await s(t);if(this.setSrc(t,n),this.duration=r||this.getDuration()||await new Promise((t=>{this.onceMediaEvent("loadedmetadata",(()=>t(this.getDuration())))}))||0,e)this.decodedData=i.createBuffer(e,this.duration);else if(n){const t=await n.arrayBuffer();this.decodedData=await i.decode(t,this.options.sampleRate),0!==this.duration&&this.duration!==1/0||(this.duration=this.decodedData.duration)}this.emit("decode",this.duration),this.decodedData&&this.renderer.render(this.decodedData),this.emit("ready",this.duration)}zoom(t){if(!this.decodedData)throw new Error("No audio loaded");this.renderer.zoom(t),this.emit("zoom",t)}getDecodedData(){return this.decodedData}getDuration(){return null!==this.duration?this.duration:super.getDuration()}toggleInteraction(t){this.options.interact=t}seekTo(t){const e=this.getDuration()*t;this.setTime(e)}async playPause(){return this.isPlaying()?this.pause():this.play()}stop(){this.pause(),this.setTime(0)}skip(t){this.setTime(this.getCurrentTime()+t)}empty(){this.load("",[[0]],.001)}destroy(){this.emit("destroy"),this.subscriptions.forEach((t=>t())),this.plugins.forEach((t=>t.destroy())),this.timer.destroy(),this.renderer.destroy(),super.destroy()}}const d=c;return e.default})()));
|
|
1
|
+
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.WaveSurfer=e():t.WaveSurfer=e()}(this,(()=>(()=>{"use strict";var t={d:(e,i)=>{for(var s in i)t.o(i,s)&&!t.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:i[s]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)},e={};t.d(e,{default:()=>d});const i={decode:async function(t,e){const i=new AudioContext({sampleRate:e}),s=i.decodeAudioData(t);return s.finally((()=>i.close())),s},createBuffer:function(t,e){return"number"==typeof t[0]&&(t=[t]),function(t){const e=t[0];if(e.some((t=>t>1||t<-1))){const i=e.length;let s=0;for(let t=0;t<i;t++){const i=Math.abs(e[t]);i>s&&(s=i)}for(const e of t)for(let t=0;t<i;t++)e[t]/=s}}(t),{duration:e,length:t[0].length,sampleRate:t[0].length/e,numberOfChannels:t.length,getChannelData:e=>t?.[e],copyFromChannel:AudioBuffer.prototype.copyFromChannel,copyToChannel:AudioBuffer.prototype.copyToChannel}}},s=async function(t,e){return fetch(t,e).then((t=>t.blob()))},r=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),s=this.on(t,(()=>{i(),s()}));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 r{constructor(t){super(),t.media?this.media=t.media:this.media=document.createElement("audio"),t.autoplay&&(this.media.autoplay=!0),null!=t.playbackRate&&(this.media.playbackRate=t.playbackRate)}onMediaEvent(t,e,i){return this.media.addEventListener(t,e,i),()=>this.media.removeEventListener(t,e)}onceMediaEvent(t,e){return this.onMediaEvent(t,e,{once:!0})}getSrc(){return this.media.currentSrc||this.media.src||""}revokeSrc(){const t=this.getSrc();t.startsWith("blob:")&&URL.revokeObjectURL(t)}setSrc(t,e){if(this.getSrc()===t)return;this.revokeSrc();const i=e instanceof Blob?URL.createObjectURL(e):t;this.media.src=i,this.media.load()}destroy(){this.media.pause(),this.revokeSrc(),this.media.src="",this.media.load()}play(){return this.media.play()}pause(){this.media.pause()}isPlaying(){return this.media.currentTime>0&&!this.media.paused&&!this.media.ended}setTime(t){this.media.currentTime=t}getDuration(){return this.media.duration}getCurrentTime(){return this.media.currentTime}getVolume(){return this.media.volume}setVolume(t){this.media.volume=t}getMuted(){return this.media.muted}setMuted(t){this.media.muted=t}getPlaybackRate(){return this.media.playbackRate}setPlaybackRate(t,e){null!=e&&(this.media.preservesPitch=e),this.media.playbackRate=t}getMediaElement(){return this.media}setSinkId(t){return this.media.setSinkId(t)}};class o extends r{constructor(t){let e;if(super(),this.timeouts=[],this.isScrolling=!1,this.audioData=null,this.resizeObserver=null,this.isDragging=!1,this.options=t,"string"==typeof t.container?e=document.querySelector(t.container):t.container instanceof HTMLElement&&(e=t.container),!e)throw new Error("Container not found");this.parent=e;const[i,s]=this.initHtml();e.appendChild(i),this.container=i,this.scrollContainer=s.querySelector(".scroll"),this.wrapper=s.querySelector(".wrapper"),this.canvasWrapper=s.querySelector(".canvases"),this.progressWrapper=s.querySelector(".progress"),this.cursor=s.querySelector(".cursor"),this.initEvents()}initEvents(){this.wrapper.addEventListener("click",(t=>{const e=this.wrapper.getBoundingClientRect(),i=(t.clientX-e.left)/e.width;this.emit("click",i)})),this.initDrag(),this.scrollContainer.addEventListener("scroll",(()=>{const{scrollLeft:t,scrollWidth:e,clientWidth:i}=this.scrollContainer,s=t/e,r=(t+i)/e;this.emit("scroll",s,r)}));const t=this.createDelay(100);this.resizeObserver=new ResizeObserver((()=>{t((()=>this.reRender()))})),this.resizeObserver.observe(this.scrollContainer)}initDrag(){!function(t,e,i,s,r=5){let n=()=>{};if(!t)return n;t.addEventListener("pointerdown",(o=>{o.preventDefault(),o.stopPropagation();let a=o.clientX,h=o.clientY,l=!1;const c=s=>{s.preventDefault(),s.stopPropagation();const n=s.clientX,o=s.clientY;if(l||Math.abs(n-a)>=r||Math.abs(o-h)>=r){const{left:s,top:r}=t.getBoundingClientRect();l||(l=!0,i?.(a-s,h-r)),e(n-a,o-h,n-s,o-r),a=n,h=o}},d=t=>{l&&(t.preventDefault(),t.stopPropagation())},u=()=>{l&&s?.(),n()};n=()=>{document.removeEventListener("pointermove",c),document.removeEventListener("pointerup",u),document.removeEventListener("pointerleave",u),setTimeout((()=>{document.removeEventListener("click",d,!0)}),10)},document.addEventListener("pointermove",c),document.addEventListener("pointerup",u),document.addEventListener("pointerleave",u),document.addEventListener("click",d,!0)}))}(this.wrapper,((t,e,i)=>{this.emit("drag",Math.max(0,Math.min(1,i/this.wrapper.clientWidth)))}),(()=>this.isDragging=!0),(()=>this.isDragging=!1))}getHeight(){return null==this.options.height?128:isNaN(Number(this.options.height))?"auto"===this.options.height&&this.parent.clientHeight||128:Number(this.options.height)}initHtml(){const t=document.createElement("div"),e=t.attachShadow({mode:"open"});return e.innerHTML=`\n <style>\n :host {\n user-select: none;\n }\n :host .scroll {\n overflow-x: auto;\n overflow-y: hidden;\n width: 100%;\n position: relative;\n }\n :host .noScrollbar {\n scrollbar-color: transparent;\n scrollbar-width: none;\n }\n :host .noScrollbar::-webkit-scrollbar {\n display: none;\n -webkit-appearance: none;\n }\n :host .wrapper {\n position: relative;\n overflow: visible;\n z-index: 2;\n }\n :host .canvases {\n min-height: ${this.getHeight()}px;\n }\n :host .canvases > div {\n position: relative;\n }\n :host canvas {\n display: block;\n position: absolute;\n top: 0;\n image-rendering: pixelated;\n }\n :host .progress {\n pointer-events: none;\n position: absolute;\n z-index: 2;\n top: 0;\n left: 0;\n width: 0;\n height: 100%;\n overflow: hidden;\n }\n :host .progress > div {\n position: relative;\n }\n :host .cursor {\n pointer-events: none;\n position: absolute;\n z-index: 5;\n top: 0;\n left: 0;\n height: 100%;\n border-radius: 2px;\n }\n </style>\n\n <div class="scroll" part="scroll">\n <div class="wrapper">\n <div class="canvases"></div>\n <div class="progress" part="progress"></div>\n <div class="cursor" part="cursor"></div>\n </div>\n </div>\n `,[t,e]}setOptions(t){this.options=t,this.reRender()}getWrapper(){return this.wrapper}getScroll(){return this.scrollContainer.scrollLeft}destroy(){this.container.remove(),this.resizeObserver?.disconnect()}createDelay(t=10){const e={};return this.timeouts.push(e),i=>{e.timeout&&clearTimeout(e.timeout),e.timeout=setTimeout(i,t)}}convertColorValues(t){if(!Array.isArray(t))return t||"";if(t.length<2)return t[0]||"";const e=document.createElement("canvas"),i=e.getContext("2d").createLinearGradient(0,0,0,e.height),s=1/(t.length-1);return t.forEach(((t,e)=>{const r=e*s;i.addColorStop(r,t)})),i}renderBars(t,e,i){if(i.fillStyle=this.convertColorValues(e.waveColor),e.renderFunction)return void e.renderFunction(t,i);const s=t[0],r=t[1]||t[0],n=s.length,o=window.devicePixelRatio||1,{width:a,height:h}=i.canvas,l=h/2,c=e.barHeight||1,d=e.barWidth?e.barWidth*o:1,u=e.barGap?e.barGap*o:e.barWidth?d/2:0,p=e.barRadius||0,m=a/(d+u)/n;let g=1;if(e.normalize){g=0;for(let t=0;t<n;t++){const e=Math.abs(s[t]);e>g&&(g=e)}}const v=l/g*c;i.beginPath();let f=0,b=0,y=0;for(let t=0;t<=n;t++){const n=Math.round(t*m);if(n>f){const t=Math.round(b*v),s=t+Math.round(y*v)||1;let r=l-t;"top"===e.barAlign?r=0:"bottom"===e.barAlign&&(r=h-s),i.roundRect(f*(d+u),r,d,s,p),f=n,b=0,y=0}const o=Math.abs(s[t]||0),a=Math.abs(r[t]||0);o>b&&(b=o),a>y&&(y=a)}i.fill(),i.closePath()}renderSingleCanvas(t,e,i,s,r,n,o,a){const h=window.devicePixelRatio||1,l=document.createElement("canvas"),c=t[0].length;l.width=Math.round(i*(n-r)/c),l.height=s*h,l.style.width=`${Math.floor(l.width/h)}px`,l.style.height=`${s}px`,l.style.left=`${Math.floor(r*i/h/c)}px`,o.appendChild(l);const d=l.getContext("2d");this.renderBars(t.map((t=>t.slice(r,n))),e,d);const u=l.cloneNode();a.appendChild(u);const p=u.getContext("2d");l.width>0&&l.height>0&&p.drawImage(l,0,0),p.globalCompositeOperation="source-in",p.fillStyle=this.convertColorValues(e.progressColor),p.fillRect(0,0,l.width,l.height)}renderWaveform(t,e,i){const s=document.createElement("div"),r=this.getHeight();s.style.height=`${r}px`,this.canvasWrapper.style.minHeight=`${r}px`,this.canvasWrapper.appendChild(s);const n=s.cloneNode();this.progressWrapper.appendChild(n);const{scrollLeft:a,scrollWidth:h,clientWidth:l}=this.scrollContainer,c=t[0].length,d=c/h;let u=Math.min(o.MAX_CANVAS_WIDTH,l);if(e.barWidth||e.barGap){const t=e.barWidth||.5,i=t+(e.barGap||t/2);u%i!=0&&(u=Math.floor(u/i)*i)}const p=Math.floor(Math.abs(a)*d),m=Math.floor(p+u*d),g=m-p,v=(o,a)=>{this.renderSingleCanvas(t,e,i,r,Math.max(0,o),Math.min(a,c),s,n)},f=this.createDelay(),b=this.createDelay(),y=(t,e)=>{v(t,e),t>0&&f((()=>{y(t-g,e-g)}))},C=(t,e)=>{v(t,e),e<c&&b((()=>{C(t+g,e+g)}))};y(p,m),m<c&&C(m,m+g)}render(t){this.timeouts.forEach((t=>t.timeout&&clearTimeout(t.timeout))),this.timeouts=[],this.canvasWrapper.innerHTML="",this.progressWrapper.innerHTML="",this.wrapper.style.width="";const e=window.devicePixelRatio||1,i=this.scrollContainer.clientWidth,s=Math.ceil(t.duration*(this.options.minPxPerSec||0));this.isScrolling=s>i;const r=this.options.fillParent&&!this.isScrolling,n=(r?i:s)*e;if(this.wrapper.style.width=r?"100%":`${s}px`,this.scrollContainer.style.overflowX=this.isScrolling?"auto":"hidden",this.scrollContainer.classList.toggle("noScrollbar",!!this.options.hideScrollbar),this.cursor.style.backgroundColor=`${this.options.cursorColor||this.options.progressColor}`,this.cursor.style.width=`${this.options.cursorWidth}px`,this.options.splitChannels)for(let e=0;e<t.numberOfChannels;e++){const i={...this.options,...this.options.splitChannels[e]};this.renderWaveform([t.getChannelData(e)],i,n)}else{const e=[t.getChannelData(0)];t.numberOfChannels>1&&e.push(t.getChannelData(1)),this.renderWaveform(e,this.options,n)}this.audioData=t,this.emit("render")}reRender(){if(!this.audioData)return;const t=this.progressWrapper.clientWidth;this.render(this.audioData);const e=this.progressWrapper.clientWidth;this.scrollContainer.scrollLeft+=e-t}zoom(t){this.options.minPxPerSec=t,this.reRender()}scrollIntoView(t,e=!1){const{clientWidth:i,scrollLeft:s,scrollWidth:r}=this.scrollContainer,n=r*t,o=i/2;if(n>s+(e&&this.options.autoCenter&&!this.isDragging?o:i)||n<s)if(this.options.autoCenter&&!this.isDragging){const t=o/20;n-(s+o)>=t&&n<s+i?this.scrollContainer.scrollLeft+=t:this.scrollContainer.scrollLeft=n-o}else if(this.isDragging){const t=10;this.scrollContainer.scrollLeft=n<s?n-t:n-i+t}else this.scrollContainer.scrollLeft=n;{const{scrollLeft:t}=this.scrollContainer,e=t/r,s=(t+i)/r;this.emit("scroll",e,s)}}renderProgress(t,e){isNaN(t)||(this.progressWrapper.style.width=100*t+"%",this.cursor.style.left=100*t+"%",this.cursor.style.marginLeft=100===Math.round(100*t)?`-${this.options.cursorWidth}px`:"",this.isScrolling&&this.options.autoScroll&&this.scrollIntoView(t,e))}}o.MAX_CANVAS_WIDTH=4e3;const a=o,h=class extends r{constructor(){super(...arguments),this.unsubscribe=()=>{}}start(){this.unsubscribe=this.on("tick",(()=>{requestAnimationFrame((()=>{this.emit("tick")}))})),this.emit("tick")}stop(){this.unsubscribe()}destroy(){this.unsubscribe()}},l={waveColor:"#999",progressColor:"#555",cursorWidth:1,minPxPerSec:0,fillParent:!0,interact:!0,autoScroll:!0,autoCenter:!0,sampleRate:8e3};class c extends n{static create(t){return new c(t)}constructor(t){super({media:t.media,autoplay:t.autoplay,playbackRate:t.audioRate}),this.plugins=[],this.decodedData=null,this.duration=null,this.subscriptions=[],this.options=Object.assign({},l,t),this.timer=new h,this.renderer=new a(this.options),this.initPlayerEvents(),this.initRendererEvents(),this.initTimerEvents(),this.initPlugins();const e=this.options.url||this.options.media?.currentSrc||this.options.media?.src;e&&this.load(e,this.options.peaks,this.options.duration)}setOptions(t){this.options=Object.assign({},this.options,t),this.renderer.setOptions(this.options),t.audioRate&&this.setPlaybackRate(t.audioRate)}initTimerEvents(){this.subscriptions.push(this.timer.on("tick",(()=>{const t=this.getCurrentTime();this.renderer.renderProgress(t/this.getDuration(),!0),this.emit("timeupdate",t),this.emit("audioprocess",t)})))}initPlayerEvents(){this.subscriptions.push(this.onMediaEvent("timeupdate",(()=>{const t=this.getCurrentTime();this.renderer.renderProgress(t/this.getDuration(),this.isPlaying()),this.emit("timeupdate",t)})),this.onMediaEvent("play",(()=>{this.emit("play"),this.timer.start()})),this.onMediaEvent("pause",(()=>{this.emit("pause"),this.timer.stop()})),this.onMediaEvent("ended",(()=>{this.emit("finish")})),this.onMediaEvent("seeking",(()=>{this.emit("seeking",this.getCurrentTime())})))}initRendererEvents(){this.subscriptions.push(this.renderer.on("click",(t=>{this.options.interact&&(this.seekTo(t),this.emit("interaction",this.getCurrentTime()),this.emit("click",t))})),this.renderer.on("scroll",((t,e)=>{const i=this.getDuration();this.emit("scroll",t*i,e*i)})),this.renderer.on("render",(()=>{this.emit("redraw")})));{let t;this.subscriptions.push(this.renderer.on("drag",(e=>{this.options.interact&&(this.renderer.renderProgress(e),clearTimeout(t),t=setTimeout((()=>{this.seekTo(e)}),this.isPlaying()?0:200),this.emit("interaction",e*this.getDuration()),this.emit("drag",e))})))}}initPlugins(){this.options.plugins?.length&&this.options.plugins.forEach((t=>{this.registerPlugin(t)}))}registerPlugin(t){return t.init(this),this.plugins.push(t),t}getWrapper(){return this.renderer.getWrapper()}getScroll(){return this.renderer.getScroll()}getActivePlugins(){return this.plugins}async load(t,e,r){this.decodedData=null,this.duration=null,this.emit("load",t);const n=e?void 0:await s(t,this.options.fetchParams);if(this.setSrc(t,n),this.duration=r||this.getDuration()||await new Promise((t=>{this.onceMediaEvent("loadedmetadata",(()=>t(this.getDuration())))}))||0,e)this.decodedData=i.createBuffer(e,this.duration);else if(n){const t=await n.arrayBuffer();this.decodedData=await i.decode(t,this.options.sampleRate),0!==this.duration&&this.duration!==1/0||(this.duration=this.decodedData.duration)}this.emit("decode",this.duration),this.decodedData&&this.renderer.render(this.decodedData),this.emit("ready",this.duration)}zoom(t){if(!this.decodedData)throw new Error("No audio loaded");this.renderer.zoom(t),this.emit("zoom",t)}getDecodedData(){return this.decodedData}getDuration(){return null!==this.duration?this.duration:super.getDuration()}toggleInteraction(t){this.options.interact=t}seekTo(t){const e=this.getDuration()*t;this.setTime(e)}async playPause(){return this.isPlaying()?this.pause():this.play()}stop(){this.pause(),this.setTime(0)}skip(t){this.setTime(this.getCurrentTime()+t)}empty(){this.load("",[[0]],.001)}destroy(){this.emit("destroy"),this.subscriptions.forEach((t=>t())),this.plugins.forEach((t=>t.destroy())),this.timer.destroy(),this.renderer.destroy(),super.destroy()}}const d=c;return e.default})()));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wavesurfer.js",
|
|
3
|
-
"version": "7.0.0-beta.
|
|
3
|
+
"version": "7.0.0-beta.12",
|
|
4
4
|
"license": "BSD-3-Clause",
|
|
5
5
|
"author": "katspaugh",
|
|
6
6
|
"description": "Navigable audio waveform player",
|
|
@@ -42,10 +42,10 @@
|
|
|
42
42
|
"build:dev": "tsc -w --target ESNext",
|
|
43
43
|
"build:umd": "webpack",
|
|
44
44
|
"build:umd:plugins": "webpack --config webpack.config.plugins.js",
|
|
45
|
-
"build": "tsc && npm run build:umd && npm run build:umd:plugins",
|
|
45
|
+
"build": "rm -rf dist && tsc && npm run build:umd && npm run build:umd:plugins",
|
|
46
46
|
"deploy": "yarn build && yarn docs",
|
|
47
47
|
"prepublishOnly": "npm run build",
|
|
48
|
-
"docs": "typedoc src/wavesurfer.ts src/plugins/*.ts --out docs",
|
|
48
|
+
"docs": "typedoc --titleLink '/' src/wavesurfer.ts src/plugins/*.ts --out docs",
|
|
49
49
|
"lint": "eslint --ext .ts src --fix",
|
|
50
50
|
"prettier": "prettier -w '**/*.{js,ts,css}' --ignore-path .gitignore",
|
|
51
51
|
"cypress": "cypress open --e2e",
|
|
@@ -1,9 +0,0 @@
|
|
|
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;
|
|
@@ -1,150 +0,0 @@
|
|
|
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
|
-
}
|