wavesurfer.js 7.0.0-alpha.19 → 7.0.0-alpha.20

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.
@@ -1,7 +1,9 @@
1
1
  import WaveSurfer from '../index.js';
2
2
  import RegionsPlugin from './regions.js';
3
3
  import TimelinePlugin from './timeline.js';
4
- class MultiTrack {
4
+ import EnvelopePlugin from './envelope.js';
5
+ import EventEmitter from '../event-emitter.js';
6
+ class MultiTrack extends EventEmitter {
5
7
  tracks;
6
8
  options;
7
9
  audios = [];
@@ -12,10 +14,14 @@ class MultiTrack {
12
14
  rendering;
13
15
  isDragging = false;
14
16
  frameRequest = null;
17
+ timer = null;
18
+ subscriptions = [];
19
+ timeline = null;
15
20
  static create(tracks, options) {
16
21
  return new MultiTrack(tracks, options);
17
22
  }
18
23
  constructor(tracks, options) {
24
+ super();
19
25
  this.tracks = tracks.map((track) => ({
20
26
  ...track,
21
27
  startPosition: track.startPosition || 0,
@@ -23,98 +29,142 @@ class MultiTrack {
23
29
  }));
24
30
  this.options = options;
25
31
  this.rendering = initRendering(this.tracks, this.options);
26
- this.initAudios().then((durations) => {
27
- this.durations = durations;
28
- const maxDuration = this.tracks.reduce((max, track, index) => {
29
- return Math.max(max, track.startPosition + durations[index]);
30
- }, 0);
31
- this.rendering.setMainWidth(durations, maxDuration);
32
- this.rendering.addClickHandler((position) => {
33
- if (this.isDragging)
34
- return;
35
- this.seekTo(position * maxDuration);
36
- });
37
- this.maxDuration = maxDuration;
38
- this.initWavesurfers();
39
- this.initTimeline();
32
+ this.rendering.addDropHandler((trackId) => {
33
+ this.emit('drop', { id: trackId });
34
+ });
35
+ this.initAllAudios().then((durations) => {
36
+ this.initDurations(durations);
37
+ this.initAllWavesurfers();
40
38
  this.rendering.containers.forEach((container, index) => {
41
39
  const drag = initDragging(container, (delta) => this.onDrag(index, delta), options.rightButtonDrag);
42
- this.wavesurfers[index].once('destroy', () => {
43
- drag?.destroy();
44
- });
40
+ this.wavesurfers[index].once('destroy', () => drag?.destroy());
45
41
  });
42
+ this.emit('canplay');
46
43
  });
47
44
  }
48
- initAudios() {
49
- this.audios = this.tracks.map((track) => new Audio(track.url));
50
- return Promise.all(this.audios.map((audio) => {
51
- return new Promise((resolve) => {
52
- if (!audio.src)
53
- return resolve(0);
54
- audio.addEventListener('canplay', () => {
55
- resolve(audio.duration);
56
- }, { once: true });
57
- });
45
+ initDurations(durations) {
46
+ this.durations = durations;
47
+ this.maxDuration = this.tracks.reduce((max, track, index) => {
48
+ return Math.max(max, track.startPosition + durations[index]);
49
+ }, 0);
50
+ this.rendering.setMainWidth(durations, this.maxDuration);
51
+ this.rendering.addClickHandler((position) => {
52
+ if (this.isDragging)
53
+ return;
54
+ this.seekTo(position * this.maxDuration);
55
+ });
56
+ }
57
+ initAudio(track) {
58
+ const audio = new Audio(track.url);
59
+ return new Promise((resolve) => {
60
+ if (!audio.src)
61
+ return resolve(audio);
62
+ audio.addEventListener('loadedmetadata', () => resolve(audio), { once: true });
63
+ });
64
+ }
65
+ async initAllAudios() {
66
+ this.audios = await Promise.all(this.tracks.map((track) => this.initAudio(track)));
67
+ return this.audios.map((a) => (a.src ? a.duration : 0));
68
+ }
69
+ initWavesurfer(track, index) {
70
+ const container = this.rendering.containers[index];
71
+ // Create a wavesurfer instance
72
+ const ws = WaveSurfer.create({
73
+ ...track.options,
74
+ container,
75
+ minPxPerSec: 0,
76
+ media: this.audios[index],
77
+ peaks: track.peaks,
78
+ cursorColor: 'transparent',
79
+ cursorWidth: 0,
80
+ interactive: false,
81
+ });
82
+ // Regions and markers
83
+ const wsRegions = ws.registerPlugin(RegionsPlugin, {
84
+ draggable: false,
85
+ resizable: true,
86
+ dragSelection: false,
87
+ });
88
+ this.subscriptions.push(ws.once('decode', () => {
89
+ // Start and end cues
90
+ if (track.startCue != null || track.endCue != null) {
91
+ const { startCue = 0, endCue = this.durations[index] } = track;
92
+ const startCueRegion = wsRegions.add(0, startCue, '', 'rgba(0, 0, 0, 0.7)');
93
+ const endCueRegion = wsRegions.add(endCue, endCue + this.durations[index], '', 'rgba(0, 0, 0, 0.7)');
94
+ // Allow resizing only from one side
95
+ startCueRegion.element.firstElementChild?.remove();
96
+ endCueRegion.element.lastChild?.remove();
97
+ // Update the start and end cues on resize
98
+ this.subscriptions.push(wsRegions.on('region-updated', ({ region }) => {
99
+ this.setIsDragging();
100
+ if (region === startCueRegion || region === endCueRegion) {
101
+ if (region === startCueRegion) {
102
+ track.startCue = region.endTime;
103
+ this.emit('start-cue-change', { id: track.id, startCue: track.startCue });
104
+ }
105
+ else {
106
+ track.endCue = region.startTime;
107
+ this.emit('end-cue-change', { id: track.id, endCue: track.endCue });
108
+ }
109
+ }
110
+ }));
111
+ }
112
+ // Render regions
113
+ if (track.regions) {
114
+ track.regions.forEach((params) => {
115
+ const region = wsRegions.add(params.startTime || 0, params.endTime, params.label, params.color);
116
+ if (!params.startTime) {
117
+ region.element.firstElementChild?.remove();
118
+ }
119
+ });
120
+ }
121
+ // Render markers
122
+ if (track.markers) {
123
+ track.markers.forEach((marker) => {
124
+ wsRegions.add(marker.time, marker.time, marker.label, marker.color);
125
+ });
126
+ }
127
+ }));
128
+ // Envelope
129
+ const envelope = ws.registerPlugin(EnvelopePlugin, {
130
+ ...this.options.envelopeOptions,
131
+ startTime: track.startCue,
132
+ endTime: track.endCue,
133
+ fadeInEnd: track.fadeInEnd,
134
+ fadeOutStart: track.fadeOutStart,
135
+ volume: track.volume,
136
+ });
137
+ this.subscriptions.push(envelope.on('volume-change', ({ volume }) => {
138
+ this.setIsDragging();
139
+ this.emit('volume-change', { id: track.id, volume });
140
+ }), envelope.on('fade-in-change', ({ time }) => {
141
+ this.setIsDragging();
142
+ this.emit('fade-in-change', { id: track.id, fadeInEnd: time });
143
+ }), envelope.on('fade-out-change', ({ time }) => {
144
+ this.setIsDragging();
145
+ this.emit('fade-out-change', { id: track.id, fadeOutStart: time });
58
146
  }));
147
+ return ws;
59
148
  }
60
- initWavesurfers() {
149
+ initAllWavesurfers() {
61
150
  const wavesurfers = this.tracks.map((track, index) => {
62
- // Create a wavesurfer instance
63
- const ws = WaveSurfer.create({
64
- ...track.options,
65
- container: this.rendering.containers[index],
66
- minPxPerSec: 0,
67
- media: this.audios[index],
68
- peaks: track.peaks,
69
- cursorColor: 'transparent',
70
- cursorWidth: 0,
71
- interactive: false,
72
- });
73
- const wsRegions = ws.registerPlugin(RegionsPlugin, {
74
- draggable: false,
75
- resizable: true,
76
- dragSelection: false,
77
- });
78
- ws.once('decode', () => {
79
- // Render start and end cues
80
- if (track.startCue) {
81
- const region = wsRegions.add(0, track.startCue, '', 'rgba(0, 0, 0, 0.7)');
82
- region.element.firstElementChild?.remove();
83
- }
84
- if (track.endCue) {
85
- const region = wsRegions.add(track.endCue, track.endCue + this.durations[index], '', 'rgba(0, 0, 0, 0.7)');
86
- region.element.lastChild?.remove();
87
- }
88
- // Render regions
89
- if (track.regions) {
90
- track.regions.forEach((params) => {
91
- const region = wsRegions.add(params.startTime || 0, params.endTime, params.label, params.color);
92
- if (!params.startTime) {
93
- region.element.firstElementChild?.remove();
94
- }
95
- });
96
- }
97
- // Render markers
98
- if (track.markers) {
99
- track.markers.forEach((marker) => {
100
- wsRegions.add(marker.time, marker.time, marker.label, marker.color);
101
- });
102
- }
103
- });
104
- return ws;
151
+ return this.initWavesurfer(track, index);
105
152
  });
106
153
  this.wavesurfers = wavesurfers;
154
+ this.initTimeline();
107
155
  }
108
156
  initTimeline() {
109
- this.wavesurfers[0].registerPlugin(TimelinePlugin, {
157
+ if (this.timeline)
158
+ this.timeline.destroy();
159
+ this.timeline = this.wavesurfers[0].registerPlugin(TimelinePlugin, {
110
160
  duration: this.maxDuration,
111
161
  container: this.rendering.containers[0].parentElement,
112
162
  });
113
163
  }
114
- updatePosition(time) {
164
+ updatePosition(time, autoCenter = false) {
115
165
  const precisionSeconds = 0.3;
116
166
  this.currentTime = time;
117
- this.rendering.updateCursor(time / this.maxDuration);
167
+ this.rendering.updateCursor(time / this.maxDuration, autoCenter);
118
168
  const isPaused = !this.isPlaying();
119
169
  // Update the current time of each audio
120
170
  this.tracks.forEach((track, index) => {
@@ -138,10 +188,15 @@ class MultiTrack {
138
188
  audio.volume = newVolume;
139
189
  });
140
190
  }
141
- onDrag(index, delta) {
191
+ setIsDragging() {
142
192
  // Prevent click events when dragging
143
193
  this.isDragging = true;
144
- setTimeout(() => (this.isDragging = false), 600);
194
+ if (this.timer)
195
+ clearTimeout(this.timer);
196
+ this.timer = setTimeout(() => (this.isDragging = false), 300);
197
+ }
198
+ onDrag(index, delta) {
199
+ this.setIsDragging();
145
200
  const newTime = this.tracks[index].startPosition + delta * this.maxDuration;
146
201
  this.onMove(index, newTime);
147
202
  }
@@ -157,7 +212,7 @@ class MultiTrack {
157
212
  track.startPosition = newStartPosition;
158
213
  this.rendering.setContainerOffsets();
159
214
  this.updatePosition(this.currentTime);
160
- this.options.onTrackPositionUpdate?.(track.id, track.startPosition);
215
+ this.emit('start-position-change', { id: track.id, startPosition: newStartPosition });
161
216
  }
162
217
  }
163
218
  findCurrentTracks() {
@@ -185,7 +240,7 @@ class MultiTrack {
185
240
  return pos;
186
241
  }, this.currentTime);
187
242
  if (position > this.currentTime) {
188
- this.updatePosition(position);
243
+ this.updatePosition(position, true);
189
244
  }
190
245
  this.frameRequest = requestAnimationFrame(onFrame);
191
246
  };
@@ -204,6 +259,9 @@ class MultiTrack {
204
259
  isPlaying() {
205
260
  return this.audios.some((audio) => !audio.paused);
206
261
  }
262
+ getCurrentTime() {
263
+ return this.currentTime;
264
+ }
207
265
  seekTo(time) {
208
266
  const wasPlaying = this.isPlaying();
209
267
  this.updatePosition(time);
@@ -216,6 +274,25 @@ class MultiTrack {
216
274
  this.rendering.setMainWidth(this.durations, this.maxDuration);
217
275
  this.rendering.setContainerOffsets();
218
276
  }
277
+ addTrack(track) {
278
+ const index = this.tracks.findIndex((t) => t.id === track.id);
279
+ if (index !== -1) {
280
+ this.tracks[index] = track;
281
+ this.initAudio(track).then((audio) => {
282
+ this.audios[index] = audio;
283
+ this.durations[index] = audio.duration;
284
+ this.initDurations(this.durations);
285
+ const container = this.rendering.containers[index];
286
+ container.innerHTML = '';
287
+ this.wavesurfers[index].destroy();
288
+ this.wavesurfers[index] = this.initWavesurfer(track, index);
289
+ const drag = initDragging(container, (delta) => this.onDrag(index, delta), this.options.rightButtonDrag);
290
+ this.wavesurfers[index].once('destroy', () => drag?.destroy());
291
+ this.initTimeline();
292
+ this.emit('canplay');
293
+ });
294
+ }
295
+ }
219
296
  destroy() {
220
297
  if (this.frameRequest)
221
298
  cancelAnimationFrame(this.frameRequest);
@@ -228,10 +305,18 @@ class MultiTrack {
228
305
  ws.destroy();
229
306
  });
230
307
  }
308
+ // See https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/setSinkId
309
+ setSinkId(sinkId) {
310
+ return Promise.all(this.audios.map((item) => {
311
+ const audio = item;
312
+ return audio.setSinkId ? audio.setSinkId(sinkId) : Promise.resolve();
313
+ }));
314
+ }
231
315
  }
232
316
  function initRendering(tracks, options) {
233
317
  let pxPerSec = 0;
234
318
  let durations = [];
319
+ let mainWidth = 0;
235
320
  // Create a common container for all tracks
236
321
  const scroll = document.createElement('div');
237
322
  scroll.setAttribute('style', 'width: 100%; overflow-x: scroll; overflow-y: hidden; user-select: none;');
@@ -247,16 +332,35 @@ function initRendering(tracks, options) {
247
332
  wrapper.appendChild(cursor);
248
333
  const { clientWidth } = wrapper;
249
334
  // Create containers for each track
250
- const containers = tracks.map((_, index) => {
335
+ const containers = tracks.map((track, index) => {
251
336
  const container = document.createElement('div');
337
+ container.style.position = 'relative';
252
338
  if (options.trackBorderColor && index > 0) {
253
339
  const borderDiv = document.createElement('div');
254
340
  borderDiv.setAttribute('style', `width: 100%; height: 2px; background-color: ${options.trackBorderColor}`);
255
341
  wrapper.appendChild(borderDiv);
256
342
  }
257
- if (options.trackBackground) {
343
+ if (options.trackBackground && track.url) {
258
344
  container.style.background = options.trackBackground;
259
345
  }
346
+ // No audio on this track, so make it droppable
347
+ if (!track.url) {
348
+ const dropArea = document.createElement('div');
349
+ dropArea.setAttribute('style', `position: absolute; z-index: 10; left: 10px; top: 10px; right: 10px; bottom: 10px; border: 2px dashed ${options.trackBorderColor};`);
350
+ dropArea.addEventListener('dragover', (e) => {
351
+ e.preventDefault();
352
+ dropArea.style.background = options.trackBackground || '';
353
+ });
354
+ dropArea.addEventListener('dragleave', (e) => {
355
+ e.preventDefault();
356
+ dropArea.style.background = '';
357
+ });
358
+ dropArea.addEventListener('drop', (e) => {
359
+ e.preventDefault();
360
+ dropArea.style.background = '';
361
+ });
362
+ container.appendChild(dropArea);
363
+ }
260
364
  wrapper.appendChild(container);
261
365
  return container;
262
366
  });
@@ -264,10 +368,10 @@ function initRendering(tracks, options) {
264
368
  const setContainerOffsets = () => {
265
369
  containers.forEach((container, i) => {
266
370
  const offset = tracks[i].startPosition * pxPerSec;
267
- container.style.width = `${durations[i] * pxPerSec}px`;
371
+ if (durations[i]) {
372
+ container.style.width = `${durations[i] * pxPerSec}px`;
373
+ }
268
374
  container.style.transform = `translateX(${offset}px)`;
269
- if (tracks[i].draggable)
270
- container.style.cursor = 'move';
271
375
  });
272
376
  };
273
377
  return {
@@ -278,13 +382,21 @@ function initRendering(tracks, options) {
278
382
  setMainWidth: (trackDurations, maxDuration) => {
279
383
  durations = trackDurations;
280
384
  pxPerSec = Math.max(options.minPxPerSec || 0, clientWidth / maxDuration);
281
- const width = pxPerSec * maxDuration;
282
- wrapper.style.width = `${width}px`;
385
+ mainWidth = pxPerSec * maxDuration;
386
+ wrapper.style.width = `${mainWidth}px`;
283
387
  setContainerOffsets();
284
388
  },
285
389
  // Update cursor position
286
- updateCursor: (position) => {
390
+ updateCursor: (position, autoCenter) => {
287
391
  cursor.style.left = `${Math.min(100, position * 100)}%`;
392
+ // Update scroll
393
+ const { clientWidth, scrollLeft } = scroll;
394
+ const center = clientWidth / 2;
395
+ const minScroll = autoCenter ? center : clientWidth;
396
+ const pos = position * mainWidth;
397
+ if (pos > scrollLeft + minScroll || pos < scrollLeft) {
398
+ scroll.scrollLeft = pos - center;
399
+ }
288
400
  },
289
401
  // Click to seek
290
402
  addClickHandler: (onClick) => {
@@ -299,6 +411,18 @@ function initRendering(tracks, options) {
299
411
  destroy: () => {
300
412
  scroll.remove();
301
413
  },
414
+ // Do something on drop
415
+ addDropHandler: (onDrop) => {
416
+ tracks.forEach((track, index) => {
417
+ if (!track.url) {
418
+ const droppable = containers[index].querySelector('div');
419
+ droppable?.addEventListener('drop', (e) => {
420
+ e.preventDefault();
421
+ onDrop(track.id);
422
+ });
423
+ }
424
+ });
425
+ },
302
426
  };
303
427
  }
304
428
  function initDragging(container, onDrag, rightButtonDrag = false) {
@@ -316,12 +440,14 @@ function initDragging(container, onDrag, rightButtonDrag = false) {
316
440
  return;
317
441
  const rect = wrapper.getBoundingClientRect();
318
442
  dragStart = e.clientX - rect.left;
443
+ container.style.cursor = 'grabbing';
319
444
  });
320
445
  // Drag end
321
446
  const onMouseUp = (e) => {
322
447
  if (dragStart != null) {
323
448
  e.stopPropagation();
324
449
  dragStart = null;
450
+ container.style.cursor = '';
325
451
  }
326
452
  };
327
453
  // Drag move
@@ -163,6 +163,21 @@ class RegionsPlugin extends BasePlugin {
163
163
  }
164
164
  });
165
165
  this.regionsContainer.appendChild(div);
166
+ // Check that the label doesn't overlap with other labels
167
+ // If it does, push it down
168
+ const labelLeft = div.getBoundingClientRect().left;
169
+ const labelWidth = div.scrollWidth;
170
+ const overlap = this.regions
171
+ .filter((reg) => {
172
+ const { left } = reg.element.getBoundingClientRect();
173
+ const width = reg.element.scrollWidth;
174
+ return labelLeft < left + width && left < labelLeft + labelWidth;
175
+ })
176
+ .map((reg) => parseFloat(reg.element.style.paddingTop))
177
+ .reduce((sum, val) => sum + val, 0);
178
+ if (overlap > 0) {
179
+ div.style.paddingTop = `${overlap + 1}em`;
180
+ }
166
181
  return div;
167
182
  }
168
183
  createRegion(start, end, title = '') {
@@ -26,6 +26,7 @@ declare class Renderer extends EventEmitter<RendererEvents> {
26
26
  private canvasWrapper;
27
27
  private progressWrapper;
28
28
  private timeout;
29
+ private isScrolling;
29
30
  constructor(options: RendererOptions);
30
31
  getContainer(): HTMLElement;
31
32
  getWrapper(): HTMLElement;
package/dist/renderer.js CHANGED
@@ -7,6 +7,7 @@ class Renderer extends EventEmitter {
7
7
  canvasWrapper;
8
8
  progressWrapper;
9
9
  timeout = null;
10
+ isScrolling = false;
10
11
  constructor(options) {
11
12
  super();
12
13
  this.options = options;
@@ -201,12 +202,12 @@ class Renderer extends EventEmitter {
201
202
  const pixelRatio = window.devicePixelRatio || 1;
202
203
  const parentWidth = this.options.fillParent ? this.scrollContainer.clientWidth * pixelRatio : 0;
203
204
  const scrollWidth = audioData.duration * this.options.minPxPerSec;
204
- const isScrolling = scrollWidth > parentWidth;
205
- const width = Math.max(1, isScrolling ? scrollWidth : parentWidth);
205
+ this.isScrolling = scrollWidth > parentWidth;
206
+ const width = Math.max(1, this.isScrolling ? scrollWidth : parentWidth);
206
207
  const { height } = this.options;
207
208
  // Remember the current cursor position
208
209
  const oldCursorPosition = this.progressWrapper.clientWidth;
209
- this.scrollContainer.style.overflowX = isScrolling ? 'auto' : 'hidden';
210
+ this.scrollContainer.style.overflowX = this.isScrolling ? 'auto' : 'hidden';
210
211
  this.wrapper.style.width = `${Math.floor(width / pixelRatio)}px`;
211
212
  // Adjust the scroll position so that the cursor stays in the same place
212
213
  const newCursortPosition = this.progressWrapper.clientWidth;
@@ -224,12 +225,14 @@ class Renderer extends EventEmitter {
224
225
  }
225
226
  renderProgress(progress, autoCenter = false) {
226
227
  this.progressWrapper.style.width = `${progress * 100}%`;
227
- const containerWidth = this.scrollContainer.clientWidth;
228
- const center = containerWidth / 2;
229
- const progressWidth = this.progressWrapper.clientWidth;
230
- const minScroll = autoCenter ? center : containerWidth;
231
- if (progressWidth > this.scrollContainer.scrollLeft + minScroll) {
232
- this.scrollContainer.scrollLeft = progressWidth - center;
228
+ if (this.isScrolling) {
229
+ const containerWidth = this.scrollContainer.clientWidth;
230
+ const center = containerWidth / 2;
231
+ const progressWidth = this.progressWrapper.clientWidth;
232
+ const minScroll = autoCenter ? center : containerWidth;
233
+ if (progressWidth > this.scrollContainer.scrollLeft + minScroll) {
234
+ this.scrollContainer.scrollLeft = progressWidth - center;
235
+ }
233
236
  }
234
237
  }
235
238
  }
@@ -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.Minimap=e():t.Minimap=e()}(WaveSurfer,(()=>(()=>{"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=class{eventTarget;constructor(){this.eventTarget=new EventTarget}emit(t,e){const i=new CustomEvent(String(t),{detail:e});this.eventTarget.dispatchEvent(i)}on(t,e,i){const s=t=>{t instanceof CustomEvent&&e(t.detail)},r=String(t);return this.eventTarget.addEventListener(r,s,{once:i}),()=>this.eventTarget.removeEventListener(r,s)}once(t,e){return this.on(t,e,!0)}},s=class extends i{wavesurfer;container;wrapper;subscriptions=[];options;constructor(t,e){super(),this.wavesurfer=t.wavesurfer,this.container=t.container,this.wrapper=t.wrapper,this.options=e}destroy(){this.subscriptions.forEach((t=>t()))}},r=class extends i{options;container;scrollContainer;wrapper;canvasWrapper;progressWrapper;timeout=null;constructor(t){super(),this.options=t;let e=null;if("string"==typeof this.options.container?e=document.querySelector(this.options.container):this.options.container instanceof HTMLElement&&(e=this.options.container),!e)throw new Error("Container not found");const i=document.createElement("div"),s=i.attachShadow({mode:"open"});s.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 ${this.options.noScrollbar?"scrollbar-color: transparent;":""}\n }\n :host ::-webkit-scrollbar {\n display: ${this.options.noScrollbar?"none":"auto"};\n }\n :host .wrapper {\n position: relative;\n min-width: 100%;\n z-index: 2;\n }\n :host .canvases {\n position: relative;\n height: ${this.options.height}px;\n }\n :host canvas {\n display: block;\n position: absolute;\n top: 0;\n height: ${this.options.height}px;\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: ${this.options.height}px;\n overflow: hidden;\n box-sizing: border-box;\n border-right-style: solid;\n border-right-width: ${this.options.cursorWidth}px;\n border-right-color: ${this.options.cursorColor||this.options.progressColor};\n }\n </style>\n\n <div class="scroll">\n <div class="wrapper">\n <div class="canvases"></div>\n <div class="progress"></div>\n </div>\n </div>\n `,this.container=i,this.scrollContainer=s.querySelector(".scroll"),this.wrapper=s.querySelector(".wrapper"),this.canvasWrapper=s.querySelector(".canvases"),this.progressWrapper=s.querySelector(".progress"),e.appendChild(i),this.wrapper.addEventListener("click",(t=>{const e=this.wrapper.getBoundingClientRect(),i=(t.clientX-e.left)/e.width;this.emit("click",{relativeX:i})}))}getContainer(){return this.scrollContainer}getWrapper(){return this.wrapper}destroy(){this.container.remove()}delay(t,e=10){return this.timeout&&clearTimeout(this.timeout),new Promise((i=>{this.timeout=setTimeout((()=>{i(t())}),e)}))}async renderPeaks(t,e,i,s){const r=null!=this.options.barWidth?this.options.barWidth*s:1,n=null!=this.options.barGap?this.options.barGap*s:this.options.barWidth?r/2:0,o=this.options.barRadius??0,a=t[0],h=a.length,l=Math.floor(e/(r+n))/h,d=i/2,p=1===t.length,c=p?a:t[1],u=p&&c.some((t=>t<0)),m=(t,i)=>{let p=0,m=0,y=0;const g=document.createElement("canvas");g.width=Math.round(e*(i-t)/h),g.height=this.options.height,g.style.width=`${Math.floor(g.width/s)}px`,g.style.left=`${Math.floor(t*e/s/h)}px`,this.canvasWrapper.appendChild(g);const v=g.getContext("2d",{desynchronized:!0});v.beginPath(),v.fillStyle=this.options.waveColor,v.roundRect||(v.roundRect=v.fillRect);for(let e=t;e<i;e++){const i=Math.round((e-t)*l);if(i>p){const t=Math.round(m*d),e=Math.round(y*d);v.roundRect(p*(r+n),d-t,r,t+e||1,o),p=i,m=0,y=0}const s=u?a[e]:Math.abs(a[e]),h=u?c[e]:Math.abs(c[e]);s>m&&(m=s),(u?h<-y:h>y)&&(y=h<0?-h:h)}v.fill(),v.closePath();const f=g.cloneNode();this.progressWrapper.appendChild(f);const b=f.getContext("2d",{desynchronized:!0});b.drawImage(g,0,0),b.globalCompositeOperation="source-in",b.fillStyle=this.options.progressColor,b.fillRect(0,0,g.width,g.height)};this.canvasWrapper.innerHTML="",this.progressWrapper.innerHTML="";const{scrollLeft:y,scrollWidth:g,clientWidth:v}=this.scrollContainer,f=h/g,b=Math.floor(y*f),w=Math.ceil(Math.min(g,y+v)*f);m(b,w);const C=w-b;for(let t=w;t<h;t+=C)await this.delay((()=>{m(t,Math.min(h,t+C))}));for(let t=b-1;t>=0;t-=C)await this.delay((()=>{m(Math.max(0,t-C),t)}))}render(t){const e=window.devicePixelRatio||1,i=this.options.fillParent?this.scrollContainer.clientWidth*e:0,s=t.duration*this.options.minPxPerSec,r=s>i,n=Math.max(1,r?s:i),{height:o}=this.options,a=this.progressWrapper.clientWidth;this.scrollContainer.style.overflowX=r?"auto":"hidden",this.wrapper.style.width=`${Math.floor(n/e)}px`;const h=this.progressWrapper.clientWidth;this.scrollContainer.scrollLeft+=h-a;const l=[t.getChannelData(0)];t.numberOfChannels>1&&l.push(t.getChannelData(1)),this.renderPeaks(l,n,o,e)}zoom(t,e){this.options.minPxPerSec=e,this.render(t)}renderProgress(t,e=!1){this.progressWrapper.style.width=100*t+"%";const i=this.scrollContainer.clientWidth,s=i/2,r=this.progressWrapper.clientWidth,n=e?s:i;r>this.scrollContainer.scrollLeft+n&&(this.scrollContainer.scrollLeft=r-s)}},n=class extends i{unsubscribe=()=>{};start(){this.unsubscribe=this.on("tick",(()=>{requestAnimationFrame((()=>{this.emit("tick")}))})),this.emit("tick")}stop(){this.unsubscribe()}destroy(){this.unsubscribe()}},o={height:128,waveColor:"#999",progressColor:"#555",cursorWidth:1,minPxPerSec:0,fillParent:!0,interactive:!0};class a extends i{options;fetcher;decoder;renderer;player;timer;plugins=[];subscriptions=[];decodedData=null;static create(t){return new a(t)}constructor(t){super(),this.options=Object.assign({},o,t),this.fetcher=new class{async load(t){return fetch(t).then((t=>t.arrayBuffer()))}},this.decoder=new class{audioCtx=null;initAudioContext(t){this.audioCtx=new AudioContext({latencyHint:"playback",sampleRate:t})}constructor(){try{this.initAudioContext(3e3)}catch(t){this.initAudioContext(8e3)}}async decode(t){if(!this.audioCtx)throw new Error("AudioContext is not initialized");return this.audioCtx.decodeAudioData(t)}destroy(){this.audioCtx?.close(),this.audioCtx=null}},this.timer=new n,this.player=new class{media;isExternalMedia=!1;hasPlayedOnce=!1;subscriptions=[];constructor({media:t,autoplay:e}){t?(this.media=t,this.isExternalMedia=!0):this.media=document.createElement("audio"),this.subscriptions.push(this.on("play",(()=>{this.hasPlayedOnce=!0}),{once:!0})),e&&(this.media.autoplay=!0)}on(t,e,i){return this.media.addEventListener(t,e,i),()=>this.media.removeEventListener(t,e)}destroy(){this.subscriptions.forEach((t=>{t()})),this.media.pause(),this.isExternalMedia||this.media.remove()}loadUrl(t){this.media.src=t}getCurrentTime(){return this.media.currentTime}play(){this.media.play()}pause(){this.media.pause()}isPlaying(){return this.media.currentTime>0&&!this.media.paused&&!this.media.ended}seekTo(t){!this.hasPlayedOnce&&navigator.userAgent.match(/(iPad|iPhone|iPod)/g)&&this.media.play()?.then?.((()=>{setTimeout((()=>this.media.pause()),10)})),this.media.currentTime=t}getDuration(){return this.media.duration}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}}({media:this.options.media,autoplay:this.options.autoplay}),this.renderer=new r({container:this.options.container,height:this.options.height,waveColor:this.options.waveColor,progressColor:this.options.progressColor,cursorColor:this.options.cursorColor,cursorWidth:this.options.cursorWidth,minPxPerSec:this.options.minPxPerSec,fillParent:this.options.fillParent,barWidth:this.options.barWidth,barGap:this.options.barGap,barRadius:this.options.barRadius,noScrollbar:this.options.noScrollbar}),this.initPlayerEvents(),this.initRendererEvents(),this.initTimerEvents(),this.initReadyEvent();const e=this.options.url||this.options.media?.src;e&&this.load(e,this.options.peaks,this.options.duration)}initPlayerEvents(){this.subscriptions.push(this.player.on("timeupdate",(()=>{const t=this.getCurrentTime();this.renderer.renderProgress(t/this.getDuration(),this.isPlaying()),this.emit("timeupdate",{currentTime:t})})),this.player.on("play",(()=>{this.emit("play"),this.timer.start()})),this.player.on("pause",(()=>{this.emit("pause"),this.timer.stop()})),this.player.on("canplay",(()=>{this.emit("canplay",{duration:this.getDuration()})})),this.player.on("seeking",(()=>{this.emit("seeking",{currentTime:this.getCurrentTime()})})))}initRendererEvents(){this.subscriptions.push(this.renderer.on("click",(({relativeX:t})=>{if(this.options.interactive){const e=this.getDuration()*t;this.seekTo(e),this.emit("seekClick",{currentTime:this.getCurrentTime()})}})))}initTimerEvents(){this.subscriptions.push(this.timer.on("tick",(()=>{const t=this.getCurrentTime();this.renderer.renderProgress(t/this.getDuration(),!0),this.emit("timeupdate",{currentTime:t})})))}initReadyEvent(){let t=!1,e=!1;const i=()=>{t&&e&&this.emit("ready",{duration:this.getDuration()})};this.subscriptions.push(this.on("decode",(()=>{t=!0,i()})),this.on("canplay",(()=>{e=!0,i()})),this.player.on("waiting",(()=>{e=!1,t=!1})))}async load(t,e,i){if(this.player.loadUrl(t),null==e){const e=await this.fetcher.load(t),i=await this.decoder.decode(e);this.decodedData=i}else i||(i=await new Promise((t=>{this.player.on("canplay",(()=>t(this.getDuration())),{once:!0})}))||0),this.decodedData={duration:i,numberOfChannels:e.length,sampleRate:e[0].length/i,getChannelData:t=>e[t]};this.renderer.render(this.decodedData),this.emit("decode",{duration:this.decodedData.duration})}zoom(t){if(!this.decodedData)throw new Error("No audio loaded");this.renderer.zoom(this.decodedData,t)}play(){this.player.play()}pause(){this.player.pause()}seekTo(t){this.player.seekTo(t)}isPlaying(){return this.player.isPlaying()}getDuration(){return this.player.getDuration()||this.decodedData?.duration||0}getCurrentTime(){return this.player.getCurrentTime()}getVolume(){return this.player.getVolume()}setVolume(t){this.player.setVolume(t)}getMuted(){return this.player.getMuted()}setMuted(t){this.player.setMuted(t)}getPlaybackRate(){return this.player.getPlaybackRate()}setPlaybackRate(t,e){this.player.setPlaybackRate(t,e)}registerPlugin(t,e){const i=new t({wavesurfer:this,container:this.renderer.getContainer(),wrapper:this.renderer.getWrapper()},e);return this.plugins.push(i),i}getDecodedData(){return this.decodedData}getMediaElement(){return this.player.getMediaElement()}destroy(){this.emit("destroy"),this.subscriptions.forEach((t=>t())),this.plugins.forEach((t=>t.destroy())),this.timer.destroy(),this.player.destroy(),this.decoder.destroy(),this.renderer.destroy()}}const h=a,l={height:50,overlayColor:"rgba(100, 100, 100, 0.1)"},d=class extends s{options;minimapWrapper;miniWavesurfer=null;overlay;constructor(t,e){super(t,e),this.options=Object.assign({},l,e),this.minimapWrapper=this.initMinimapWrapper(),this.overlay=this.initOverlay(),this.subscriptions.push(this.wavesurfer.on("decode",(()=>{this.initMinimap()})))}initMinimapWrapper(){const t=document.createElement("div");return t.style.position="relative",this.container.insertAdjacentElement("afterend",t),t}initOverlay(){const t=document.createElement("div");return t.setAttribute("style","position: absolute; z-index: 2; left: 0; top: 0; bottom: 0;"),t.style.backgroundColor=this.options.overlayColor,this.minimapWrapper.appendChild(t),t}initMinimap(){const t=this.wavesurfer.getDecodedData(),e=this.wavesurfer.getMediaElement();if(!t||!e)return;this.miniWavesurfer=h.create({...this.options,container:this.minimapWrapper,minPxPerSec:1,fillParent:!0,media:e,url:e.src,peaks:[t.getChannelData(0)],duration:t.duration});const i=Math.round(this.minimapWrapper.clientWidth/this.wrapper.clientWidth*100);this.overlay.style.width=`${i}%`,this.wavesurfer.on("timeupdate",(({currentTime:t})=>{const e=Math.max(0,Math.min(t/this.wavesurfer.getDuration()*100-i/2,100-i)).toFixed(2);this.overlay.style.left=`${e}%`}))}destroy(){this.miniWavesurfer?.destroy(),this.minimapWrapper.remove(),super.destroy()}};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.Minimap=e():t.Minimap=e()}(WaveSurfer,(()=>(()=>{"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=class{eventTarget;constructor(){this.eventTarget=new EventTarget}emit(t,e){const i=new CustomEvent(String(t),{detail:e});this.eventTarget.dispatchEvent(i)}on(t,e,i){const s=t=>{t instanceof CustomEvent&&e(t.detail)},r=String(t);return this.eventTarget.addEventListener(r,s,{once:i}),()=>this.eventTarget.removeEventListener(r,s)}once(t,e){return this.on(t,e,!0)}},s=class extends i{wavesurfer;container;wrapper;subscriptions=[];options;constructor(t,e){super(),this.wavesurfer=t.wavesurfer,this.container=t.container,this.wrapper=t.wrapper,this.options=e}destroy(){this.subscriptions.forEach((t=>t()))}},r=class extends i{options;container;scrollContainer;wrapper;canvasWrapper;progressWrapper;timeout=null;isScrolling=!1;constructor(t){super(),this.options=t;let e=null;if("string"==typeof this.options.container?e=document.querySelector(this.options.container):this.options.container instanceof HTMLElement&&(e=this.options.container),!e)throw new Error("Container not found");const i=document.createElement("div"),s=i.attachShadow({mode:"open"});s.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 ${this.options.noScrollbar?"scrollbar-color: transparent;":""}\n }\n :host ::-webkit-scrollbar {\n display: ${this.options.noScrollbar?"none":"auto"};\n }\n :host .wrapper {\n position: relative;\n min-width: 100%;\n z-index: 2;\n }\n :host .canvases {\n position: relative;\n height: ${this.options.height}px;\n }\n :host canvas {\n display: block;\n position: absolute;\n top: 0;\n height: ${this.options.height}px;\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: ${this.options.height}px;\n overflow: hidden;\n box-sizing: border-box;\n border-right-style: solid;\n border-right-width: ${this.options.cursorWidth}px;\n border-right-color: ${this.options.cursorColor||this.options.progressColor};\n }\n </style>\n\n <div class="scroll">\n <div class="wrapper">\n <div class="canvases"></div>\n <div class="progress"></div>\n </div>\n </div>\n `,this.container=i,this.scrollContainer=s.querySelector(".scroll"),this.wrapper=s.querySelector(".wrapper"),this.canvasWrapper=s.querySelector(".canvases"),this.progressWrapper=s.querySelector(".progress"),e.appendChild(i),this.wrapper.addEventListener("click",(t=>{const e=this.wrapper.getBoundingClientRect(),i=(t.clientX-e.left)/e.width;this.emit("click",{relativeX:i})}))}getContainer(){return this.scrollContainer}getWrapper(){return this.wrapper}destroy(){this.container.remove()}delay(t,e=10){return this.timeout&&clearTimeout(this.timeout),new Promise((i=>{this.timeout=setTimeout((()=>{i(t())}),e)}))}async renderPeaks(t,e,i,s){const r=null!=this.options.barWidth?this.options.barWidth*s:1,n=null!=this.options.barGap?this.options.barGap*s:this.options.barWidth?r/2:0,o=this.options.barRadius??0,a=t[0],h=a.length,l=Math.floor(e/(r+n))/h,d=i/2,p=1===t.length,c=p?a:t[1],u=p&&c.some((t=>t<0)),m=(t,i)=>{let p=0,m=0,g=0;const y=document.createElement("canvas");y.width=Math.round(e*(i-t)/h),y.height=this.options.height,y.style.width=`${Math.floor(y.width/s)}px`,y.style.left=`${Math.floor(t*e/s/h)}px`,this.canvasWrapper.appendChild(y);const v=y.getContext("2d",{desynchronized:!0});v.beginPath(),v.fillStyle=this.options.waveColor,v.roundRect||(v.roundRect=v.fillRect);for(let e=t;e<i;e++){const i=Math.round((e-t)*l);if(i>p){const t=Math.round(m*d),e=Math.round(g*d);v.roundRect(p*(r+n),d-t,r,t+e||1,o),p=i,m=0,g=0}const s=u?a[e]:Math.abs(a[e]),h=u?c[e]:Math.abs(c[e]);s>m&&(m=s),(u?h<-g:h>g)&&(g=h<0?-h:h)}v.fill(),v.closePath();const f=y.cloneNode();this.progressWrapper.appendChild(f);const b=f.getContext("2d",{desynchronized:!0});b.drawImage(y,0,0),b.globalCompositeOperation="source-in",b.fillStyle=this.options.progressColor,b.fillRect(0,0,y.width,y.height)};this.canvasWrapper.innerHTML="",this.progressWrapper.innerHTML="";const{scrollLeft:g,scrollWidth:y,clientWidth:v}=this.scrollContainer,f=h/y,b=Math.floor(g*f),w=Math.ceil(Math.min(y,g+v)*f);m(b,w);const C=w-b;for(let t=w;t<h;t+=C)await this.delay((()=>{m(t,Math.min(h,t+C))}));for(let t=b-1;t>=0;t-=C)await this.delay((()=>{m(Math.max(0,t-C),t)}))}render(t){const e=window.devicePixelRatio||1,i=this.options.fillParent?this.scrollContainer.clientWidth*e:0,s=t.duration*this.options.minPxPerSec;this.isScrolling=s>i;const r=Math.max(1,this.isScrolling?s:i),{height:n}=this.options,o=this.progressWrapper.clientWidth;this.scrollContainer.style.overflowX=this.isScrolling?"auto":"hidden",this.wrapper.style.width=`${Math.floor(r/e)}px`;const a=this.progressWrapper.clientWidth;this.scrollContainer.scrollLeft+=a-o;const h=[t.getChannelData(0)];t.numberOfChannels>1&&h.push(t.getChannelData(1)),this.renderPeaks(h,r,n,e)}zoom(t,e){this.options.minPxPerSec=e,this.render(t)}renderProgress(t,e=!1){if(this.progressWrapper.style.width=100*t+"%",this.isScrolling){const t=this.scrollContainer.clientWidth,i=t/2,s=this.progressWrapper.clientWidth,r=e?i:t;s>this.scrollContainer.scrollLeft+r&&(this.scrollContainer.scrollLeft=s-i)}}},n=class extends i{unsubscribe=()=>{};start(){this.unsubscribe=this.on("tick",(()=>{requestAnimationFrame((()=>{this.emit("tick")}))})),this.emit("tick")}stop(){this.unsubscribe()}destroy(){this.unsubscribe()}},o={height:128,waveColor:"#999",progressColor:"#555",cursorWidth:1,minPxPerSec:0,fillParent:!0,interactive:!0};class a extends i{options;fetcher;decoder;renderer;player;timer;plugins=[];subscriptions=[];decodedData=null;static create(t){return new a(t)}constructor(t){super(),this.options=Object.assign({},o,t),this.fetcher=new class{async load(t){return fetch(t).then((t=>t.arrayBuffer()))}},this.decoder=new class{audioCtx=null;initAudioContext(t){this.audioCtx=new AudioContext({latencyHint:"playback",sampleRate:t})}constructor(){try{this.initAudioContext(3e3)}catch(t){this.initAudioContext(8e3)}}async decode(t){if(!this.audioCtx)throw new Error("AudioContext is not initialized");return this.audioCtx.decodeAudioData(t)}destroy(){this.audioCtx?.close(),this.audioCtx=null}},this.timer=new n,this.player=new class{media;isExternalMedia=!1;hasPlayedOnce=!1;subscriptions=[];constructor({media:t,autoplay:e}){t?(this.media=t,this.isExternalMedia=!0):this.media=document.createElement("audio"),this.subscriptions.push(this.on("play",(()=>{this.hasPlayedOnce=!0}),{once:!0})),e&&(this.media.autoplay=!0)}on(t,e,i){return this.media.addEventListener(t,e,i),()=>this.media.removeEventListener(t,e)}destroy(){this.subscriptions.forEach((t=>{t()})),this.media.pause(),this.isExternalMedia||this.media.remove()}loadUrl(t){this.media.src=t}getCurrentTime(){return this.media.currentTime}play(){this.media.play()}pause(){this.media.pause()}isPlaying(){return this.media.currentTime>0&&!this.media.paused&&!this.media.ended}seekTo(t){!this.hasPlayedOnce&&navigator.userAgent.match(/(iPad|iPhone|iPod)/g)&&this.media.play()?.then?.((()=>{setTimeout((()=>this.media.pause()),10)})),this.media.currentTime=t}getDuration(){return this.media.duration}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}}({media:this.options.media,autoplay:this.options.autoplay}),this.renderer=new r({container:this.options.container,height:this.options.height,waveColor:this.options.waveColor,progressColor:this.options.progressColor,cursorColor:this.options.cursorColor,cursorWidth:this.options.cursorWidth,minPxPerSec:this.options.minPxPerSec,fillParent:this.options.fillParent,barWidth:this.options.barWidth,barGap:this.options.barGap,barRadius:this.options.barRadius,noScrollbar:this.options.noScrollbar}),this.initPlayerEvents(),this.initRendererEvents(),this.initTimerEvents(),this.initReadyEvent();const e=this.options.url||this.options.media?.src;e&&this.load(e,this.options.peaks,this.options.duration)}initPlayerEvents(){this.subscriptions.push(this.player.on("timeupdate",(()=>{const t=this.getCurrentTime();this.renderer.renderProgress(t/this.getDuration(),this.isPlaying()),this.emit("timeupdate",{currentTime:t})})),this.player.on("play",(()=>{this.emit("play"),this.timer.start()})),this.player.on("pause",(()=>{this.emit("pause"),this.timer.stop()})),this.player.on("canplay",(()=>{this.emit("canplay",{duration:this.getDuration()})})),this.player.on("seeking",(()=>{this.emit("seeking",{currentTime:this.getCurrentTime()})})))}initRendererEvents(){this.subscriptions.push(this.renderer.on("click",(({relativeX:t})=>{if(this.options.interactive){const e=this.getDuration()*t;this.seekTo(e),this.emit("seekClick",{currentTime:this.getCurrentTime()})}})))}initTimerEvents(){this.subscriptions.push(this.timer.on("tick",(()=>{const t=this.getCurrentTime();this.renderer.renderProgress(t/this.getDuration(),!0),this.emit("timeupdate",{currentTime:t})})))}initReadyEvent(){let t=!1,e=!1;const i=()=>{t&&e&&this.emit("ready",{duration:this.getDuration()})};this.subscriptions.push(this.on("decode",(()=>{t=!0,i()})),this.on("canplay",(()=>{e=!0,i()})),this.player.on("waiting",(()=>{e=!1,t=!1})))}async load(t,e,i){if(this.player.loadUrl(t),null==e){const e=await this.fetcher.load(t),i=await this.decoder.decode(e);this.decodedData=i}else i||(i=await new Promise((t=>{this.player.on("canplay",(()=>t(this.getDuration())),{once:!0})}))||0),this.decodedData={duration:i,numberOfChannels:e.length,sampleRate:e[0].length/i,getChannelData:t=>e[t]};this.renderer.render(this.decodedData),this.emit("decode",{duration:this.decodedData.duration})}zoom(t){if(!this.decodedData)throw new Error("No audio loaded");this.renderer.zoom(this.decodedData,t),this.emit("zoom",{minPxPerSec:t})}play(){this.player.play()}pause(){this.player.pause()}seekTo(t){this.player.seekTo(t)}isPlaying(){return this.player.isPlaying()}getDuration(){return this.player.getDuration()||this.decodedData?.duration||0}getCurrentTime(){return this.player.getCurrentTime()}getVolume(){return this.player.getVolume()}setVolume(t){this.player.setVolume(t)}getMuted(){return this.player.getMuted()}setMuted(t){this.player.setMuted(t)}getPlaybackRate(){return this.player.getPlaybackRate()}setPlaybackRate(t,e){this.player.setPlaybackRate(t,e)}registerPlugin(t,e){const i=new t({wavesurfer:this,container:this.renderer.getContainer(),wrapper:this.renderer.getWrapper()},e);return this.plugins.push(i),i.once("destroy",(()=>{this.plugins=this.plugins.filter((t=>t!==i))})),i}getDecodedData(){return this.decodedData}getMediaElement(){return this.player.getMediaElement()}toggleInteractive(t){this.options.interactive=t}destroy(){this.emit("destroy"),this.subscriptions.forEach((t=>t())),this.plugins.forEach((t=>t.destroy())),this.timer.destroy(),this.player.destroy(),this.decoder.destroy(),this.renderer.destroy()}}const h=a,l={height:50,overlayColor:"rgba(100, 100, 100, 0.1)"},d=class extends s{options;minimapWrapper;miniWavesurfer=null;overlay;constructor(t,e){super(t,e),this.options=Object.assign({},l,e),this.minimapWrapper=this.initMinimapWrapper(),this.overlay=this.initOverlay(),this.subscriptions.push(this.wavesurfer.on("decode",(()=>{this.initMinimap()})))}initMinimapWrapper(){const t=document.createElement("div");return t.style.position="relative",this.container.insertAdjacentElement("afterend",t),t}initOverlay(){const t=document.createElement("div");return t.setAttribute("style","position: absolute; z-index: 2; left: 0; top: 0; bottom: 0;"),t.style.backgroundColor=this.options.overlayColor,this.minimapWrapper.appendChild(t),t}initMinimap(){const t=this.wavesurfer.getDecodedData(),e=this.wavesurfer.getMediaElement();if(!t||!e)return;this.miniWavesurfer=h.create({...this.options,container:this.minimapWrapper,minPxPerSec:1,fillParent:!0,media:e,url:e.src,peaks:[t.getChannelData(0)],duration:t.duration});const i=Math.round(this.minimapWrapper.clientWidth/this.wrapper.clientWidth*100);this.overlay.style.width=`${i}%`,this.wavesurfer.on("timeupdate",(({currentTime:t})=>{const e=Math.max(0,Math.min(t/this.wavesurfer.getDuration()*100-i/2,100-i)).toFixed(2);this.overlay.style.left=`${e}%`}))}destroy(){this.miniWavesurfer?.destroy(),this.minimapWrapper.remove(),super.destroy()}};return e.default})()));