wavesurfer.js 7.8.4-beta.0 → 7.8.4-beta.1
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/dist/base-plugin.js +3 -1
- package/dist/decoder.js +5 -16
- package/dist/dom.js +1 -1
- package/dist/draggable.js +2 -2
- package/dist/event-emitter.js +3 -6
- package/dist/fetcher.js +37 -50
- package/dist/player.js +4 -14
- package/dist/plugins/envelope.js +355 -1
- package/dist/plugins/hover.js +106 -1
- package/dist/plugins/record.cjs +1 -1
- package/dist/plugins/record.esm.js +1 -1
- package/dist/plugins/record.js +1 -1
- package/dist/plugins/record.min.js +1 -1
- package/dist/renderer.js +88 -108
- package/dist/timer.js +1 -4
- package/dist/wavesurfer.js +76 -95
- package/dist/webaudio.js +33 -50
- package/package.json +1 -1
package/dist/wavesurfer.js
CHANGED
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
1
|
import BasePlugin from './base-plugin.js';
|
|
11
2
|
import Decoder from './decoder.js';
|
|
12
3
|
import * as dom from './dom.js';
|
|
@@ -28,6 +19,16 @@ const defaultOptions = {
|
|
|
28
19
|
sampleRate: 8000,
|
|
29
20
|
};
|
|
30
21
|
class WaveSurfer extends Player {
|
|
22
|
+
options;
|
|
23
|
+
renderer;
|
|
24
|
+
timer;
|
|
25
|
+
plugins = [];
|
|
26
|
+
decodedData = null;
|
|
27
|
+
subscriptions = [];
|
|
28
|
+
mediaSubscriptions = [];
|
|
29
|
+
abortController = null;
|
|
30
|
+
static BasePlugin = BasePlugin;
|
|
31
|
+
static dom = dom;
|
|
31
32
|
/** Create a new WaveSurfer instance */
|
|
32
33
|
static create(options) {
|
|
33
34
|
return new WaveSurfer(options);
|
|
@@ -42,11 +43,6 @@ class WaveSurfer extends Player {
|
|
|
42
43
|
autoplay: options.autoplay,
|
|
43
44
|
playbackRate: options.audioRate,
|
|
44
45
|
});
|
|
45
|
-
this.plugins = [];
|
|
46
|
-
this.decodedData = null;
|
|
47
|
-
this.subscriptions = [];
|
|
48
|
-
this.mediaSubscriptions = [];
|
|
49
|
-
this.abortController = null;
|
|
50
46
|
this.options = Object.assign({}, defaultOptions, options);
|
|
51
47
|
this.timer = new Timer();
|
|
52
48
|
const audioElement = media ? undefined : this.getMediaElement();
|
|
@@ -172,8 +168,7 @@ class WaveSurfer extends Player {
|
|
|
172
168
|
}
|
|
173
169
|
}
|
|
174
170
|
initPlugins() {
|
|
175
|
-
|
|
176
|
-
if (!((_a = this.options.plugins) === null || _a === void 0 ? void 0 : _a.length))
|
|
171
|
+
if (!this.options.plugins?.length)
|
|
177
172
|
return;
|
|
178
173
|
this.options.plugins.forEach((plugin) => {
|
|
179
174
|
this.registerPlugin(plugin);
|
|
@@ -229,80 +224,73 @@ class WaveSurfer extends Player {
|
|
|
229
224
|
getActivePlugins() {
|
|
230
225
|
return this.plugins;
|
|
231
226
|
}
|
|
232
|
-
loadAudio(url, blob, channelData, duration) {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
this.
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
if (
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
this.abortController = new AbortController();
|
|
244
|
-
fetchParams.signal = (_a = this.abortController) === null || _a === void 0 ? void 0 : _a.signal;
|
|
245
|
-
}
|
|
246
|
-
const onProgress = (percentage) => this.emit('loading', percentage);
|
|
247
|
-
blob = yield Fetcher.fetchBlob(url, onProgress, fetchParams);
|
|
248
|
-
}
|
|
249
|
-
// Set the mediaelement source
|
|
250
|
-
this.setSrc(url, blob);
|
|
251
|
-
// Wait for the audio duration
|
|
252
|
-
const audioDuration = yield new Promise((resolve) => {
|
|
253
|
-
const staticDuration = duration || this.getDuration();
|
|
254
|
-
if (staticDuration) {
|
|
255
|
-
resolve(staticDuration);
|
|
256
|
-
}
|
|
257
|
-
else {
|
|
258
|
-
this.mediaSubscriptions.push(this.onMediaEvent('loadedmetadata', () => resolve(this.getDuration()), { once: true }));
|
|
259
|
-
}
|
|
260
|
-
});
|
|
261
|
-
// Set the duration if the player is a WebAudioPlayer without a URL
|
|
262
|
-
if (!url && !blob) {
|
|
263
|
-
const media = this.getMediaElement();
|
|
264
|
-
if (media instanceof WebAudioPlayer) {
|
|
265
|
-
media.duration = audioDuration;
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
// Decode the audio data or use user-provided peaks
|
|
269
|
-
if (channelData) {
|
|
270
|
-
this.decodedData = Decoder.createBuffer(channelData, audioDuration || 0);
|
|
227
|
+
async loadAudio(url, blob, channelData, duration) {
|
|
228
|
+
this.emit('load', url);
|
|
229
|
+
if (!this.options.media && this.isPlaying())
|
|
230
|
+
this.pause();
|
|
231
|
+
this.decodedData = null;
|
|
232
|
+
// Fetch the entire audio as a blob if pre-decoded data is not provided
|
|
233
|
+
if (!blob && !channelData) {
|
|
234
|
+
const fetchParams = this.options.fetchParams || {};
|
|
235
|
+
if (window.AbortController && !fetchParams.signal) {
|
|
236
|
+
this.abortController = new AbortController();
|
|
237
|
+
fetchParams.signal = this.abortController?.signal;
|
|
271
238
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
239
|
+
const onProgress = (percentage) => this.emit('loading', percentage);
|
|
240
|
+
blob = await Fetcher.fetchBlob(url, onProgress, fetchParams);
|
|
241
|
+
}
|
|
242
|
+
// Set the mediaelement source
|
|
243
|
+
this.setSrc(url, blob);
|
|
244
|
+
// Wait for the audio duration
|
|
245
|
+
const audioDuration = await new Promise((resolve) => {
|
|
246
|
+
const staticDuration = duration || this.getDuration();
|
|
247
|
+
if (staticDuration) {
|
|
248
|
+
resolve(staticDuration);
|
|
275
249
|
}
|
|
276
|
-
|
|
277
|
-
this.
|
|
278
|
-
this.renderer.render(this.decodedData);
|
|
250
|
+
else {
|
|
251
|
+
this.mediaSubscriptions.push(this.onMediaEvent('loadedmetadata', () => resolve(this.getDuration()), { once: true }));
|
|
279
252
|
}
|
|
280
|
-
this.emit('ready', this.getDuration());
|
|
281
253
|
});
|
|
254
|
+
// Set the duration if the player is a WebAudioPlayer without a URL
|
|
255
|
+
if (!url && !blob) {
|
|
256
|
+
const media = this.getMediaElement();
|
|
257
|
+
if (media instanceof WebAudioPlayer) {
|
|
258
|
+
media.duration = audioDuration;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
// Decode the audio data or use user-provided peaks
|
|
262
|
+
if (channelData) {
|
|
263
|
+
this.decodedData = Decoder.createBuffer(channelData, audioDuration || 0);
|
|
264
|
+
}
|
|
265
|
+
else if (blob) {
|
|
266
|
+
const arrayBuffer = await blob.arrayBuffer();
|
|
267
|
+
this.decodedData = await Decoder.decode(arrayBuffer, this.options.sampleRate);
|
|
268
|
+
}
|
|
269
|
+
if (this.decodedData) {
|
|
270
|
+
this.emit('decode', this.getDuration());
|
|
271
|
+
this.renderer.render(this.decodedData);
|
|
272
|
+
}
|
|
273
|
+
this.emit('ready', this.getDuration());
|
|
282
274
|
}
|
|
283
275
|
/** Load an audio file by URL, with optional pre-decoded audio data */
|
|
284
|
-
load(url, channelData, duration) {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
}
|
|
293
|
-
});
|
|
276
|
+
async load(url, channelData, duration) {
|
|
277
|
+
try {
|
|
278
|
+
return await this.loadAudio(url, undefined, channelData, duration);
|
|
279
|
+
}
|
|
280
|
+
catch (err) {
|
|
281
|
+
this.emit('error', err);
|
|
282
|
+
throw err;
|
|
283
|
+
}
|
|
294
284
|
}
|
|
295
285
|
/** Load an audio blob */
|
|
296
|
-
loadBlob(blob, channelData, duration) {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
}
|
|
305
|
-
});
|
|
286
|
+
async loadBlob(blob, channelData, duration) {
|
|
287
|
+
try {
|
|
288
|
+
return await this.loadAudio('', blob, channelData, duration);
|
|
289
|
+
}
|
|
290
|
+
catch (err) {
|
|
291
|
+
this.emit('error', err);
|
|
292
|
+
throw err;
|
|
293
|
+
}
|
|
306
294
|
}
|
|
307
295
|
/** Zoom the waveform by a given pixels-per-second factor */
|
|
308
296
|
zoom(minPxPerSec) {
|
|
@@ -317,7 +305,7 @@ class WaveSurfer extends Player {
|
|
|
317
305
|
return this.decodedData;
|
|
318
306
|
}
|
|
319
307
|
/** Get decoded peaks */
|
|
320
|
-
exportPeaks({ channels = 2, maxLength = 8000, precision =
|
|
308
|
+
exportPeaks({ channels = 2, maxLength = 8000, precision = 10_000 } = {}) {
|
|
321
309
|
if (!this.decodedData) {
|
|
322
310
|
throw new Error('The audio has not been decoded yet');
|
|
323
311
|
}
|
|
@@ -366,10 +354,8 @@ class WaveSurfer extends Player {
|
|
|
366
354
|
this.setTime(time);
|
|
367
355
|
}
|
|
368
356
|
/** Play or pause the audio */
|
|
369
|
-
playPause() {
|
|
370
|
-
return
|
|
371
|
-
return this.isPlaying() ? this.pause() : this.play();
|
|
372
|
-
});
|
|
357
|
+
async playPause() {
|
|
358
|
+
return this.isPlaying() ? this.pause() : this.play();
|
|
373
359
|
}
|
|
374
360
|
/** Stop the audio and go to the beginning */
|
|
375
361
|
stop() {
|
|
@@ -390,16 +376,13 @@ class WaveSurfer extends Player {
|
|
|
390
376
|
super.setMediaElement(element);
|
|
391
377
|
this.initPlayerEvents();
|
|
392
378
|
}
|
|
393
|
-
exportImage() {
|
|
394
|
-
return
|
|
395
|
-
return this.renderer.exportImage(format, quality, type);
|
|
396
|
-
});
|
|
379
|
+
async exportImage(format = 'image/png', quality = 1, type = 'dataURL') {
|
|
380
|
+
return this.renderer.exportImage(format, quality, type);
|
|
397
381
|
}
|
|
398
382
|
/** Unmount wavesurfer */
|
|
399
383
|
destroy() {
|
|
400
|
-
var _a;
|
|
401
384
|
this.emit('destroy');
|
|
402
|
-
|
|
385
|
+
this.abortController?.abort();
|
|
403
386
|
this.plugins.forEach((plugin) => plugin.destroy());
|
|
404
387
|
this.subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
405
388
|
this.unsubscribePlayerEvents();
|
|
@@ -408,6 +391,4 @@ class WaveSurfer extends Player {
|
|
|
408
391
|
super.destroy();
|
|
409
392
|
}
|
|
410
393
|
}
|
|
411
|
-
WaveSurfer.BasePlugin = BasePlugin;
|
|
412
|
-
WaveSurfer.dom = dom;
|
|
413
394
|
export default WaveSurfer;
|
package/dist/webaudio.js
CHANGED
|
@@ -1,43 +1,34 @@
|
|
|
1
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
1
|
import EventEmitter from './event-emitter.js';
|
|
11
2
|
/**
|
|
12
3
|
* A Web Audio buffer player emulating the behavior of an HTML5 Audio element.
|
|
13
4
|
*/
|
|
14
5
|
class WebAudioPlayer extends EventEmitter {
|
|
6
|
+
audioContext;
|
|
7
|
+
gainNode;
|
|
8
|
+
bufferNode = null;
|
|
9
|
+
playStartTime = 0;
|
|
10
|
+
playedDuration = 0;
|
|
11
|
+
_muted = false;
|
|
12
|
+
_playbackRate = 1;
|
|
13
|
+
_duration = undefined;
|
|
14
|
+
buffer = null;
|
|
15
|
+
currentSrc = '';
|
|
16
|
+
paused = true;
|
|
17
|
+
crossOrigin = null;
|
|
18
|
+
seeking = false;
|
|
19
|
+
autoplay = false;
|
|
15
20
|
constructor(audioContext = new AudioContext()) {
|
|
16
21
|
super();
|
|
17
|
-
this.bufferNode = null;
|
|
18
|
-
this.playStartTime = 0;
|
|
19
|
-
this.playedDuration = 0;
|
|
20
|
-
this._muted = false;
|
|
21
|
-
this._playbackRate = 1;
|
|
22
|
-
this._duration = undefined;
|
|
23
|
-
this.buffer = null;
|
|
24
|
-
this.currentSrc = '';
|
|
25
|
-
this.paused = true;
|
|
26
|
-
this.crossOrigin = null;
|
|
27
|
-
this.seeking = false;
|
|
28
|
-
this.autoplay = false;
|
|
29
|
-
/** Subscribe to an event. Returns an unsubscribe function. */
|
|
30
|
-
this.addEventListener = this.on;
|
|
31
|
-
/** Unsubscribe from an event */
|
|
32
|
-
this.removeEventListener = this.un;
|
|
33
22
|
this.audioContext = audioContext;
|
|
34
23
|
this.gainNode = this.audioContext.createGain();
|
|
35
24
|
this.gainNode.connect(this.audioContext.destination);
|
|
36
25
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
26
|
+
/** Subscribe to an event. Returns an unsubscribe function. */
|
|
27
|
+
addEventListener = this.on;
|
|
28
|
+
/** Unsubscribe from an event */
|
|
29
|
+
removeEventListener = this.un;
|
|
30
|
+
async load() {
|
|
31
|
+
return;
|
|
41
32
|
}
|
|
42
33
|
get src() {
|
|
43
34
|
return this.currentSrc;
|
|
@@ -73,11 +64,10 @@ class WebAudioPlayer extends EventEmitter {
|
|
|
73
64
|
});
|
|
74
65
|
}
|
|
75
66
|
_play() {
|
|
76
|
-
var _a;
|
|
77
67
|
if (!this.paused)
|
|
78
68
|
return;
|
|
79
69
|
this.paused = false;
|
|
80
|
-
|
|
70
|
+
this.bufferNode?.disconnect();
|
|
81
71
|
this.bufferNode = this.audioContext.createBufferSource();
|
|
82
72
|
if (this.buffer) {
|
|
83
73
|
this.bufferNode.buffer = this.buffer;
|
|
@@ -99,18 +89,15 @@ class WebAudioPlayer extends EventEmitter {
|
|
|
99
89
|
};
|
|
100
90
|
}
|
|
101
91
|
_pause() {
|
|
102
|
-
var _a;
|
|
103
92
|
this.paused = true;
|
|
104
|
-
|
|
93
|
+
this.bufferNode?.stop();
|
|
105
94
|
this.playedDuration += this.audioContext.currentTime - this.playStartTime;
|
|
106
95
|
}
|
|
107
|
-
play() {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
this.emit('play');
|
|
113
|
-
});
|
|
96
|
+
async play() {
|
|
97
|
+
if (!this.paused)
|
|
98
|
+
return;
|
|
99
|
+
this._play();
|
|
100
|
+
this.emit('play');
|
|
114
101
|
}
|
|
115
102
|
pause() {
|
|
116
103
|
if (this.paused)
|
|
@@ -119,19 +106,16 @@ class WebAudioPlayer extends EventEmitter {
|
|
|
119
106
|
this.emit('pause');
|
|
120
107
|
}
|
|
121
108
|
stopAt(timeSeconds) {
|
|
122
|
-
var _a, _b;
|
|
123
109
|
const delay = timeSeconds - this.currentTime;
|
|
124
|
-
|
|
125
|
-
|
|
110
|
+
this.bufferNode?.stop(this.audioContext.currentTime + delay);
|
|
111
|
+
this.bufferNode?.addEventListener('ended', () => {
|
|
126
112
|
this.bufferNode = null;
|
|
127
113
|
this.pause();
|
|
128
114
|
}, { once: true });
|
|
129
115
|
}
|
|
130
|
-
setSinkId(deviceId) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
return ac.setSinkId(deviceId);
|
|
134
|
-
});
|
|
116
|
+
async setSinkId(deviceId) {
|
|
117
|
+
const ac = this.audioContext;
|
|
118
|
+
return ac.setSinkId(deviceId);
|
|
135
119
|
}
|
|
136
120
|
get playbackRate() {
|
|
137
121
|
return this._playbackRate;
|
|
@@ -157,8 +141,7 @@ class WebAudioPlayer extends EventEmitter {
|
|
|
157
141
|
this.emit('timeupdate');
|
|
158
142
|
}
|
|
159
143
|
get duration() {
|
|
160
|
-
|
|
161
|
-
return (_a = this._duration) !== null && _a !== void 0 ? _a : (((_b = this.buffer) === null || _b === void 0 ? void 0 : _b.duration) || 0);
|
|
144
|
+
return this._duration ?? (this.buffer?.duration || 0);
|
|
162
145
|
}
|
|
163
146
|
set duration(value) {
|
|
164
147
|
this._duration = value;
|