wavesurfer.js 7.0.0-beta.9 → 7.0.0

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.
Files changed (76) hide show
  1. package/README.md +56 -24
  2. package/dist/base-plugin.d.ts +5 -2
  3. package/dist/base-plugin.js +1 -0
  4. package/dist/decoder.js +17 -6
  5. package/dist/draggable.js +10 -7
  6. package/dist/fetcher.d.ts +1 -3
  7. package/dist/fetcher.js +13 -6
  8. package/dist/player.d.ts +2 -2
  9. package/dist/player.js +10 -8
  10. package/dist/plugins/base-plugin.d.ts +16 -0
  11. package/dist/plugins/decoder.d.ts +9 -0
  12. package/dist/plugins/draggable.d.ts +1 -0
  13. package/dist/plugins/envelope.cjs +1 -0
  14. package/dist/plugins/envelope.d.ts +12 -4
  15. package/dist/plugins/envelope.esm.js +1 -0
  16. package/dist/plugins/envelope.js +29 -9
  17. package/dist/plugins/envelope.min.js +1 -0
  18. package/dist/plugins/event-emitter.d.ts +19 -0
  19. package/dist/plugins/fetcher.d.ts +5 -0
  20. package/dist/plugins/hover.cjs +1 -0
  21. package/dist/plugins/hover.d.ts +35 -0
  22. package/dist/plugins/hover.esm.js +1 -0
  23. package/dist/plugins/hover.js +101 -0
  24. package/dist/plugins/hover.min.js +1 -0
  25. package/dist/plugins/minimap.cjs +1 -0
  26. package/dist/plugins/minimap.d.ts +2 -2
  27. package/dist/plugins/minimap.esm.js +1 -0
  28. package/dist/plugins/minimap.js +8 -13
  29. package/dist/plugins/minimap.min.js +1 -0
  30. package/dist/plugins/player.d.ts +45 -0
  31. package/dist/plugins/plugins/envelope.d.ts +79 -0
  32. package/dist/plugins/plugins/hover.d.ts +35 -0
  33. package/dist/plugins/plugins/minimap.d.ts +39 -0
  34. package/dist/plugins/plugins/record.d.ts +31 -0
  35. package/dist/plugins/plugins/regions.d.ts +115 -0
  36. package/dist/plugins/plugins/spectrogram.d.ts +76 -0
  37. package/dist/plugins/plugins/timeline.d.ts +47 -0
  38. package/dist/plugins/record.cjs +1 -0
  39. package/dist/plugins/record.d.ts +7 -4
  40. package/dist/plugins/record.esm.js +1 -0
  41. package/dist/plugins/record.js +73 -66
  42. package/dist/plugins/record.min.js +1 -0
  43. package/dist/plugins/regions.cjs +1 -0
  44. package/dist/plugins/regions.d.ts +25 -4
  45. package/dist/plugins/regions.esm.js +1 -0
  46. package/dist/plugins/regions.js +60 -60
  47. package/dist/plugins/regions.min.js +1 -0
  48. package/dist/plugins/renderer.d.ts +44 -0
  49. package/dist/plugins/spectrogram.cjs +1 -0
  50. package/dist/plugins/spectrogram.d.ts +10 -3
  51. package/dist/plugins/spectrogram.esm.js +1 -0
  52. package/dist/plugins/spectrogram.js +166 -20
  53. package/dist/plugins/spectrogram.min.js +1 -0
  54. package/dist/plugins/timeline.cjs +1 -0
  55. package/dist/plugins/timeline.d.ts +5 -3
  56. package/dist/plugins/timeline.esm.js +1 -0
  57. package/dist/plugins/timeline.js +27 -21
  58. package/dist/plugins/timeline.min.js +1 -0
  59. package/dist/plugins/timer.d.ts +11 -0
  60. package/dist/plugins/wavesurfer.d.ts +156 -0
  61. package/dist/renderer.js +11 -7
  62. package/dist/wavesurfer.cjs +1 -0
  63. package/dist/wavesurfer.d.ts +5 -3
  64. package/dist/wavesurfer.esm.js +1 -0
  65. package/dist/wavesurfer.js +62 -41
  66. package/dist/wavesurfer.min.js +1 -0
  67. package/package.json +21 -22
  68. package/dist/plugins/envelope.min.cjs +0 -1
  69. package/dist/plugins/minimap.min.cjs +0 -1
  70. package/dist/plugins/record.min.cjs +0 -1
  71. package/dist/plugins/regions.min.cjs +0 -1
  72. package/dist/plugins/spectrogram-fft.d.ts +0 -9
  73. package/dist/plugins/spectrogram-fft.js +0 -150
  74. package/dist/plugins/spectrogram.min.cjs +0 -1
  75. package/dist/plugins/timeline.min.cjs +0 -1
  76. package/dist/wavesurfer.min.cjs +0 -1
@@ -6,16 +6,21 @@
6
6
  import BasePlugin from '../base-plugin.js';
7
7
  import { makeDraggable } from '../draggable.js';
8
8
  import EventEmitter from '../event-emitter.js';
