wavesurfer.js 7.0.0-alpha.35 → 7.0.0-alpha.37

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.
@@ -3,8 +3,8 @@ import Player from './player.js';
3
3
  import type { GenericPlugin } from './base-plugin.js';
4
4
  export type WaveSurferOptions = {
5
5
  /** HTML element or CSS selector */
6
- container: HTMLElement | string | null;
7
- /** Height of the waveform in pixels */
6
+ container: HTMLElement | string;
7
+ /** The height of the waveform in pixels */
8
8
  height?: number;
9
9
  /** The color of the waveform */
10
10
  waveColor?: string;
@@ -12,15 +12,15 @@ export type WaveSurferOptions = {
12
12
  progressColor?: string;
13
13
  /** The color of the playpack cursor */
14
14
  cursorColor?: string;
15
- /** The cursor with */
15
+ /** The cursor width */
16
16
  cursorWidth?: number;
17
- /** If set, the waveform will be rendered in bars like so: ▁ ▂ ▇ ▃ ▅ ▂ */
17
+ /** If set, the waveform will be rendered with bars like this: ▁ ▂ ▇ ▃ ▅ ▂ */
18
18
  barWidth?: number;
19
19
  /** Spacing between bars in pixels */
20
20
  barGap?: number;
21
21
  /** Rounded borders for bars */
22
22
  barRadius?: number;
23
- /** Minimum pixels per second of audio (zoom) */
23
+ /** Minimum pixels per second of audio (i.e. zoom level) */
24
24
  minPxPerSec?: number;
25
25
  /** Stretch the waveform to fill the container, true by default */
26
26
  fillParent?: boolean;
@@ -34,15 +34,15 @@ export type WaveSurferOptions = {
34
34
  media?: HTMLMediaElement;
35
35
  /** Play the audio on load */
36
36
  autoplay?: boolean;
37
- /** Is the waveform clickable? */
37
+ /** Pass false to disable clicks on the waveform */
38
38
  interact?: boolean;
39
- /** Hide scrollbar **/
39
+ /** Hide the scrollbar */
40
40
  hideScrollbar?: boolean;
41
41
  /** Audio rate */
42
42
  audioRate?: number;
43
- /** Keep scroll to the center of the waveform during playback */
43
+ /** Keep scroll in the center of the waveform during playback */
44
44
  autoCenter?: boolean;
45
- /** Initialize plugins */
45
+ /** The list of plugins to initialize on start */
46
46
  plugins?: GenericPlugin[];
47
47
  };
48
48
  declare const defaultOptions: {
@@ -57,50 +57,33 @@ declare const defaultOptions: {
57
57
  };
58
58
  export type WaveSurferEvents = {
59
59
  /** When an audio is being loaded */
60
- loading: {
61
- url: string;
62
- };
60
+ loading: [url: string];
63
61
  /** When the audio has been decoded */
64
- decode: {
65
- duration: number;
66
- };
62
+ decode: [duration: number];
67
63
  /** When the media element has loaded enough to play */
68
- canplay: {
69
- duration: number;
70
- };
64
+ canplay: [duration: number];
71
65
  /** When the audio is both decoded and can play */
72
- ready: {
73
- duration: number;
74
- };
66
+ ready: [duration: number];
75
67
  /** When a waveform is drawn */
76
- redraw: void;
68
+ redraw: [];
77
69
  /** When the audio starts playing */
78
- play: void;
70
+ play: [];
79
71
  /** When the audio pauses */
80
- pause: void;
72
+ pause: [];
81
73
  /** When the audio finishes playing */
82
- finish: void;
83
- /** Fires continuously while the audio is playing */
84
- timeupdate: {
85
- currentTime: number;
86
- };
74
+ finish: [];
75
+ /** On audio position change, fires continuously while the audio is playing */
76
+ timeupdate: [currentTime: number];
77
+ /** An alias of timeupdate but only when the audio is playing */
78
+ audioprocess: [currentTime: number];
87
79
  /** When the user seeks to a new position */
88
- seeking: {
89
- currentTime: number;
90
- };
80
+ seeking: [currentTime: number];
91
81
  /** When a user interaction (i.e. a click on the waveform) happens */
92
- interaction: void;
82
+ interaction: [];
93
83
  /** When the zoom level changes */
94
- zoom: {
95
- minPxPerSec: number;
96
- };
84
+ zoom: [minPxPerSec: number];
97
85
  /** Just before the waveform is destroyed so you can clean up your events */
98
- destroy: void;
99
- };
100
- export type WaveSurferPluginParams = {
101
- wavesurfer: WaveSurfer;
102
- container: HTMLElement;
103
- wrapper: HTMLElement;
86
+ destroy: [];
104
87
  };
105
88
  declare class WaveSurfer extends Player<WaveSurferEvents> {
106
89
  options: WaveSurferOptions & typeof defaultOptions;
@@ -53,7 +53,7 @@ class WaveSurfer extends Player {
53
53
  this.subscriptions.push(this.onMediaEvent('timeupdate', () => {
54
54
  const currentTime = this.getCurrentTime();
55
55
  this.renderer.renderProgress(currentTime / this.getDuration(), this.isPlaying());
56
- this.emit('timeupdate', { currentTime });
56
+ this.emit('timeupdate', currentTime);
57
57
  }), this.onMediaEvent('play', () => {
58
58
  this.emit('play');
59
59
  this.timer.start();
@@ -65,14 +65,14 @@ class WaveSurfer extends Player {
65
65
  }
66
66
  }), this.onMediaEvent('canplay', () => {
67
67
  this.canPlay = true;
68
- this.emit('canplay', { duration: this.getDuration() });
68
+ this.emit('canplay', this.getDuration());
69
69
  }), this.onMediaEvent('seeking', () => {
70
- this.emit('seeking', { currentTime: this.getCurrentTime() });
70
+ this.emit('seeking', this.getCurrentTime());
71
71
  }));
72
72
  }
73
73
  initRendererEvents() {
74
74
  // Seek on click
75
- this.subscriptions.push(this.renderer.on('click', ({ relativeX }) => {
75
+ this.subscriptions.push(this.renderer.on('click', (relativeX) => {
76
76
  if (this.options.interact) {
77
77
  this.seekTo(relativeX);
78
78
  this.emit('interaction');
@@ -84,13 +84,14 @@ class WaveSurfer extends Player {
84
84
  this.subscriptions.push(this.timer.on('tick', () => {
85
85
  const currentTime = this.getCurrentTime();
86
86
  this.renderer.renderProgress(currentTime / this.getDuration(), true);
87
- this.emit('timeupdate', { currentTime });
87
+ this.emit('timeupdate', currentTime);
88
+ this.emit('audioprocess', currentTime);
88
89
  }));
89
90
  }
90
91
  initReadyEvent() {
91
92
  const emitReady = () => {
92
93
  if (this.decodedData && this.canPlay) {
93
- this.emit('ready', { duration: this.getDuration() });
94
+ this.emit('ready', this.getDuration());
94
95
  }
95
96
  };
96
97
  this.subscriptions.push(this.on('decode', emitReady), this.on('canplay', emitReady));
@@ -121,7 +122,7 @@ class WaveSurfer extends Player {
121
122
  this.decodedData = null;
122
123
  this.canPlay = false;
123
124
  this.loadUrl(url);
124
- this.emit('loading', { url });
125
+ this.emit('loading', url);
125
126
  // Fetch and decode the audio of no pre-computed audio data is provided
126
127
  if (channelData == null) {
127
128
  const audio = await this.fetcher.load(url);
@@ -138,7 +139,7 @@ class WaveSurfer extends Player {
138
139
  this.decodedData = this.decoder.createBuffer(channelData, duration);
139
140
  }
140
141
  this.renderAudio();
141
- this.emit('decode', { duration: this.getDuration() });
142
+ this.emit('decode', this.getDuration());
142
143
  this.emit('redraw');
143
144
  }
144
145
  renderAudio() {
@@ -157,7 +158,7 @@ class WaveSurfer extends Player {
157
158
  throw new Error('No audio loaded');
158
159
  }
159
160
  this.renderer.zoom(minPxPerSec);
160
- this.emit('zoom', { minPxPerSec });
161
+ this.emit('zoom', minPxPerSec);
161
162
  }
162
163
  /** Get the decoded audio data */
163
164
  getDecodedData() {
@@ -1 +1 @@
1
- !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.WaveSurfer=e():t.WaveSurfer=e()}(this,(()=>(()=>{"use strict";var t={d:(e,i)=>{for(var s in i)t.o(i,s)&&!t.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:i[s]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)},e={};t.d(e,{default:()=>d});const i=class{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)},n=String(t);return this.eventTarget.addEventListener(n,s,{once:i}),()=>this.eventTarget.removeEventListener(n,s)}once(t,e){return this.on(t,e,!0)}};class s extends i{constructor(t,e){super(),this.options={height:0},this.timeout=null,this.isScrolling=!1,this.channelData=null,this.duration=null,this.resizeObserver=null,this.options={...e};let i=null;if("string"==typeof t.container?i=document.querySelector(t.container):t.container instanceof HTMLElement&&(i=t.container),!i)throw new Error("Container not found");const[s,n]=this.initHtml();i.appendChild(s),this.container=s,this.scrollContainer=n.querySelector(".scroll"),this.wrapper=n.querySelector(".wrapper"),this.canvasWrapper=n.querySelector(".canvases"),this.progressWrapper=n.querySelector(".progress"),this.wrapper.addEventListener("click",(t=>{const e=this.wrapper.getBoundingClientRect(),i=(t.clientX-e.left)/e.width;this.emit("click",{relativeX:i})})),this.resizeObserver=new ResizeObserver((()=>{this.delay((()=>this.reRender()),100)})),this.resizeObserver.observe(this.scrollContainer)}initHtml(){const t=document.createElement("div"),e=t.attachShadow({mode:"open"});return e.innerHTML=`\n <style>\n :host {\n user-select: none;\n }\n :host .scroll {\n overflow-x: auto;\n overflow-y: hidden;\n width: 100%;\n position: relative;\n }\n :host .noScrollbar {\n scrollbar-color: transparent;\n scrollbar-width: none;\n }\n :host .noScrollbar::-webkit-scrollbar {\n display: none;\n -webkit-appearance: none;\n }\n :host .wrapper {\n position: relative;\n overflow: visible;\n z-index: 2;\n }\n :host .canvases {\n position: relative;\n height: ${this.options.height}px;\n }\n :host canvas {\n display: block;\n position: absolute;\n top: 0;\n image-rendering: pixelated;\n height: ${this.options.height}px;\n }\n :host .progress {\n pointer-events: none;\n position: absolute;\n z-index: 2;\n top: 0;\n left: 0;\n width: 0;\n height: 100%;\n overflow: hidden;\n box-sizing: border-box;\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 `,[t,e]}setOptions(t){this.options=t,this.reRender()}getContainer(){return this.scrollContainer}getWrapper(){return this.wrapper}destroy(){this.container.remove(),this.resizeObserver?.disconnect()}delay(t,e=10){return this.timeout&&clearTimeout(this.timeout),new Promise((i=>{this.timeout=setTimeout((()=>{i(t())}),e)}))}async renderPeaks(t,e,i,n){const r=null!=this.options.barWidth?this.options.barWidth*n:1,o=null!=this.options.barGap?this.options.barGap*n:this.options.barWidth?r/2:0,a=this.options.barRadius??0,h=t[0],d=h.length,l=Math.floor(e/(r+o))/d,c=i/2,p=1===t.length,u=p?h:t[1],m=p&&u.some((t=>t<0)),g=(t,i)=>{let s=0,p=0,g=0;const y=document.createElement("canvas");y.width=Math.round(e*(i-t)/d),y.height=this.options.height,y.style.width=`${Math.floor(y.width/n)}px`,y.style.height=`${this.options.height}px`,y.style.left=`${Math.floor(t*e/n/d)}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>s){const t=Math.round(p*c),e=Math.round(g*c);v.roundRect(s*(r+o),c-t,r,t+e||1,a),s=i,p=0,g=0}const n=m?h[e]:Math.abs(h[e]),d=m?u[e]:Math.abs(u[e]);n>p&&(p=n),(m?d<-g:d>g)&&(g=d<0?-d:d)}v.fill(),v.closePath();const f=y.cloneNode();this.progressWrapper.appendChild(f);const b=f.getContext("2d",{desynchronized:!0});y.width>0&&y.height>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:y,scrollWidth:v,clientWidth:f}=this.scrollContainer,b=d/v;let C=Math.min(s.MAX_CANVAS_WIDTH,f);C-=C%((r+o)/n);const w=Math.floor(Math.abs(y)*b),x=Math.ceil(w+C*b);g(w,x);const P=x-w;for(let t=x;t<d;t+=P)await this.delay((()=>{g(t,Math.min(d,t+P))}));for(let t=w-1;t>=0;t-=P)await this.delay((()=>{g(Math.max(0,t-P),t)}))}render(t,e){const i=window.devicePixelRatio||1,s=this.scrollContainer.clientWidth,n=Math.ceil(e*(this.options.minPxPerSec||0));this.isScrolling=n>s;const r=this.options.fillParent&&!this.isScrolling,o=(r?s:n)*i,{height:a}=this.options;this.wrapper.style.width=r?"100%":`${n}px`,this.scrollContainer.style.overflowX=this.isScrolling?"auto":"hidden",this.scrollContainer.classList.toggle("noScrollbar",!!this.options.hideScrollbar),this.progressWrapper.style.borderRightStyle="solid",this.progressWrapper.style.borderRightColor=`${this.options.cursorColor||this.options.progressColor}`,this.progressWrapper.style.borderRightWidth=`${this.options.cursorWidth}px`,this.canvasWrapper.style.height=`${this.options.height}px`,this.renderPeaks(t,o,a,i),this.channelData=t,this.duration=e}reRender(){if(!this.channelData||!this.duration)return;const t=this.progressWrapper.clientWidth;this.render(this.channelData,this.duration);const e=this.progressWrapper.clientWidth;this.scrollContainer.scrollLeft+=e-t}zoom(t){this.options.minPxPerSec=t,this.reRender()}renderProgress(t,e=!1){if(!isNaN(t)&&(this.progressWrapper.style.width=100*t+"%",this.isScrolling&&this.options.autoCenter)){const{clientWidth:i,scrollLeft:s,scrollWidth:n}=this.scrollContainer,r=n*t,o=i/2,a=o/20;(r>s+(e?o:i)||r<s)&&(r-(s+o)>=a&&r<s+i?this.scrollContainer.scrollLeft+=a:this.scrollContainer.scrollLeft=r-o)}}}s.MAX_CANVAS_WIDTH=4e3;const n=s,r=class extends i{constructor(t){super(),this.subscriptions=[],this.isExternalMedia=!1,this.hasPlayedOnce=!1,t.media?(this.media=t.media,this.isExternalMedia=!0):this.media=document.createElement("audio"),this.subscriptions.push(this.onceMediaEvent("play",(()=>{this.hasPlayedOnce=!0}))),t.autoplay&&(this.media.autoplay=!0),null!=t.playbackRate&&(this.media.playbackRate=t.playbackRate)}onMediaEvent(t,e,i){return this.media.addEventListener(t,e,i),()=>this.media.removeEventListener(t,e)}onceMediaEvent(t,e){return this.onMediaEvent(t,e,{once:!0})}loadUrl(t){this.media.src=t}destroy(){this.media.pause(),this.subscriptions.forEach((t=>t())),this.isExternalMedia||this.media.remove()}play(){return this.media.play()}pause(){this.media.pause()}isPlaying(){return this.media.currentTime>0&&!this.media.paused&&!this.media.ended}setTime(t){this.hasPlayedOnce||this.media.play()?.then?.((()=>{setTimeout((()=>this.media.pause()),10)})),this.media.currentTime=t}getDuration(){return this.media.duration}getCurrentTime(){return this.media.currentTime}getVolume(){return this.media.volume}setVolume(t){this.media.volume=t}getMuted(){return this.media.muted}setMuted(t){this.media.muted=t}getPlaybackRate(){return this.media.playbackRate}setPlaybackRate(t,e){null!=e&&(this.media.preservesPitch=e),this.media.playbackRate=t}getMediaElement(){return this.media}setSinkId(t){return this.media.setSinkId(t)}},o=class extends i{constructor(){super(...arguments),this.unsubscribe=()=>{}}start(){this.unsubscribe=this.on("tick",(()=>{requestAnimationFrame((()=>{this.emit("tick")}))})),this.emit("tick")}stop(){this.unsubscribe()}destroy(){this.unsubscribe()}},a={height:128,waveColor:"#999",progressColor:"#555",cursorWidth:1,minPxPerSec:0,fillParent:!0,interact:!0,autoCenter:!0};class h extends r{static create(t){return new h(t)}constructor(t){super({media:t.media,autoplay:t.autoplay,playbackRate:t.audioRate}),this.plugins=[],this.decodedData=null,this.canPlay=!1,this.options=Object.assign({},a,t),this.fetcher=new class{async load(t){return fetch(t).then((t=>t.arrayBuffer()))}},this.decoder=new class{initAudioContext(t){this.audioCtx=new AudioContext({latencyHint:"playback",sampleRate:t})}constructor(){this.audioCtx=null;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)}createBuffer(t,e){if("number"==typeof t[0]&&(t=[t]),t[0].some((t=>t>1||t<-1))){const e=Math.max(...t[0]);t=t.map((t=>t.map((t=>t/e))))}return{length:t[0].length,duration:e,numberOfChannels:t.length,sampleRate:t[0].length/e,getChannelData:e=>t?.[e],copyFromChannel:AudioBuffer.prototype.copyFromChannel,copyToChannel:AudioBuffer.prototype.copyToChannel}}destroy(){this.audioCtx?.close(),this.audioCtx=null}},this.timer=new o,this.renderer=new n({container:this.options.container},this.options),this.initPlayerEvents(),this.initRendererEvents(),this.initTimerEvents(),this.initReadyEvent(),this.initPlugins();const e=this.options.url||this.options.media?.src;e&&this.load(e,this.options.peaks,this.options.duration)}setOptions(t){this.options={...this.options,...t},this.renderer.setOptions(this.options)}initPlayerEvents(){this.subscriptions.push(this.onMediaEvent("timeupdate",(()=>{const t=this.getCurrentTime();this.renderer.renderProgress(t/this.getDuration(),this.isPlaying()),this.emit("timeupdate",{currentTime:t})})),this.onMediaEvent("play",(()=>{this.emit("play"),this.timer.start()})),this.onMediaEvent("pause",(()=>{this.emit("pause"),this.timer.stop(),this.getCurrentTime()>=this.getDuration()&&this.emit("finish")})),this.onMediaEvent("canplay",(()=>{this.canPlay=!0,this.emit("canplay",{duration:this.getDuration()})})),this.onMediaEvent("seeking",(()=>{this.emit("seeking",{currentTime:this.getCurrentTime()})})))}initRendererEvents(){this.subscriptions.push(this.renderer.on("click",(({relativeX:t})=>{this.options.interact&&(this.seekTo(t),this.emit("interaction"))})))}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(){const t=()=>{this.decodedData&&this.canPlay&&this.emit("ready",{duration:this.getDuration()})};this.subscriptions.push(this.on("decode",t),this.on("canplay",t))}initPlugins(){this.options.plugins?.length&&this.options.plugins.forEach((t=>{this.registerPlugin(t)}))}registerPlugin(t){return t.init({wavesurfer:this,container:this.renderer.getContainer(),wrapper:this.renderer.getWrapper()}),this.plugins.push(t),t}getActivePlugins(){return this.plugins}async load(t,e,i){if(this.decodedData=null,this.canPlay=!1,this.loadUrl(t),this.emit("loading",{url: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.onceMediaEvent("loadedmetadata",(()=>t(this.getDuration())))}))||0),this.decodedData=this.decoder.createBuffer(e,i);this.renderAudio(),this.emit("decode",{duration:this.getDuration()}),this.emit("redraw")}renderAudio(){if(!this.decodedData)return;const t=[this.decodedData.getChannelData(0)];this.decodedData.numberOfChannels>1&&t.push(this.decodedData.getChannelData(1)),this.renderer.render(t,this.decodedData.duration)}zoom(t){if(!this.decodedData)throw new Error("No audio loaded");this.renderer.zoom(t),this.emit("zoom",{minPxPerSec:t})}getDecodedData(){return this.decodedData}getDuration(){const t=super.getDuration();return t>0&&t<1/0?t:this.decodedData?.duration||0}toggleInteraction(t){this.options.interact=t}seekTo(t){const e=this.getDuration()*t;this.setTime(e)}playPause(){return this.isPlaying()?(this.pause(),Promise.resolve()):this.play()}stop(){this.pause(),this.setTime(0)}skip(t){this.setTime(this.getCurrentTime()+t)}empty(){this.load("",[[0]],.001)}destroy(){this.emit("destroy"),this.plugins.forEach((t=>t.destroy())),this.timer.destroy(),this.decoder.destroy(),this.renderer.destroy(),super.destroy()}}const d=h;return e.default})()));
1
+ !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.WaveSurfer=e():t.WaveSurfer=e()}(this,(()=>(()=>{"use strict";var t={d:(e,i)=>{for(var s in i)t.o(i,s)&&!t.o(e,s)&&Object.defineProperty(e,s,{enumerable:!0,get:i[s]})},o:(t,e)=>Object.prototype.hasOwnProperty.call(t,e)},e={};t.d(e,{default:()=>l});const i=class{constructor(){this.listeners={}}on(t,e){return this.listeners[t]||(this.listeners[t]=new Set),this.listeners[t].add(e),()=>this.un(t,e)}once(t,e){const i=this.on(t,e),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 s extends i{constructor(t,e){super(),this.options={height:0},this.timeout=null,this.isScrolling=!1,this.channelData=null,this.duration=null,this.resizeObserver=null,this.options={...e};let i=null;if("string"==typeof t.container?i=document.querySelector(t.container):t.container instanceof HTMLElement&&(i=t.container),!i)throw new Error("Container not found");const[s,n]=this.initHtml();i.appendChild(s),this.container=s,this.scrollContainer=n.querySelector(".scroll"),this.wrapper=n.querySelector(".wrapper"),this.canvasWrapper=n.querySelector(".canvases"),this.progressWrapper=n.querySelector(".progress"),this.wrapper.addEventListener("click",(t=>{const e=this.wrapper.getBoundingClientRect(),i=(t.clientX-e.left)/e.width;this.emit("click",i)})),this.resizeObserver=new ResizeObserver((()=>{this.delay((()=>this.reRender()),100)})),this.resizeObserver.observe(this.scrollContainer)}initHtml(){const t=document.createElement("div"),e=t.attachShadow({mode:"open"});return e.innerHTML=`\n <style>\n :host {\n user-select: none;\n }\n :host .scroll {\n overflow-x: auto;\n overflow-y: hidden;\n width: 100%;\n position: relative;\n }\n :host .noScrollbar {\n scrollbar-color: transparent;\n scrollbar-width: none;\n }\n :host .noScrollbar::-webkit-scrollbar {\n display: none;\n -webkit-appearance: none;\n }\n :host .wrapper {\n position: relative;\n overflow: visible;\n z-index: 2;\n }\n :host .canvases {\n position: relative;\n height: ${this.options.height}px;\n }\n :host canvas {\n display: block;\n position: absolute;\n top: 0;\n image-rendering: pixelated;\n height: ${this.options.height}px;\n }\n :host .progress {\n pointer-events: none;\n position: absolute;\n z-index: 2;\n top: 0;\n left: 0;\n width: 0;\n height: 100%;\n overflow: hidden;\n box-sizing: border-box;\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 `,[t,e]}setOptions(t){this.options=t,this.reRender()}getContainer(){return this.scrollContainer}getWrapper(){return this.wrapper}destroy(){this.container.remove(),this.resizeObserver?.disconnect()}delay(t,e=10){return this.timeout&&clearTimeout(this.timeout),new Promise((i=>{this.timeout=setTimeout((()=>{i(t())}),e)}))}async renderPeaks(t,e,i,n){const r=null!=this.options.barWidth?this.options.barWidth*n:1,o=null!=this.options.barGap?this.options.barGap*n:this.options.barWidth?r/2:0,a=this.options.barRadius??0,h=t[0],l=h.length,d=Math.floor(e/(r+o))/l,c=i/2,p=1===t.length,u=p?h:t[1],m=p&&u.some((t=>t<0)),g=(t,i)=>{let s=0,p=0,g=0;const y=document.createElement("canvas");y.width=Math.round(e*(i-t)/l),y.height=this.options.height,y.style.width=`${Math.floor(y.width/n)}px`,y.style.height=`${this.options.height}px`,y.style.left=`${Math.floor(t*e/n/l)}px`,this.canvasWrapper.appendChild(y);const f=y.getContext("2d",{desynchronized:!0});f.beginPath(),f.fillStyle=this.options.waveColor??"",f.roundRect||(f.roundRect=f.fillRect);for(let e=t;e<i;e++){const i=Math.round((e-t)*d);if(i>s){const t=Math.round(p*c),e=Math.round(g*c);f.roundRect(s*(r+o),c-t,r,t+e||1,a),s=i,p=0,g=0}const n=m?h[e]:Math.abs(h[e]),l=m?u[e]:Math.abs(u[e]);n>p&&(p=n),(m?l<-g:l>g)&&(g=l<0?-l:l)}f.fill(),f.closePath();const v=y.cloneNode();this.progressWrapper.appendChild(v);const b=v.getContext("2d",{desynchronized:!0});y.width>0&&y.height>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:y,scrollWidth:f,clientWidth:v}=this.scrollContainer,b=l/f;let C=Math.min(s.MAX_CANVAS_WIDTH,v);C-=C%((r+o)/n);const w=Math.floor(Math.abs(y)*b),x=Math.ceil(w+C*b);g(w,x);const P=x-w;for(let t=x;t<l;t+=P)await this.delay((()=>{g(t,Math.min(l,t+P))}));for(let t=w-1;t>=0;t-=P)await this.delay((()=>{g(Math.max(0,t-P),t)}))}render(t,e){const i=window.devicePixelRatio||1,s=this.scrollContainer.clientWidth,n=Math.ceil(e*(this.options.minPxPerSec||0));this.isScrolling=n>s;const r=this.options.fillParent&&!this.isScrolling,o=(r?s:n)*i,{height:a}=this.options;this.wrapper.style.width=r?"100%":`${n}px`,this.scrollContainer.style.overflowX=this.isScrolling?"auto":"hidden",this.scrollContainer.classList.toggle("noScrollbar",!!this.options.hideScrollbar),this.progressWrapper.style.borderRightStyle="solid",this.progressWrapper.style.borderRightColor=`${this.options.cursorColor||this.options.progressColor}`,this.progressWrapper.style.borderRightWidth=`${this.options.cursorWidth}px`,this.canvasWrapper.style.height=`${this.options.height}px`,this.renderPeaks(t,o,a,i),this.channelData=t,this.duration=e}reRender(){if(!this.channelData||!this.duration)return;const t=this.progressWrapper.clientWidth;this.render(this.channelData,this.duration);const e=this.progressWrapper.clientWidth;this.scrollContainer.scrollLeft+=e-t}zoom(t){this.options.minPxPerSec=t,this.reRender()}renderProgress(t,e=!1){if(!isNaN(t)&&(this.progressWrapper.style.width=100*t+"%",this.isScrolling&&this.options.autoCenter)){const{clientWidth:i,scrollLeft:s,scrollWidth:n}=this.scrollContainer,r=n*t,o=i/2,a=o/20;(r>s+(e?o:i)||r<s)&&(r-(s+o)>=a&&r<s+i?this.scrollContainer.scrollLeft+=a:this.scrollContainer.scrollLeft=r-o)}}}s.MAX_CANVAS_WIDTH=4e3;const n=s,r=class extends i{constructor(t){super(),this.subscriptions=[],this.isExternalMedia=!1,this.hasPlayedOnce=!1,t.media?(this.media=t.media,this.isExternalMedia=!0):this.media=document.createElement("audio"),this.subscriptions.push(this.onceMediaEvent("play",(()=>{this.hasPlayedOnce=!0}))),t.autoplay&&(this.media.autoplay=!0),null!=t.playbackRate&&(this.media.playbackRate=t.playbackRate)}onMediaEvent(t,e,i){return this.media.addEventListener(t,e,i),()=>this.media.removeEventListener(t,e)}onceMediaEvent(t,e){return this.onMediaEvent(t,e,{once:!0})}loadUrl(t){this.media.src=t}destroy(){this.media.pause(),this.subscriptions.forEach((t=>t())),this.isExternalMedia||this.media.remove()}play(){return this.media.play()}pause(){this.media.pause()}isPlaying(){return this.media.currentTime>0&&!this.media.paused&&!this.media.ended}setTime(t){this.hasPlayedOnce||this.media.play()?.then?.((()=>{setTimeout((()=>this.media.pause()),10)})),this.media.currentTime=t}getDuration(){return this.media.duration}getCurrentTime(){return this.media.currentTime}getVolume(){return this.media.volume}setVolume(t){this.media.volume=t}getMuted(){return this.media.muted}setMuted(t){this.media.muted=t}getPlaybackRate(){return this.media.playbackRate}setPlaybackRate(t,e){null!=e&&(this.media.preservesPitch=e),this.media.playbackRate=t}getMediaElement(){return this.media}setSinkId(t){return this.media.setSinkId(t)}},o=class extends i{constructor(){super(...arguments),this.unsubscribe=()=>{}}start(){this.unsubscribe=this.on("tick",(()=>{requestAnimationFrame((()=>{this.emit("tick")}))})),this.emit("tick")}stop(){this.unsubscribe()}destroy(){this.unsubscribe()}},a={height:128,waveColor:"#999",progressColor:"#555",cursorWidth:1,minPxPerSec:0,fillParent:!0,interact:!0,autoCenter:!0};class h extends r{static create(t){return new h(t)}constructor(t){super({media:t.media,autoplay:t.autoplay,playbackRate:t.audioRate}),this.plugins=[],this.decodedData=null,this.canPlay=!1,this.options=Object.assign({},a,t),this.fetcher=new class{async load(t){return fetch(t).then((t=>t.arrayBuffer()))}},this.decoder=new class{initAudioContext(t){this.audioCtx=new AudioContext({latencyHint:"playback",sampleRate:t})}constructor(){this.audioCtx=null;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)}createBuffer(t,e){if("number"==typeof t[0]&&(t=[t]),t[0].some((t=>t>1||t<-1))){const e=Math.max(...t[0]);t=t.map((t=>t.map((t=>t/e))))}return{length:t[0].length,duration:e,numberOfChannels:t.length,sampleRate:t[0].length/e,getChannelData:e=>t?.[e],copyFromChannel:AudioBuffer.prototype.copyFromChannel,copyToChannel:AudioBuffer.prototype.copyToChannel}}destroy(){this.audioCtx?.close(),this.audioCtx=null}},this.timer=new o,this.renderer=new n({container:this.options.container},this.options),this.initPlayerEvents(),this.initRendererEvents(),this.initTimerEvents(),this.initReadyEvent(),this.initPlugins();const e=this.options.url||this.options.media?.src;e&&this.load(e,this.options.peaks,this.options.duration)}setOptions(t){this.options={...this.options,...t},this.renderer.setOptions(this.options)}initPlayerEvents(){this.subscriptions.push(this.onMediaEvent("timeupdate",(()=>{const t=this.getCurrentTime();this.renderer.renderProgress(t/this.getDuration(),this.isPlaying()),this.emit("timeupdate",t)})),this.onMediaEvent("play",(()=>{this.emit("play"),this.timer.start()})),this.onMediaEvent("pause",(()=>{this.emit("pause"),this.timer.stop(),this.getCurrentTime()>=this.getDuration()&&this.emit("finish")})),this.onMediaEvent("canplay",(()=>{this.canPlay=!0,this.emit("canplay",this.getDuration())})),this.onMediaEvent("seeking",(()=>{this.emit("seeking",this.getCurrentTime())})))}initRendererEvents(){this.subscriptions.push(this.renderer.on("click",(t=>{this.options.interact&&(this.seekTo(t),this.emit("interaction"))})))}initTimerEvents(){this.subscriptions.push(this.timer.on("tick",(()=>{const t=this.getCurrentTime();this.renderer.renderProgress(t/this.getDuration(),!0),this.emit("timeupdate",t),this.emit("audioprocess",t)})))}initReadyEvent(){const t=()=>{this.decodedData&&this.canPlay&&this.emit("ready",this.getDuration())};this.subscriptions.push(this.on("decode",t),this.on("canplay",t))}initPlugins(){this.options.plugins?.length&&this.options.plugins.forEach((t=>{this.registerPlugin(t)}))}registerPlugin(t){return t.init({wavesurfer:this,container:this.renderer.getContainer(),wrapper:this.renderer.getWrapper()}),this.plugins.push(t),t}getActivePlugins(){return this.plugins}async load(t,e,i){if(this.decodedData=null,this.canPlay=!1,this.loadUrl(t),this.emit("loading",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.onceMediaEvent("loadedmetadata",(()=>t(this.getDuration())))}))||0),this.decodedData=this.decoder.createBuffer(e,i);this.renderAudio(),this.emit("decode",this.getDuration()),this.emit("redraw")}renderAudio(){if(!this.decodedData)return;const t=[this.decodedData.getChannelData(0)];this.decodedData.numberOfChannels>1&&t.push(this.decodedData.getChannelData(1)),this.renderer.render(t,this.decodedData.duration)}zoom(t){if(!this.decodedData)throw new Error("No audio loaded");this.renderer.zoom(t),this.emit("zoom",t)}getDecodedData(){return this.decodedData}getDuration(){const t=super.getDuration();return t>0&&t<1/0?t:this.decodedData?.duration||0}toggleInteraction(t){this.options.interact=t}seekTo(t){const e=this.getDuration()*t;this.setTime(e)}playPause(){return this.isPlaying()?(this.pause(),Promise.resolve()):this.play()}stop(){this.pause(),this.setTime(0)}skip(t){this.setTime(this.getCurrentTime()+t)}empty(){this.load("",[[0]],.001)}destroy(){this.emit("destroy"),this.plugins.forEach((t=>t.destroy())),this.timer.destroy(),this.decoder.destroy(),this.renderer.destroy(),super.destroy()}}const l=h;return e.default})()));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wavesurfer.js",
3
- "version": "7.0.0-alpha.35",
3
+ "version": "7.0.0-alpha.37",
4
4
  "license": "BSD-3-Clause",
5
5
  "author": "katspaugh",
6
6
  "homepage": "https://wavesurfer-js.org",