9
- export class Region extends EventEmitter {
9
+ class Region extends EventEmitter {
10
10
  constructor(params, totalDuration) {
11
+ var _a, _b, _c, _d, _e, _f;
11
12
  super();
12
13
  this.totalDuration = totalDuration;
14
+ this.minLength = 0;
15
+ this.maxLength = Infinity;
13
16
  this.id = params.id || `region-${Math.random().toString(32).slice(2)}`;
14
17
  this.start = params.start;
15
- this.end = params.end ?? params.start;
16
- this.drag = params.drag ?? true;
17
- this.resize = params.resize ?? true;
18
- this.color = params.color ?? 'rgba(0, 0, 0, 0.1)';
18
+ this.end = (_a = params.end) !== null && _a !== void 0 ? _a : params.start;
19
+ this.drag = (_b = params.drag) !== null && _b !== void 0 ? _b : true;
20
+ this.resize = (_c = params.resize) !== null && _c !== void 0 ? _c : true;
21
+ this.color = (_d = params.color) !== null && _d !== void 0 ? _d : 'rgba(0, 0, 0, 0.1)';
22
+ this.minLength = (_e = params.minLength) !== null && _e !== void 0 ? _e : this.minLength;
23
+ this.maxLength = (_f = params.maxLength) !== null && _f !== void 0 ? _f : this.maxLength;
19
24
  this.element = this.initElement(params.content);
20
25
  this.renderPosition();
21
26
  this.initMouseEvents();
@@ -34,13 +39,12 @@ export class Region extends EventEmitter {
34
39
  transition: background-color 0.2s ease;
35
40
  cursor: ${this.drag ? 'grab' : 'default'};
36
41
  pointer-events: all;
37
- padding: 0.2em ${isMarker ? 0.2 : 0.4}em;
38
- pointer-events: all;
39
42
  `);
40
43
  // Init content
41
44
  if (content) {
42
45
  if (typeof content === 'string') {
43
46
  this.content = document.createElement('div');
47
+ this.content.style.padding = `0.2em ${isMarker ? 0.2 : 0.4}em`;
44
48
  this.content.textContent = content;
45
49
  }
46
50
  else {
@@ -81,9 +85,9 @@ export class Region extends EventEmitter {
81
85
  }
82
86
  renderPosition() {
83
87
  const start = this.start / this.totalDuration;
84
- const end = this.end / this.totalDuration;
88
+ const end = (this.totalDuration - this.end) / this.totalDuration;
85
89
  this.element.style.left = `${start * 100}%`;
86
- this.element.style.width = `${(end - start) * 100}%`;
90
+ this.element.style.right = `${end * 100}%`;
87
91
  }
88
92
  initMouseEvents() {
89
93
  const { element } = this;
@@ -111,31 +115,33 @@ export class Region extends EventEmitter {
111
115
  this.element.style.cursor = 'grab';
112
116
  this.emit('update-end');
113
117
  }
114
- onUpdate(dx, sides) {
118
+ _onUpdate(dx, side) {
115
119
  if (!this.element.parentElement)
116
120
  return;
117
121
  const deltaSeconds = (dx / this.element.parentElement.clientWidth) * this.totalDuration;
118
- sides.forEach((side) => {
119
- this[side] += deltaSeconds;
120
- if (side === 'start') {
121
- this.start = Math.max(0, Math.min(this.start, this.end));
122
- }
123
- else {
124
- this.end = Math.max(this.start, Math.min(this.end, this.totalDuration));
125
- }
126
- });
127
- this.renderPosition();
128
- this.emit('update');
122
+ const newStart = !side || side === 'start' ? this.start + deltaSeconds : this.start;
123
+ const newEnd = !side || side === 'end' ? this.end + deltaSeconds : this.end;
124
+ const length = newEnd - newStart;
125
+ if (newStart > 0 &&
126
+ newEnd < this.totalDuration &&
127
+ newStart <= newEnd &&
128
+ length >= this.minLength &&
129
+ length <= this.maxLength) {
130
+ this.start = newStart;
131
+ this.end = newEnd;
132
+ this.renderPosition();
133
+ this.emit('update');
134
+ }
129
135
  }
130
136
  onMove(dx) {
131
137
  if (!this.drag)
132
138
  return;
133
- this.onUpdate(dx, ['start', 'end']);
139
+ this._onUpdate(dx);
134
140
  }
135
141
  onResize(dx, side) {
136
142
  if (!this.resize)
137
143
  return;
138
- this.onUpdate(dx, [side]);
144
+ this._onUpdate(dx, side);
139
145
  }
140
146
  onEndResizing() {
141
147
  if (!this.resize)
@@ -152,6 +158,7 @@ export class Region extends EventEmitter {
152
158
  }
153
159
  /** Update the region's options */
154
160
  setOptions(options) {
161
+ var _a, _b;
155
162
  if (options.color) {
156
163
  this.color = options.color;
157
164
  this.element.style.backgroundColor = this.color;
@@ -168,8 +175,8 @@ export class Region extends EventEmitter {
168
175
  });
169
176
  }
170
177
  if (options.start !== undefined || options.end !== undefined) {
171
- this.start = options.start ?? this.start;
172
- this.end = options.end ?? this.end;
178
+ this.start = (_a = options.start) !== null && _a !== void 0 ? _a : this.start;
179
+ this.end = (_b = options.end) !== null && _b !== void 0 ? _b : this.end;
173
180
  this.renderPosition();
174
181
  }
175
182
  }
@@ -233,7 +240,7 @@ class RegionsPlugin extends BasePlugin {
233
240
  const width = reg.element.scrollWidth;
234
241
  return labelLeft < left + width && left < labelLeft + labelWidth;
235
242
  })
236
- .map((reg) => reg.content?.getBoundingClientRect().height || 0)
243
+ .map((reg) => { var _a; return ((_a = reg.content) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect().height) || 0; })
237
244
  .reduce((sum, val) => sum + val, 0);
238
245
  div.style.marginTop = `${overlap}px`;
239
246
  }
@@ -248,8 +255,9 @@ class RegionsPlugin extends BasePlugin {
248
255
  this.emit('region-updated', region);
249
256
  }),
250
257
  region.on('play', () => {
251
- this.wavesurfer?.play();
252
- this.wavesurfer?.setTime(region.start);
258
+ var _a, _b;
259
+ (_a = this.wavesurfer) === null || _a === void 0 ? void 0 : _a.play();
260
+ (_b = this.wavesurfer) === null || _b === void 0 ? void 0 : _b.setTime(region.start);
253
261
  }),
254
262
  region.on('click', (e) => {
255
263
  this.emit('region-clicked', region, e);
@@ -288,52 +296,44 @@ class RegionsPlugin extends BasePlugin {
288
296
  * Returns a function to disable the drag selection.
289
297
  */
290
298
  enableDragSelection(options) {
291
- const wrapper = this.wavesurfer?.getWrapper()?.querySelector('div');
299
+ var _a, _b;
300
+ const wrapper = (_b = (_a = this.wavesurfer) === null || _a === void 0 ? void 0 : _a.getWrapper()) === null || _b === void 0 ? void 0 : _b.querySelector('div');
292
301
  if (!wrapper)
293
302
  return () => undefined;
303
+ const initialSize = 5;
294
304
  let region = null;
295
- let sumDx = 0;
305
+ let startX = 0;
296
306
  return makeDraggable(wrapper,
297
307
  // On drag move
298
- (dx, _, x) => {
299
- if (!this.wavesurfer)
300
- return;
301
- if (!region) {
302
- const duration = this.wavesurfer.getDuration();
303
- const box = wrapper.getBoundingClientRect();
304
- let start = (x / box.width) * duration;
305
- let end = ((x - box.left) / box.width) * duration;
306
- if (start > end)
307
- [start, end] = [end, start];
308
- region = new Region({
309
- ...options,
310
- start,
311
- end,
312
- }, duration);
313
- this.regionsContainer.appendChild(region.element);
314
- }
315
- sumDx += dx;
308
+ (dx, _dy, x) => {
316
309
  if (region) {
317
- const privateRegion = region;
318
- privateRegion.onUpdate(dx, [sumDx > 0 ? 'end' : 'start']);
310
+ // Update the end position of the region
311
+ // If we're dragging to the left, we need to update the start instead
312
+ region._onUpdate(dx, x > startX ? 'end' : 'start');
319
313
  }
320
314
  },
321
315
  // On drag start
322
- () => null,
316
+ (x) => {
317
+ startX = x;
318
+ if (!this.wavesurfer)
319
+ return;
320
+ const duration = this.wavesurfer.getDuration();
321
+ const width = this.wavesurfer.getWrapper().clientWidth;
322
+ // Calculate the start time of the region
323
+ const start = (x / width) * duration;
324
+ // Give the region a small initial size
325
+ const end = ((x + initialSize) / width) * duration;
326
+ // Create a region but don't save it until the drag ends
327
+ region = new Region(Object.assign(Object.assign({}, options), { start,
328
+ end }), duration);
329
+ // Just add it to the DOM for now
330
+ this.regionsContainer.appendChild(region.element);
331
+ },
323
332
  // On drag end
324
333
  () => {
325
334
  if (region) {
326
335
  this.saveRegion(region);
327
336
  region = null;
328
- sumDx = 0;
329
- // Prevent a click event on the waveform
330
- if (this.wavesurfer) {
331
- const { interact } = this.wavesurfer.options;
332
- if (interact) {
333
- this.wavesurfer.toggleInteraction(false);
334
- setTimeout(() => this.wavesurfer?.toggleInteraction(interact), 10);
335
- }
336
- }
337
337
  }
338
338
  });
339
339
  }
@@ -0,0 +1 @@
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):((e="undefined"!=typeof globalThis?globalThis:e||self).WaveSurfer=e.WaveSurfer||{},e.WaveSurfer.Regions=t())}(this,(function(){"use strict";class e{constructor(){this.listeners={}}on(e,t){return this.listeners[e]||(this.listeners[e]=new Set),this.listeners[e].add(t),()=>this.un(e,t)}once(e,t){const i=this.on(e,t),n=this.on(e,(()=>{i(),n()}));return i}un(e,t){this.listeners[e]&&(t?this.listeners[e].delete(t):delete this.listeners[e])}unAll(){this.listeners={}}emit(e,...t){this.listeners[e]&&this.listeners[e].forEach((e=>e(...t)))}}class t extends e{constructor(e){super(),this.subscriptions=[],this.options=e}onInit(){}init(e){this.wavesurfer=e,this.onInit()}destroy(){this.emit("destroy"),this.subscriptions.forEach((e=>e()))}}function i(e,t,i,n,s=5){let r=()=>{};if(!e)return r;const o=o=>{if(2===o.button)return;o.preventDefault(),o.stopPropagation();let l=o.clientX,a=o.clientY,d=!1;const h=n=>{n.preventDefault(),n.stopPropagation();const r=n.clientX,o=n.clientY;if(d||Math.abs(r-l)>=s||Math.abs(o-a)>=s){const{left:n,top:s}=e.getBoundingClientRect();d||(d=!0,null==i||i(l-n,a-s)),t(r-l,o-a,r-n,o-s),l=r,a=o}},u=e=>{d&&(e.preventDefault(),e.stopPropagation())},c=()=>{d&&(null==n||n()),r()};document.addEventListener("pointermove",h),document.addEventListener("pointerup",c),document.addEventListener("pointerleave",c),document.addEventListener("click",u,!0),r=()=>{document.removeEventListener("pointermove",h),document.removeEventListener("pointerup",c),document.removeEventListener("pointerleave",c),setTimeout((()=>{document.removeEventListener("click",u,!0)}),10)}};return e.addEventListener("pointerdown",o),()=>{r(),e.removeEventListener("pointerdown",o)}}class n extends e{constructor(e,t){var i,n,s,r,o,l;super(),this.totalDuration=t,this.minLength=0,this.maxLength=1/0,this.id=e.id||`region-${Math.random().toString(32).slice(2)}`,this.start=e.start,this.end=null!==(i=e.end)&&void 0!==i?i:e.start,this.drag=null===(n=e.drag)||void 0===n||n,this.resize=null===(s=e.resize)||void 0===s||s,this.color=null!==(r=e.color)&&void 0!==r?r:"rgba(0, 0, 0, 0.1)",this.minLength=null!==(o=e.minLength)&&void 0!==o?o:this.minLength,this.maxLength=null!==(l=e.maxLength)&&void 0!==l?l:this.maxLength,this.element=this.initElement(e.content),this.renderPosition(),this.initMouseEvents()}initElement(e){const t=document.createElement("div"),i=this.start===this.end;if(t.setAttribute("part",`${i?"marker":"region"} ${this.id}`),t.setAttribute("style",`\n position: absolute;\n height: 100%;\n background-color: ${i?"none":this.color};\n border-left: ${i?"2px solid "+this.color:"none"};\n border-radius: 2px;\n box-sizing: border-box;\n transition: background-color 0.2s ease;\n cursor: ${this.drag?"grab":"default"};\n pointer-events: all;\n `),e&&("string"==typeof e?(this.content=document.createElement("div"),this.content.style.padding=`0.2em ${i?.2:.4}em`,this.content.textContent=e):this.content=e,this.content.setAttribute("part","region-content"),t.appendChild(this.content)),!i){const e=document.createElement("div");e.setAttribute("data-resize","left"),e.setAttribute("style",`\n position: absolute;\n z-index: 2;\n width: 6px;\n height: 100%;\n top: 0;\n left: 0;\n border-left: 2px solid rgba(0, 0, 0, 0.5);\n border-radius: 2px 0 0 2px;\n cursor: ${this.resize?"ew-resize":"default"};\n word-break: keep-all;\n `),e.setAttribute("part","region-handle region-handle-left");const i=e.cloneNode();i.setAttribute("data-resize","right"),i.style.left="",i.style.right="0",i.style.borderRight=i.style.borderLeft,i.style.borderLeft="",i.style.borderRadius="0 2px 2px 0",i.setAttribute("part","region-handle region-handle-right"),t.appendChild(e),t.appendChild(i)}return t}renderPosition(){const e=this.start/this.totalDuration,t=(this.totalDuration-this.end)/this.totalDuration;this.element.style.left=100*e+"%",this.element.style.right=100*t+"%"}initMouseEvents(){const{element:e}=this;if(!e)return;e.addEventListener("click",(e=>this.emit("click",e))),e.addEventListener("mouseenter",(e=>this.emit("over",e))),e.addEventListener("mouseleave",(e=>this.emit("leave",e))),e.addEventListener("dblclick",(e=>this.emit("dblclick",e))),i(e,(e=>this.onMove(e)),(()=>this.onStartMoving()),(()=>this.onEndMoving()));i(e.querySelector('[data-resize="left"]'),(e=>this.onResize(e,"start")),(()=>null),(()=>this.onEndResizing()),1),i(e.querySelector('[data-resize="right"]'),(e=>this.onResize(e,"end")),(()=>null),(()=>this.onEndResizing()),1)}onStartMoving(){this.drag&&(this.element.style.cursor="grabbing")}onEndMoving(){this.drag&&(this.element.style.cursor="grab",this.emit("update-end"))}_onUpdate(e,t){if(!this.element.parentElement)return;const i=e/this.element.parentElement.clientWidth*this.totalDuration,n=t&&"start"!==t?this.start:this.start+i,s=t&&"end"!==t?this.end:this.end+i,r=s-n;n>0&&s<this.totalDuration&&n<=s&&r>=this.minLength&&r<=this.maxLength&&(this.start=n,this.end=s,this.renderPosition(),this.emit("update"))}onMove(e){this.drag&&this._onUpdate(e)}onResize(e,t){this.resize&&this._onUpdate(e,t)}onEndResizing(){this.resize&&this.emit("update-end")}_setTotalDuration(e){this.totalDuration=e,this.renderPosition()}play(){this.emit("play")}setOptions(e){var t,i;e.color&&(this.color=e.color,this.element.style.backgroundColor=this.color),void 0!==e.drag&&(this.drag=e.drag,this.element.style.cursor=this.drag?"grab":"default"),void 0!==e.resize&&(this.resize=e.resize,this.element.querySelectorAll("[data-resize]").forEach((e=>{e.style.cursor=this.resize?"ew-resize":"default"}))),void 0===e.start&&void 0===e.end||(this.start=null!==(t=e.start)&&void 0!==t?t:this.start,this.end=null!==(i=e.end)&&void 0!==i?i:this.end,this.renderPosition())}remove(){this.emit("remove"),this.element.remove(),this.element=null}}class s extends t{constructor(e){super(e),this.regions=[],this.regionsContainer=this.initRegionsContainer()}static create(e){return new s(e)}onInit(){if(!this.wavesurfer)throw Error("WaveSurfer is not initialized");this.wavesurfer.getWrapper().appendChild(this.regionsContainer)}initRegionsContainer(){const e=document.createElement("div");return e.setAttribute("style","\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n z-index: 3;\n pointer-events: none;\n "),e}getRegions(){return this.regions}avoidOverlapping(e){if(!e.content)return;const t=e.content,i=t.getBoundingClientRect().left,n=e.element.scrollWidth,s=this.regions.filter((t=>{if(t===e||!t.content)return!1;const s=t.content.getBoundingClientRect().left,r=t.element.scrollWidth;return i<s+r&&s<i+n})).map((e=>{var t;return(null===(t=e.content)||void 0===t?void 0:t.getBoundingClientRect().height)||0})).reduce(((e,t)=>e+t),0);t.style.marginTop=`${s}px`}saveRegion(e){this.regionsContainer.appendChild(e.element),this.avoidOverlapping(e),this.regions.push(e),this.emit("region-created",e);const t=[e.on("update-end",(()=>{this.avoidOverlapping(e),this.emit("region-updated",e)})),e.on("play",(()=>{var t,i;null===(t=this.wavesurfer)||void 0===t||t.play(),null===(i=this.wavesurfer)||void 0===i||i.setTime(e.start)})),e.on("click",(t=>{this.emit("region-clicked",e,t)})),e.on("dblclick",(t=>{this.emit("region-double-clicked",e,t)})),e.once("remove",(()=>{t.forEach((e=>e())),this.regions=this.regions.filter((t=>t!==e))}))];this.subscriptions.push(...t)}addRegion(e){if(!this.wavesurfer)throw Error("WaveSurfer is not initialized");const t=this.wavesurfer.getDuration(),i=new n(e,t);return t?this.saveRegion(i):this.subscriptions.push(this.wavesurfer.once("ready",(e=>{i._setTotalDuration(e),this.saveRegion(i)}))),i}enableDragSelection(e){var t,s;const r=null===(s=null===(t=this.wavesurfer)||void 0===t?void 0:t.getWrapper())||void 0===s?void 0:s.querySelector("div");if(!r)return()=>{};let o=null,l=0;return i(r,((e,t,i)=>{o&&o._onUpdate(e,i>l?"end":"start")}),(t=>{if(l=t,!this.wavesurfer)return;const i=this.wavesurfer.getDuration(),s=this.wavesurfer.getWrapper().clientWidth,r=t/s*i,a=(t+5)/s*i;o=new n(Object.assign(Object.assign({},e),{start:r,end:a}),i),this.regionsContainer.appendChild(o.element)}),(()=>{o&&(this.saveRegion(o),o=null)}))}clearRegions(){this.regions.forEach((e=>e.remove()))}destroy(){this.clearRegions(),super.destroy()}}return s}));
@@ -0,0 +1,44 @@
1
+ import EventEmitter from './event-emitter.js';
2
+ import type { WaveSurferOptions } from './wavesurfer.js';
3
+ type RendererEvents = {
4
+ click: [relativeX: number];
5
+ drag: [relativeX: number];
6
+ scroll: [relativeStart: number, relativeEnd: number];
7
+ render: [];
8
+ };
9
+ declare class Renderer extends EventEmitter<RendererEvents> {
10
+ private static MAX_CANVAS_WIDTH;
11
+ private options;
12
+ private parent;
13
+ private container;
14
+ private scrollContainer;
15
+ private wrapper;
16
+ private canvasWrapper;
17
+ private progressWrapper;
18
+ private cursor;
19
+ private timeouts;
20
+ private isScrolling;
21
+ private audioData;
22
+ private resizeObserver;
23
+ private isDragging;
24
+ constructor(options: WaveSurferOptions);
25
+ private initEvents;
26
+ private initDrag;
27
+ private getHeight;
28
+ private initHtml;
29
+ setOptions(options: WaveSurferOptions): void;
30
+ getWrapper(): HTMLElement;
31
+ getScroll(): number;
32
+ destroy(): void;
33
+ private createDelay;
34
+ private convertColorValues;
35
+ private renderBars;
36
+ private renderSingleCanvas;
37
+ private renderWaveform;
38
+ render(audioData: AudioBuffer): void;
39
+ reRender(): void;
40
+ zoom(minPxPerSec: number): void;
41
+ private scrollIntoView;
42
+ renderProgress(progress: number, isPlaying?: boolean): void;
43
+ }
44
+ export default Renderer;
@@ -0,0 +1 @@
1
+ "use strict";class t{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)))}}class e extends t{constructor(t){super(),this.subscriptions=[],this.options=t}onInit(){}init(t){this.wavesurfer=t,this.onInit()}destroy(){this.emit("destroy"),this.subscriptions.forEach((t=>t()))}}function s(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,h=t>>1;r<t;){for(a=0;a<r;a++)this.reverseTable[a+r]=this.reverseTable[a]+h;r<<=1,h>>=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,h=this.sinTable,n=this.reverseTable,l=new Float32Array(a),o=new Float32Array(a),c=2/this.bufferSize,f=Math.sqrt,p=new Float32Array(a/2),u=Math.floor(Math.log(a)/Math.LN2);if(Math.pow(2,u)!==a)throw"Invalid buffer size, must be a power of 2.";if(a!==t.length)throw"Supplied buffer is not the same size as defined FFT. FFT Size: "+a+" Buffer Size: "+t.length;for(var d,w,M,b,g,m,y,v,x=1,k=0;k<a;k++)l[k]=t[n[k]]*this.windowValues[n[k]],o[k]=0;for(;x<a;){d=r[x],w=h[x],M=1,b=0;for(var q=0;q<x;q++){for(k=q;k<a;)m=M*l[g=k+x]-b*o[g],y=M*o[g]+b*l[g],l[g]=l[k]-m,o[g]=o[k]-y,l[k]+=m,o[k]+=y,k+=x<<1;M=(v=M)*d-b*w,b=v*w+b*d}x<<=1}k=0;for(var S=a/2;k<S;k++)(i=c*f((e=l[k])*e+(s=o[k])*s))>this.peak&&(this.peakBand=k,this.peak=i),p[k]=i;return p}}class i extends e{static create(t){return new i(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,h=this.frequencyMax;if(e){for(let n=0;n<t.length;n++){const l=this.resample(t[n]),o=new ImageData(i,s);for(let t=0;t<l.length;t++)for(let e=0;e<l[t].length;e++){const a=this.colorMap[l[t][e]],r=4*((s-e)*i+t);o.data[r]=255*a[0],o.data[r+1]=255*a[1],o.data[r+2]=255*a[2],o.data[r+3]=255*a[3]}createImageBitmap(o).then((t=>{e.drawImage(t,0,s*(1-h/a),i,s*(h-r)/a,0,s*n,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),super.destroy()}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,i=this.wavesurfer.getDecodedData(),a=this.channels;if(this.frequencyMax=this.frequencyMax||i.sampleRate/2,!i)return;this.buffer=i;const r=i.sampleRate,h=[];let n=this.noverlap;if(!n){const t=i.length/this.canvas.width;n=Math.max(0,Math.round(e-t))}const l=new s(e,r,this.windowFunc,this.alpha);for(let t=0;t<a;t++){const s=i.getChannelData(t),a=[];let r=0;for(;r+e<s.length;){const t=s.slice(r,r+e),i=l.calculateSpectrum(t),h=new Uint8Array(e/2);let o;for(o=0;o<e/2;o++)h[o]=Math.max(-255,45*Math.log10(i[o]));a.push(h),r+=e-n}h.push(a)}t(h,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,h,n){t=t||"rgba(68,68,68,0)",e=e||"12px",s=s||"12px",i=i||"Helvetica",a=a||"#fff",r=r||"#fff",h=h||"center";const l=this.height||512,o=l/256*5,c=this.frequencyMin,f=(this.frequencyMax-c)/o,p=this.labelsEl.getContext("2d"),u=window.devicePixelRatio;if(this.labelsEl.height=this.height*this.channels*u,this.labelsEl.width=55*u,p.scale(u,u),p)for(let n=0;n<this.channels;n++){let u;for(p.fillStyle=t,p.fillRect(0,n*l,55,(1+n)*l),p.fill(),u=0;u<=o;u++){p.textAlign=h,p.textBaseline="middle";const t=c+f*u,o=this.freqType(t),d=this.unitType(t),w=16;let M;M=0==u?(1+n)*l+u-10:(1+n)*l-50*u+2,p.fillStyle=r,p.font=s+" "+i,p.fillText(d,w+24,M),p.fillStyle=a,p.font=e+" "+i,p.fillText(o,w,M)}}}resample(t){const e=this.width,s=[],i=1/t.length,a=1/e;let r;for(r=0;r<e;r++){const e=new Array(t[0].length);let h;for(h=0;h<t.length;h++){const s=h*i,n=s+i,l=r*a,o=l+a,c=n<=l||o<=s?0:Math.min(Math.max(n,l),Math.max(o,s))-Math.max(Math.min(n,l),Math.min(o,s));let f;if(c>0)for(f=0;f<t[0].length;f++)null==e[f]&&(e[f]=0),e[f]+=c/a*t[h][f]}const n=new Uint8Array(t[0].length);let l;for(l=0;l<t[0].length;l++)n[l]=e[l];s.push(n)}return s}}module.exports=i;
@@ -17,7 +17,10 @@
17
17
  * ]
18
18
  * });
19
19
  */
20
- import BasePlugin from '../base-plugin.js';
20
+ /**
21
+ * Spectrogram plugin for wavesurfer.
22
+ */
23
+ import BasePlugin, { type BasePluginEvents } from '../base-plugin.js';
21
24
  export type SpectrogramPluginOptions = {
22
25
  /** Selector of element or element in which to render */
23
26
  container: string | HTMLElement;
@@ -27,6 +30,9 @@ export type SpectrogramPluginOptions = {
27
30
  height?: number;
28
31
  /** Set to true to display frequency labels. */
29
32
  labels?: boolean;
33
+ labelsBackground?: string;
34
+ labelsColor?: string;
35
+ labelsHzColor?: string;
30
36
  /** Size of the overlapping window. Must be < fftSamples. Auto deduced from canvas size by default. */
31
37
  noverlap?: number;
32
38
  /** The window function to be used. */
@@ -43,11 +49,11 @@ export type SpectrogramPluginOptions = {
43
49
  */
44
50
  colorMap?: number[][];
45
51
  };
46
- export type SpectrogramPluginEvents = {
52
+ export type SpectrogramPluginEvents = BasePluginEvents & {
47
53
  ready: [];
48
54
  click: [relativeX: number];
49
55
  };
50
- export default class SpectrogramPlugin extends BasePlugin<SpectrogramPluginEvents, SpectrogramPluginOptions> {
56
+ declare class SpectrogramPlugin extends BasePlugin<SpectrogramPluginEvents, SpectrogramPluginOptions> {
51
57
  static create(options?: SpectrogramPluginOptions): SpectrogramPlugin;
52
58
  utils: {
53
59
  style: (el: HTMLElement, styles: Record<string, string>) => CSSStyleDeclaration & Record<string, string>;
@@ -67,3 +73,4 @@ export default class SpectrogramPlugin extends BasePlugin<SpectrogramPluginEvent
67
73
  loadLabels(bgFill: any, fontSizeFreq: any, fontSizeUnit: any, fontType: any, textColorFreq: any, textColorUnit: any, textAlign: any, container: any): void;
68
74
  resample(oldMatrix: any): Uint8Array[];
69
75
  }
76
+ export default SpectrogramPlugin;
@@ -0,0 +1 @@
1
+ class t{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)))}}class e extends t{constructor(t){super(),this.subscriptions=[],this.options=t}onInit(){}init(t){this.wavesurfer=t,this.onInit()}destroy(){this.emit("destroy"),this.subscriptions.forEach((t=>t()))}}function s(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,h=t>>1;r<t;){for(a=0;a<r;a++)this.reverseTable[a+r]=this.reverseTable[a]+h;r<<=1,h>>=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,h=this.sinTable,n=this.reverseTable,l=new Float32Array(a),o=new Float32Array(a),c=2/this.bufferSize,f=Math.sqrt,p=new Float32Array(a/2),u=Math.floor(Math.log(a)/Math.LN2);if(Math.pow(2,u)!==a)throw"Invalid buffer size, must be a power of 2.";if(a!==t.length)throw"Supplied buffer is not the same size as defined FFT. FFT Size: "+a+" Buffer Size: "+t.length;for(var d,w,M,b,g,m,y,v,x=1,k=0;k<a;k++)l[k]=t[n[k]]*this.windowValues[n[k]],o[k]=0;for(;x<a;){d=r[x],w=h[x],M=1,b=0;for(var q=0;q<x;q++){for(k=q;k<a;)m=M*l[g=k+x]-b*o[g],y=M*o[g]+b*l[g],l[g]=l[k]-m,o[g]=o[k]-y,l[k]+=m,o[k]+=y,k+=x<<1;M=(v=M)*d-b*w,b=v*w+b*d}x<<=1}k=0;for(var S=a/2;k<S;k++)(i=c*f((e=l[k])*e+(s=o[k])*s))>this.peak&&(this.peakBand=k,this.peak=i),p[k]=i;return p}}class i extends e{static create(t){return new i(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,h=this.frequencyMax;if(e){for(let n=0;n<t.length;n++){const l=this.resample(t[n]),o=new ImageData(i,s);for(let t=0;t<l.length;t++)for(let e=0;e<l[t].length;e++){const a=this.colorMap[l[t][e]],r=4*((s-e)*i+t);o.data[r]=255*a[0],o.data[r+1]=255*a[1],o.data[r+2]=255*a[2],o.data[r+3]=255*a[3]}createImageBitmap(o).then((t=>{e.drawImage(t,0,s*(1-h/a),i,s*(h-r)/a,0,s*n,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),super.destroy()}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,i=this.wavesurfer.getDecodedData(),a=this.channels;if(this.frequencyMax=this.frequencyMax||i.sampleRate/2,!i)return;this.buffer=i;const r=i.sampleRate,h=[];let n=this.noverlap;if(!n){const t=i.length/this.canvas.width;n=Math.max(0,Math.round(e-t))}const l=new s(e,r,this.windowFunc,this.alpha);for(let t=0;t<a;t++){const s=i.getChannelData(t),a=[];let r=0;for(;r+e<s.length;){const t=s.slice(r,r+e),i=l.calculateSpectrum(t),h=new Uint8Array(e/2);let o;for(o=0;o<e/2;o++)h[o]=Math.max(-255,45*Math.log10(i[o]));a.push(h),r+=e-n}h.push(a)}t(h,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,h,n){t=t||"rgba(68,68,68,0)",e=e||"12px",s=s||"12px",i=i||"Helvetica",a=a||"#fff",r=r||"#fff",h=h||"center";const l=this.height||512,o=l/256*5,c=this.frequencyMin,f=(this.frequencyMax-c)/o,p=this.labelsEl.getContext("2d"),u=window.devicePixelRatio;if(this.labelsEl.height=this.height*this.channels*u,this.labelsEl.width=55*u,p.scale(u,u),p)for(let n=0;n<this.channels;n++){let u;for(p.fillStyle=t,p.fillRect(0,n*l,55,(1+n)*l),p.fill(),u=0;u<=o;u++){p.textAlign=h,p.textBaseline="middle";const t=c+f*u,o=this.freqType(t),d=this.unitType(t),w=16;let M;M=0==u?(1+n)*l+u-10:(1+n)*l-50*u+2,p.fillStyle=r,p.font=s+" "+i,p.fillText(d,w+24,M),p.fillStyle=a,p.font=e+" "+i,p.fillText(o,w,M)}}}resample(t){const e=this.width,s=[],i=1/t.length,a=1/e;let r;for(r=0;r<e;r++){const e=new Array(t[0].length);let h;for(h=0;h<t.length;h++){const s=h*i,n=s+i,l=r*a,o=l+a,c=n<=l||o<=s?0:Math.min(Math.max(n,l),Math.max(o,s))-Math.max(Math.min(n,l),Math.min(o,s));let f;if(c>0)for(f=0;f<t[0].length;f++)null==e[f]&&(e[f]=0),e[f]+=c/a*t[h][f]}const n=new Uint8Array(t[0].length);let l;for(l=0;l<t[0].length;l++)n[l]=e[l];s.push(n)}return s}}export{i as default};
@@ -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
- import FFT from './spectrogram-fft.js';
23
- export default class SpectrogramPlugin extends BasePlugin {
174
+ class SpectrogramPlugin extends BasePlugin {
24
175
  static create(options) {
25
176
  return new SpectrogramPlugin(options || {});
26
177
  }
@@ -127,6 +278,7 @@ export default class SpectrogramPlugin extends BasePlugin {
127
278
  this.wrapper.remove();
128
279
  this.wrapper = null;
129
280
  }
281
+ super.destroy();
130
282
  }
131
283
  createWrapper() {
132
284
  this.wrapper = document.createElement('div');
@@ -140,6 +292,7 @@ export default class SpectrogramPlugin extends BasePlugin {
140
292
  // if labels are active
141
293
  if (this.options.labels) {
142
294
  const labelsEl = document.createElement('canvas');
295
+ labelsEl.setAttribute('part', 'spec-labels');
143
296
  labelsEl.classList.add('spec-labels');
144
297
  this.utils.style(labelsEl, {
145
298
  position: 'absolute',
@@ -180,7 +333,7 @@ export default class SpectrogramPlugin extends BasePlugin {
180
333
  else {
181
334
  this.getFrequencies(this.drawSpectrogram);
182
335
  }
183
- this.loadLabels('rgba(68,68,68,0.5)', '12px', '10px', '', '#fff', '#f7f7f7', 'center', '#specLabels');
336
+ this.loadLabels(this.options.labelsBackground, '12px', '12px', '', this.options.labelsColor, this.options.labelsHzColor || this.options.labelsColor, 'center', '#specLabels');
184
337
  }
185
338
  getFrequencies(callback) {
186
339
  const fftSamples = this.fftSamples;
@@ -236,7 +389,7 @@ export default class SpectrogramPlugin extends BasePlugin {
236
389
  const frequenciesHeight = this.height;
237
390
  bgFill = bgFill || 'rgba(68,68,68,0)';
238
391
  fontSizeFreq = fontSizeFreq || '12px';
239
- fontSizeUnit = fontSizeUnit || '10px';
392
+ fontSizeUnit = fontSizeUnit || '12px';
240
393
  fontType = fontType || 'Helvetica';
241
394
  textColorFreq = textColorFreq || '#fff';
242
395
  textColorUnit = textColorUnit || '#fff';
@@ -275,26 +428,18 @@ export default class SpectrogramPlugin extends BasePlugin {
275
428
  let y;
276
429
  if (i == 0) {
277
430
  y = (1 + c) * getMaxY + i - 10;
278
- // unit label
279
- ctx.fillStyle = textColorUnit;
280
- ctx.font = fontSizeUnit + ' ' + fontType;
281
- ctx.fillText(units, x + 24, y);
282
- // freq label
283
- ctx.fillStyle = textColorFreq;
284
- ctx.font = fontSizeFreq + ' ' + fontType;
285
- ctx.fillText(label, x, y);
286
431
  }
287
432
  else {
288
433
  y = (1 + c) * getMaxY - i * 50 + yLabelOffset;
289
- // unit label
290
- ctx.fillStyle = textColorUnit;
291
- ctx.font = fontSizeUnit + ' ' + fontType;
292
- ctx.fillText(units, x + 24, y);
293
- // freq label
294
- ctx.fillStyle = textColorFreq;
295
- ctx.font = fontSizeFreq + ' ' + fontType;
296
- ctx.fillText(label, x, y);
297
434
  }
435
+ // unit label
436
+ ctx.fillStyle = textColorUnit;
437
+ ctx.font = fontSizeUnit + ' ' + fontType;
438
+ ctx.fillText(units, x + 24, y);
439
+ // freq label
440
+ ctx.fillStyle = textColorFreq;
441
+ ctx.font = fontSizeFreq + ' ' + fontType;
442
+ ctx.fillText(label, x, y);
298
443
  }
299
444
  }
300
445
  }
@@ -338,3 +483,4 @@ export default class SpectrogramPlugin extends BasePlugin {
338
483
  return newMatrix;
339
484
  }
340
485
  }
486
+ export default SpectrogramPlugin;
@@ -0,0 +1 @@
1
+ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):((t="undefined"!=typeof globalThis?globalThis:t||self).WaveSurfer=t.WaveSurfer||{},t.WaveSurfer.Spectrogram=e())}(this,(function(){"use strict";class t{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)))}}class e extends t{constructor(t){super(),this.subscriptions=[],this.options=t}onInit(){}init(t){this.wavesurfer=t,this.onInit()}destroy(){this.emit("destroy"),this.subscriptions.forEach((t=>t()))}}function s(t,e,s,i){switch(this.bufferSize=t,this.sampleRate=e,this.bandwidth=2/t*(e/2),this.sinTable=new Float32Array(t),this.cosTable=new Float32Array(t),this.windowValues=new Float32Array(t),this.reverseTable=new Uint32Array(t),this.peakBand=0,this.peak=0,s){case"bartlett":for(a=0;a<t;a++)this.windowValues[a]=2/(t-1)*((t-1)/2-Math.abs(a-(t-1)/2));break;case"bartlettHann":for(a=0;a<t;a++)this.windowValues[a]=.62-.48*Math.abs(a/(t-1)-.5)-.38*Math.cos(2*Math.PI*a/(t-1));break;case"blackman":for(i=i||.16,a=0;a<t;a++)this.windowValues[a]=(1-i)/2-.5*Math.cos(2*Math.PI*a/(t-1))+i/2*Math.cos(4*Math.PI*a/(t-1));break;case"cosine":for(a=0;a<t;a++)this.windowValues[a]=Math.cos(Math.PI*a/(t-1)-Math.PI/2);break;case"gauss":for(i=i||.25,a=0;a<t;a++)this.windowValues[a]=Math.pow(Math.E,-.5*Math.pow((a-(t-1)/2)/(i*(t-1)/2),2));break;case"hamming":for(a=0;a<t;a++)this.windowValues[a]=.54-.46*Math.cos(2*Math.PI*a/(t-1));break;case"hann":case void 0:for(a=0;a<t;a++)this.windowValues[a]=.5*(1-Math.cos(2*Math.PI*a/(t-1)));break;case"lanczoz":for(a=0;a<t;a++)this.windowValues[a]=Math.sin(Math.PI*(2*a/(t-1)-1))/(Math.PI*(2*a/(t-1)-1));break;case"rectangular":for(a=0;a<t;a++)this.windowValues[a]=1;break;case"triangular":for(a=0;a<t;a++)this.windowValues[a]=2/t*(t/2-Math.abs(a-(t-1)/2));break;default:throw Error("No such window function '"+s+"'")}for(var a,r=1,n=t>>1;r<t;){for(a=0;a<r;a++)this.reverseTable[a+r]=this.reverseTable[a]+n;r<<=1,n>>=1}for(a=0;a<t;a++)this.sinTable[a]=Math.sin(-Math.PI/a),this.cosTable[a]=Math.cos(-Math.PI/a);this.calculateSpectrum=function(t){var e,s,i,a=this.bufferSize,r=this.cosTable,n=this.sinTable,h=this.reverseTable,l=new Float32Array(a),o=new Float32Array(a),c=2/this.bufferSize,f=Math.sqrt,u=new Float32Array(a/2),p=Math.floor(Math.log(a)/Math.LN2);if(Math.pow(2,p)!==a)throw"Invalid buffer size, must be a power of 2.";if(a!==t.length)throw"Supplied buffer is not the same size as defined FFT. FFT Size: "+a+" Buffer Size: "+t.length;for(var d,w,b,M,g,m,y,v,x=1,S=0;S<a;S++)l[S]=t[h[S]]*this.windowValues[h[S]],o[S]=0;for(;x<a;){d=r[x],w=n[x],b=1,M=0;for(var k=0;k<x;k++){for(S=k;S<a;)m=b*l[g=S+x]-M*o[g],y=b*o[g]+M*l[g],l[g]=l[S]-m,o[g]=o[S]-y,l[S]+=m,o[S]+=y,S+=x<<1;b=(v=b)*d-M*w,M=v*w+M*d}x<<=1}S=0;for(var q=a/2;S<q;S++)(i=c*f((e=l[S])*e+(s=o[S])*s))>this.peak&&(this.peakBand=S,this.peak=i),u[S]=i;return u}}class i extends e{static create(t){return new i(t||{})}constructor(t){if(super(t),this.utils={style:(t,e)=>Object.assign(t.style,e)},this.drawSpectrogram=t=>{isNaN(t[0][0])||(t=[t]);const e=this.spectrCc,s=this.height,i=this.width,a=this.buffer.sampleRate/2,r=this.frequencyMin,n=this.frequencyMax;if(e){for(let h=0;h<t.length;h++){const l=this.resample(t[h]),o=new ImageData(i,s);for(let t=0;t<l.length;t++)for(let e=0;e<l[t].length;e++){const a=this.colorMap[l[t][e]],r=4*((s-e)*i+t);o.data[r]=255*a[0],o.data[r+1]=255*a[1],o.data[r+2]=255*a[2],o.data[r+3]=255*a[3]}createImageBitmap(o).then((t=>{e.drawImage(t,0,s*(1-n/a),i,s*(n-r)/a,0,s*h,i,s)}))}this.emit("ready")}},this.frequenciesDataUrl=t.frequenciesDataUrl,this.container="string"==typeof t.container?document.querySelector(t.container):t.container,t.colorMap){if(t.colorMap.length<256)throw new Error("Colormap must contain 256 elements");for(let e=0;e<t.colorMap.length;e++){if(4!==t.colorMap[e].length)throw new Error("ColorMap entries must contain 4 values")}this.colorMap=t.colorMap}else{this.colorMap=[];for(let t=0;t<256;t++){const e=(255-t)/256;this.colorMap.push([e,e,e,1])}}this.fftSamples=t.fftSamples||512,this.height=t.height||this.fftSamples/2,this.noverlap=t.noverlap,this.windowFunc=t.windowFunc,this.alpha=t.alpha,this.channels=1,this.frequencyMin=t.frequencyMin||0,this.frequencyMax=t.frequencyMax||0,this.createWrapper(),this.createCanvas()}onInit(){this.container=this.container||this.wavesurfer.getWrapper(),this.container.appendChild(this.wrapper),this.wavesurfer.options.fillParent&&this.utils.style(this.wrapper,{width:"100%",overflowX:"hidden",overflowY:"hidden"}),this.width=this.wavesurfer.getWrapper().offsetWidth,this.subscriptions.push(this.wavesurfer.on("redraw",(()=>this.render())))}destroy(){this.unAll(),this.wavesurfer.un("ready",this._onReady),this.wavesurfer.un("redraw",this._onRender),this.wavesurfer=null,this.util=null,this.options=null,this.wrapper&&(this.wrapper.remove(),this.wrapper=null),super.destroy()}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,i=this.wavesurfer.getDecodedData(),a=this.channels;if(this.frequencyMax=this.frequencyMax||i.sampleRate/2,!i)return;this.buffer=i;const r=i.sampleRate,n=[];let h=this.noverlap;if(!h){const t=i.length/this.canvas.width;h=Math.max(0,Math.round(e-t))}const l=new s(e,r,this.windowFunc,this.alpha);for(let t=0;t<a;t++){const s=i.getChannelData(t),a=[];let r=0;for(;r+e<s.length;){const t=s.slice(r,r+e),i=l.calculateSpectrum(t),n=new Uint8Array(e/2);let o;for(o=0;o<e/2;o++)n[o]=Math.max(-255,45*Math.log10(i[o]));a.push(n),r+=e-h}n.push(a)}t(n,this)}loadFrequenciesData(t){return fetch(t).then((t=>t.json())).then(this.drawSpectrogram)}freqType(t){return t>=1e3?(t/1e3).toFixed(1):Math.round(t)}unitType(t){return t>=1e3?"KHz":"Hz"}loadLabels(t,e,s,i,a,r,n,h){t=t||"rgba(68,68,68,0)",e=e||"12px",s=s||"12px",i=i||"Helvetica",a=a||"#fff",r=r||"#fff",n=n||"center";const l=this.height||512,o=l/256*5,c=this.frequencyMin,f=(this.frequencyMax-c)/o,u=this.labelsEl.getContext("2d"),p=window.devicePixelRatio;if(this.labelsEl.height=this.height*this.channels*p,this.labelsEl.width=55*p,u.scale(p,p),u)for(let h=0;h<this.channels;h++){let p;for(u.fillStyle=t,u.fillRect(0,h*l,55,(1+h)*l),u.fill(),p=0;p<=o;p++){u.textAlign=n,u.textBaseline="middle";const t=c+f*p,o=this.freqType(t),d=this.unitType(t),w=16;let b;b=0==p?(1+h)*l+p-10:(1+h)*l-50*p+2,u.fillStyle=r,u.font=s+" "+i,u.fillText(d,w+24,b),u.fillStyle=a,u.font=e+" "+i,u.fillText(o,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,l=r*a,o=l+a,c=h<=l||o<=s?0:Math.min(Math.max(h,l),Math.max(o,s))-Math.max(Math.min(h,l),Math.min(o,s));let f;if(c>0)for(f=0;f<t[0].length;f++)null==e[f]&&(e[f]=0),e[f]+=c/a*t[n][f]}const h=new Uint8Array(t[0].length);let l;for(l=0;l<t[0].length;l++)h[l]=e[l];s.push(h)}return s}}return i}));
@@ -0,0 +1 @@
1
+ "use strict";class t{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)))}}class e extends t{constructor(t){super(),this.subscriptions=[],this.options=t}onInit(){}init(t){this.wavesurfer=t,this.onInit()}destroy(){this.emit("destroy"),this.subscriptions.forEach((t=>t()))}}const i={height:20,formatTimeCallback:t=>{if(t/60>1){return`${Math.floor(t/60)}:${`${(t=Math.round(t%60))<10?"0":""}${t}`}`}return`${Math.round(1e3*t)/1e3}`}};class s extends e{constructor(t){super(t||{}),this.options=Object.assign({},i,t),this.timelineWrapper=this.initTimelineWrapper()}static create(t){return new s(t)}onInit(){var t;if(!this.wavesurfer)throw Error("WaveSurfer is not initialized");const e=null!==(t=this.options.container)&&void 0!==t?t:this.wavesurfer.getWrapper();this.options.insertPosition?(e.firstElementChild||e).insertAdjacentElement(this.options.insertPosition,this.timelineWrapper):e.appendChild(this.timelineWrapper),this.options.duration?this.initTimeline(this.options.duration):this.subscriptions.push(this.wavesurfer.on("redraw",(()=>{var t;this.initTimeline((null===(t=this.wavesurfer)||void 0===t?void 0:t.getDuration())||0)})))}destroy(){this.timelineWrapper.remove(),super.destroy()}initTimelineWrapper(){const t=document.createElement("div");return t.setAttribute("part","timeline"),t}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){var e,i,s;const n=this.timelineWrapper.scrollWidth/t,r=null!==(e=this.options.timeInterval)&&void 0!==e?e:this.defaultTimeInterval(n),o=null!==(i=this.options.primaryLabelInterval)&&void 0!==i?i:this.defaultPrimaryLabelInterval(n),l=null!==(s=this.options.secondaryLabelInterval)&&void 0!==s?s:this.defaultSecondaryLabelInterval(n),a="beforebegin"===this.options.insertPosition,h=document.createElement("div");if(h.setAttribute("style",`\n height: ${this.options.height}px;\n overflow: hidden;\n font-size: ${this.options.height/2}px;\n white-space: nowrap;\n position: relative;\n `),a){const t="\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n z-index: 2;\n ";h.setAttribute("style",h.getAttribute("style")+t)}"string"==typeof this.options.style?h.setAttribute("style",h.getAttribute("style")+this.options.style):"object"==typeof this.options.style&&Object.assign(h.style,this.options.style);const p=document.createElement("div");p.setAttribute("part","timeline-notch"),p.setAttribute("style",`\n width: 0;\n height: 50%;\n display: flex;\n flex-direction: column;\n justify-content: ${a?"flex-start":"flex-end"};\n ${a?"top: 0;":"bottom: 0;"}\n overflow: visible;\n border-left: 1px solid currentColor;\n opacity: 0.25;\n position: absolute;\n z-index: 1;\n `);for(let e=0;e<t;e+=r){const t=p.cloneNode(),i=Math.round(100*e)/100%o==0,s=Math.round(100*e)/100%l==0;(i||s)&&(t.style.height="100%",t.style.textIndent="3px",t.textContent=this.options.formatTimeCallback(e),i&&(t.style.opacity="1")),t.style.left=e*n+"px",h.appendChild(t)}this.timelineWrapper.innerHTML="",this.timelineWrapper.appendChild(h),this.emit("ready")}}module.exports=s;