{"version":3,"sources":["webpack://WaveSurfer/webpack/universalModuleDefinition","webpack://WaveSurfer/webpack/bootstrap","webpack://WaveSurfer/./src/util/index.js","webpack://WaveSurfer/./src/util/observer.js","webpack://WaveSurfer/./src/util/request-animation-frame.js","webpack://WaveSurfer/./src/webaudio.js","webpack://WaveSurfer/./src/wavesurfer.js","webpack://WaveSurfer/./src/util/ajax.js","webpack://WaveSurfer/./src/util/get-id.js","webpack://WaveSurfer/./src/util/max.js","webpack://WaveSurfer/./src/util/min.js","webpack://WaveSurfer/./src/util/extend.js","webpack://WaveSurfer/./src/util/style.js","webpack://WaveSurfer/./src/util/frame.js","webpack://WaveSurfer/./node_modules/debounce/index.js","webpack://WaveSurfer/./src/util/prevent-click.js","webpack://WaveSurfer/./src/drawer.multicanvas.js","webpack://WaveSurfer/./src/drawer.js","webpack://WaveSurfer/./src/mediaelement.js","webpack://WaveSurfer/./src/peakcache.js"],"names":["root","factory","exports","module","define","amd","window","installedModules","__webpack_require__","moduleId","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","_ajax","_interopRequireDefault","_getId","_max","_min","_observer","_extend","_style","_requestAnimationFrame","_frame","_debounce","_preventClick","Observer","_classCallCheck","this","handlers","event","fn","_this","push","callback","un","e","length","splice","handler","_this2","on","_len","arguments","args","Array","_key","apply","setTimeout","_len2","_key2","forEach","requestAnimationFrame","webkitRequestAnimationFrame","mozRequestAnimationFrame","oRequestAnimationFrame","msRequestAnimationFrame","element","util","_interopRequireWildcard","PLAYING","PAUSED","FINISHED","WebAudio","params","_this$stateBehaviors","_this$states","_possibleConstructorReturn","_getPrototypeOf","audioContext","offlineAudioContext","stateBehaviors","_defineProperty","init","addOnAudioProcess","getPlayedPercents","duration","getDuration","getCurrentTime","startPosition","getPlayedTime","removeOnAudioProcess","fireEvent","ac","getAudioContext","lastPlay","currentTime","scheduledPause","states","analyser","buffer","filters","gainNode","mergedPeaks","offlineAc","peaks","playbackRate","scriptNode","source","splitPeaks","state","explicitDuration","AudioContext","webkitAudioContext","WaveSurferAudioContext","sampleRate","WaveSurferOfflineAudioContext","OfflineAudioContext","webkitOfflineAudioContext","createVolumeNode","createScriptNode","createAnalyserNode","setState","setPlaybackRate","audioRate","setLength","filter","disconnect","connect","setFilters","disconnectFilters","reduce","prev","curr","audioScriptProcessor","createScriptProcessor","scriptBufferSize","createJavaScriptNode","destination","onaudioprocess","time","pause","createAnalyser","createGain","createGainNode","deviceId","audio","Audio","setSinkId","Promise","reject","Error","autoplay","dest","createMediaStreamDestination","srcObject","stream","gain","setValueAtTime","arraybuffer","errback","getOfflineAudioContext","decodeAudioData","data","channels","numberOfChannels","first","last","splitChannels","newBuffer","createBuffer","sampleSize","sampleStep","chan","getChannelData","start","end","min","max","j","isPaused","unAll","disconnectSource","closeAudioContext","close","createSource","createBufferSource","noteGrainOn","stop","noteOff","adjustedTime","seekTo","resume","play","_drawer","_webaudio","_mediaelement","_peakcache","WaveSurfer","defaultParams","autoCenter","backend","barHeight","barGap","container","cursorColor","cursorWidth","dragSelection","fillParent","forceDecode","height","hideScrollbar","interact","loopSelection","maxCanvasWidth","mediaContainer","mediaControls","mediaType","minPxPerSec","normalize","partialRender","pixelRatio","devicePixelRatio","screen","deviceXDPI","logicalXDPI","plugins","progressColor","removeMediaElementOnDestroy","renderer","MultiCanvas","responsive","scrollParent","skipLength","waveColor","xhr","backends","MediaElement","extend","document","querySelector","savedVolume","isMuted","tmpEvents","currentAjax","drawer","peakCache","Drawer","Backend","initialisedPluginList","isDestroyed","isReady","prevWidth","_onResize","debounce","wrapper","clientWidth","_assertThisInitialized","registerPlugins","createDrawer","createBackend","createPeakCache","plugin","addPlugin","deferInit","initPlugin","_this3","instance","concat","staticProps","keys","pluginStaticProp","Instance","getOwnPropertyNames","destroyPlugin","destroy","_this4","_this5","addEventListener","drawBuffer","progress","_this6","supportsWebAudio","PeakCache","seconds","_this7","skip","offset","position","Math","seekAndCenter","recenter","_this8","isFinite","console","error","paused","oldScrollParent","newVolume","setVolume","getVolume","rate","getPlaybackRate","setMute","mute","color","updateCursor","setHeight","nominalWidth","round","parentWidth","getWidth","width","getScrollX","newRanges","addRangeToPeakCache","getPeaks","drawPeaks","pxPerSec","_this9","decodeArrayBuffer","loadDecodedBuffer","load","blob","_this10","reader","FileReader","onProgress","loadArrayBuffer","target","result","readAsArrayBuffer","empty","url","preload","preloadIgnoreReasons","Preload is not 'auto', 'none' or 'metadata'","indexOf","Peaks are not provided","Backend is not of type MediaElement","Url is not of type string","activeReasons","reason","warn","join","loadBuffer","loadMediaElement","_this11","action","once","getArrayBuffer","setPeaks","urlOrElt","_this12","elt","loadElt","src","err","_this13","_this14","ajax","responseType","statusText","percentComplete","lengthComputable","loaded","total","accuracy","noWindow","arr","map","val","json","JSON","stringify","open","encodeURIComponent","format","quality","getImage","abort","cancelAjax","clearTmpEvents","setWidth","destroyAllPlugins","removeEventListener","VERSION","__VERSION__","options","XMLHttpRequest","fired100","method","requestHeaders","header","setRequestHeader","withCredentials","status","response","send","random","toString","substring","values","largest","Infinity","smallest","Number","sources","el","styles","prop","style","func","default","wait","immediate","timeout","context","timestamp","later","Date","now","debounced","callNow","clear","clearTimeout","flush","preventClickHandler","stopPropagation","body","maxCanvasElementWidth","hasProgressCanvas","halfPixel","canvases","progressWave","createWrapper","createElements","appendChild","createElement","zIndex","left","top","bottom","overflow","display","boxSizing","borderRightStyle","pointerEvents","addCanvas","borderRightWidth","borderRightColor","totalWidth","requiredCanvases","ceil","removeCanvas","entry","canvasWidth","updateDimensions","clearWaveForEntry","leftOffset","wave","waveCtx","getContext","progressCtx","lastEntry","pop","parentElement","removeChild","elementWidth","canvas","offsetLeft","clearRect","channelIndex","prepareDraw","_ref","absmax","hasMinVals","offsetY","halfH","undefined","peakIndexScale","bar","barWidth","step","scale","peak","floor","h","fillRect","_ref2","reflectedPeaks","len","drawLine","setFillStyles","drawLineToContext","ctx","canvasStart","canvasEnd","beginPath","moveTo","lineTo","closePath","fill","x","y","startCanvas","endCanvas","intersection","x1","y1","x2","y2","fillRectToContext","frame","channelPeaks","some","fillStyle","type","images","toDataURL","lastPos","userSelect","webkitUserSelect","overflowX","overflowY","setupWrapperEvents","noPrevent","preventDefault","clientX","targetTouches","bbox","getBoundingClientRect","scrollLeft","scrollWidth","scrollbarHeight","offsetHeight","clientHeight","clientY","handleEvent","clearWave","drawBars","drawWave","percent","recenterOnPosition","half","maxScroll","updateSize","minPxDelta","pos","newPos","updateProgress","parentNode","media","volume","toLowerCase","elementPosition","onPlayEnd","createTimer","onAudioProcess","controls","prevMedia","_load","seekable","clearPlayEnd","promise","setPlayEnd","_onPlayEnd","_get","clearPeakCache","peakCacheRanges","peakCacheLength","uncachedRanges","item","sort","a","b","uncachedRangePairs","peakCacheRangePairs"],"mappings":"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","file":"wavesurfer.min.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"WaveSurfer\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"WaveSurfer\"] = factory();\n\telse\n\t\troot[\"WaveSurfer\"] = factory();\n})(window, function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 4);\n","export { default as ajax } from './ajax';\nexport { default as getId } from './get-id';\nexport { default as max } from './max';\nexport { default as min } from './min';\nexport { default as Observer } from './observer';\nexport { default as extend } from './extend';\nexport { default as style } from './style';\nexport { default as requestAnimationFrame } from './request-animation-frame';\nexport { default as frame } from './frame';\nexport { default as debounce } from 'debounce';\nexport { default as preventClick } from './prevent-click';\n","/**\n * @typedef {Object} ListenerDescriptor\n * @property {string} name The name of the event\n * @property {function} callback The callback\n * @property {function} un The function to call to remove the listener\n */\n\n/**\n * Observer class\n */\nexport default class Observer {\n /**\n * Instantiate Observer\n */\n constructor() {\n /**\n * @private\n * @todo Initialise the handlers here already and remove the conditional\n * assignment in `on()`\n */\n this.handlers = null;\n }\n /**\n * Attach a handler function for an event.\n *\n * @param {string} event Name of the event to listen to\n * @param {function} fn The callback to trigger when the event is fired\n * @return {ListenerDescriptor}\n */\n on(event, fn) {\n if (!this.handlers) {\n this.handlers = {};\n }\n\n let handlers = this.handlers[event];\n if (!handlers) {\n handlers = this.handlers[event] = [];\n }\n handlers.push(fn);\n\n // Return an event descriptor\n return {\n name: event,\n callback: fn,\n un: (e, fn) => this.un(e, fn)\n };\n }\n\n /**\n * Remove an event handler.\n *\n * @param {string} event Name of the event the listener that should be\n * removed listens to\n * @param {function} fn The callback that should be removed\n */\n un(event, fn) {\n if (!this.handlers) {\n return;\n }\n\n const handlers = this.handlers[event];\n let i;\n if (handlers) {\n if (fn) {\n for (i = handlers.length - 1; i >= 0; i--) {\n if (handlers[i] == fn) {\n handlers.splice(i, 1);\n }\n }\n } else {\n handlers.length = 0;\n }\n }\n }\n\n /**\n * Remove all event handlers.\n */\n unAll() {\n this.handlers = null;\n }\n\n /**\n * Attach a handler to an event. The handler is executed at most once per\n * event type.\n *\n * @param {string} event The event to listen to\n * @param {function} handler The callback that is only to be called once\n * @return {ListenerDescriptor}\n */\n once(event, handler) {\n const fn = (...args) => {\n /* eslint-disable no-invalid-this */\n handler.apply(this, args);\n /* eslint-enable no-invalid-this */\n setTimeout(() => {\n this.un(event, fn);\n }, 0);\n };\n return this.on(event, fn);\n }\n\n /**\n * Manually fire an event\n *\n * @param {string} event The event to fire manually\n * @param {...any} args The arguments with which to call the listeners\n */\n fireEvent(event, ...args) {\n if (!this.handlers) {\n return;\n }\n const handlers = this.handlers[event];\n handlers &&\n handlers.forEach(fn => {\n fn(...args);\n });\n }\n}\n","/**\n * Returns the requestAnimationFrame function for the browser, or a shim with\n * setTimeout if none is found\n *\n * @return {function}\n */\nexport default (\n window.requestAnimationFrame ||\n window.webkitRequestAnimationFrame ||\n window.mozRequestAnimationFrame ||\n window.oRequestAnimationFrame ||\n window.msRequestAnimationFrame ||\n ((callback, element) => setTimeout(callback, 1000 / 60))\n).bind(window);\n","import * as util from './util';\n\n// using constants to prevent someone writing the string wrong\nconst PLAYING = 'playing';\nconst PAUSED = 'paused';\nconst FINISHED = 'finished';\n\n/**\n * WebAudio backend\n *\n * @extends {Observer}\n */\nexport default class WebAudio extends util.Observer {\n /** @private */\n static scriptBufferSize = 256;\n /** @private */\n audioContext = null;\n /** @private */\n offlineAudioContext = null;\n /** @private */\n stateBehaviors = {\n [PLAYING]: {\n init() {\n this.addOnAudioProcess();\n },\n getPlayedPercents() {\n const duration = this.getDuration();\n return this.getCurrentTime() / duration || 0;\n },\n getCurrentTime() {\n return this.startPosition + this.getPlayedTime();\n }\n },\n [PAUSED]: {\n init() {\n this.removeOnAudioProcess();\n },\n getPlayedPercents() {\n const duration = this.getDuration();\n return this.getCurrentTime() / duration || 0;\n },\n getCurrentTime() {\n return this.startPosition;\n }\n },\n [FINISHED]: {\n init() {\n this.removeOnAudioProcess();\n this.fireEvent('finish');\n },\n getPlayedPercents() {\n return 1;\n },\n getCurrentTime() {\n return this.getDuration();\n }\n }\n };\n\n /**\n * Does the browser support this backend\n *\n * @return {boolean}\n */\n supportsWebAudio() {\n return !!(window.AudioContext || window.webkitAudioContext);\n }\n\n /**\n * Get the audio context used by this backend or create one\n *\n * @return {AudioContext}\n */\n getAudioContext() {\n if (!window.WaveSurferAudioContext) {\n window.WaveSurferAudioContext = new (window.AudioContext ||\n window.webkitAudioContext)();\n }\n return window.WaveSurferAudioContext;\n }\n\n /**\n * Get the offline audio context used by this backend or create one\n *\n * @param {number} sampleRate\n * @return {OfflineAudioContext}\n */\n getOfflineAudioContext(sampleRate) {\n if (!window.WaveSurferOfflineAudioContext) {\n window.WaveSurferOfflineAudioContext = new (window.OfflineAudioContext ||\n window.webkitOfflineAudioContext)(1, 2, sampleRate);\n }\n return window.WaveSurferOfflineAudioContext;\n }\n\n /**\n * Construct the backend\n *\n * @param {WavesurferParams} params\n */\n constructor(params) {\n super();\n /** @private */\n this.params = params;\n /** @private */\n this.ac = params.audioContext || this.getAudioContext();\n /**@private */\n this.lastPlay = this.ac.currentTime;\n /** @private */\n this.startPosition = 0;\n /** @private */\n this.scheduledPause = null;\n /** @private */\n this.states = {\n [PLAYING]: Object.create(this.stateBehaviors[PLAYING]),\n [PAUSED]: Object.create(this.stateBehaviors[PAUSED]),\n [FINISHED]: Object.create(this.stateBehaviors[FINISHED])\n };\n /** @private */\n this.analyser = null;\n /** @private */\n this.buffer = null;\n /** @private */\n this.filters = [];\n /** @private */\n this.gainNode = null;\n /** @private */\n this.mergedPeaks = null;\n /** @private */\n this.offlineAc = null;\n /** @private */\n this.peaks = null;\n /** @private */\n this.playbackRate = 1;\n /** @private */\n this.analyser = null;\n /** @private */\n this.scriptNode = null;\n /** @private */\n this.source = null;\n /** @private */\n this.splitPeaks = [];\n /** @private */\n this.state = null;\n /** @private */\n this.explicitDuration = null;\n }\n\n /**\n * Initialise the backend, called in `wavesurfer.createBackend()`\n */\n init() {\n this.createVolumeNode();\n this.createScriptNode();\n this.createAnalyserNode();\n\n this.setState(PAUSED);\n this.setPlaybackRate(this.params.audioRate);\n this.setLength(0);\n }\n\n /** @private */\n disconnectFilters() {\n if (this.filters) {\n this.filters.forEach(filter => {\n filter && filter.disconnect();\n });\n this.filters = null;\n // Reconnect direct path\n this.analyser.connect(this.gainNode);\n }\n }\n\n /** @private */\n setState(state) {\n if (this.state !== this.states[state]) {\n this.state = this.states[state];\n this.state.init.call(this);\n }\n }\n\n /**\n * Unpacked `setFilters()`\n *\n * @param {...AudioNode} filters\n */\n setFilter(...filters) {\n this.setFilters(filters);\n }\n\n /**\n * Insert custom Web Audio nodes into the graph\n *\n * @param {AudioNode[]} filters Packed filters array\n * @example\n * const lowpass = wavesurfer.backend.ac.createBiquadFilter();\n * wavesurfer.backend.setFilter(lowpass);\n */\n setFilters(filters) {\n // Remove existing filters\n this.disconnectFilters();\n\n // Insert filters if filter array not empty\n if (filters && filters.length) {\n this.filters = filters;\n\n // Disconnect direct path before inserting filters\n this.analyser.disconnect();\n\n // Connect each filter in turn\n filters\n .reduce((prev, curr) => {\n prev.connect(curr);\n return curr;\n }, this.analyser)\n .connect(this.gainNode);\n }\n }\n\n /** @private */\n createScriptNode() {\n if (this.params.audioScriptProcessor) {\n this.scriptNode = this.params.audioScriptProcessor;\n } else {\n if (this.ac.createScriptProcessor) {\n this.scriptNode = this.ac.createScriptProcessor(\n WebAudio.scriptBufferSize\n );\n } else {\n this.scriptNode = this.ac.createJavaScriptNode(\n WebAudio.scriptBufferSize\n );\n }\n }\n this.scriptNode.connect(this.ac.destination);\n }\n\n /** @private */\n addOnAudioProcess() {\n this.scriptNode.onaudioprocess = () => {\n const time = this.getCurrentTime();\n\n if (time >= this.getDuration()) {\n this.setState(FINISHED);\n this.fireEvent('pause');\n } else if (time >= this.scheduledPause) {\n this.pause();\n } else if (this.state === this.states[PLAYING]) {\n this.fireEvent('audioprocess', time);\n }\n };\n }\n\n /** @private */\n removeOnAudioProcess() {\n this.scriptNode.onaudioprocess = null;\n }\n\n /** @private */\n createAnalyserNode() {\n this.analyser = this.ac.createAnalyser();\n this.analyser.connect(this.gainNode);\n }\n\n /**\n * Create the gain node needed to control the playback volume.\n *\n * @private\n */\n createVolumeNode() {\n // Create gain node using the AudioContext\n if (this.ac.createGain) {\n this.gainNode = this.ac.createGain();\n } else {\n this.gainNode = this.ac.createGainNode();\n }\n // Add the gain node to the graph\n this.gainNode.connect(this.ac.destination);\n }\n\n /**\n * Set the sink id for the media player\n *\n * @param {string} deviceId String value representing audio device id.\n */\n setSinkId(deviceId) {\n if (deviceId) {\n /**\n * The webaudio API doesn't currently support setting the device\n * output. Here we create an HTMLAudioElement, connect the\n * webaudio stream to that element and setSinkId there.\n */\n let audio = new window.Audio();\n if (!audio.setSinkId) {\n return Promise.reject(\n new Error('setSinkId is not supported in your browser')\n );\n }\n audio.autoplay = true;\n var dest = this.ac.createMediaStreamDestination();\n this.gainNode.disconnect();\n this.gainNode.connect(dest);\n audio.srcObject = dest.stream;\n\n return audio.setSinkId(deviceId);\n } else {\n return Promise.reject(new Error('Invalid deviceId: ' + deviceId));\n }\n }\n\n /**\n * Set the audio volume\n *\n * @param {number} value A floating point value between 0 and 1.\n */\n setVolume(value) {\n this.gainNode.gain.setValueAtTime(value, this.ac.currentTime);\n }\n\n /**\n * Get the current volume\n *\n * @return {number} value A floating point value between 0 and 1.\n */\n getVolume() {\n return this.gainNode.gain.value;\n }\n\n /** @private */\n decodeArrayBuffer(arraybuffer, callback, errback) {\n if (!this.offlineAc) {\n this.offlineAc = this.getOfflineAudioContext(\n this.ac && this.ac.sampleRate ? this.ac.sampleRate : 44100\n );\n }\n this.offlineAc.decodeAudioData(\n arraybuffer,\n data => callback(data),\n errback\n );\n }\n\n /**\n * Set pre-decoded peaks\n *\n * @param {number[]|number[][]} peaks\n * @param {?number} duration\n */\n setPeaks(peaks, duration) {\n this.explicitDuration = duration;\n this.peaks = peaks;\n }\n\n /**\n * Set the rendered length (different from the length of the audio).\n *\n * @param {number} length\n */\n setLength(length) {\n // No resize, we can preserve the cached peaks.\n if (this.mergedPeaks && length == 2 * this.mergedPeaks.length - 1 + 2) {\n return;\n }\n\n this.splitPeaks = [];\n this.mergedPeaks = [];\n // Set the last element of the sparse array so the peak arrays are\n // appropriately sized for other calculations.\n const channels = this.buffer ? this.buffer.numberOfChannels : 1;\n let c;\n for (c = 0; c < channels; c++) {\n this.splitPeaks[c] = [];\n this.splitPeaks[c][2 * (length - 1)] = 0;\n this.splitPeaks[c][2 * (length - 1) + 1] = 0;\n }\n this.mergedPeaks[2 * (length - 1)] = 0;\n this.mergedPeaks[2 * (length - 1) + 1] = 0;\n }\n\n /**\n * Compute the max and min value of the waveform when broken into subranges.\n *\n * @param {number} length How many subranges to break the waveform into.\n * @param {number} first First sample in the required range.\n * @param {number} last Last sample in the required range.\n * @return {number[]|number[][]} Array of 2* peaks or array of arrays of\n * peaks consisting of (max, min) values for each subrange.\n */\n getPeaks(length, first, last) {\n if (this.peaks) {\n return this.peaks;\n }\n\n first = first || 0;\n last = last || length - 1;\n\n this.setLength(length);\n\n if (!this.buffer) {\n return this.params.splitChannels\n ? this.splitPeaks\n : this.mergedPeaks;\n }\n\n /**\n * The following snippet fixes a buffering data issue on the Safari\n * browser which returned undefined It creates the missing buffer based\n * on 1 channel, 4096 samples and the sampleRate from the current\n * webaudio context 4096 samples seemed to be the best fit for rendering\n * will review this code once a stable version of Safari TP is out\n */\n if (!this.buffer.length) {\n const newBuffer = this.createBuffer(1, 4096, this.sampleRate);\n this.buffer = newBuffer.buffer;\n }\n\n const sampleSize = this.buffer.length / length;\n const sampleStep = ~~(sampleSize / 10) || 1;\n const channels = this.buffer.numberOfChannels;\n let c;\n\n for (c = 0; c < channels; c++) {\n const peaks = this.splitPeaks[c];\n const chan = this.buffer.getChannelData(c);\n let i;\n\n for (i = first; i <= last; i++) {\n const start = ~~(i * sampleSize);\n const end = ~~(start + sampleSize);\n let min = 0;\n let max = 0;\n let j;\n\n for (j = start; j < end; j += sampleStep) {\n const value = chan[j];\n\n if (value > max) {\n max = value;\n }\n\n if (value < min) {\n min = value;\n }\n }\n\n peaks[2 * i] = max;\n peaks[2 * i + 1] = min;\n\n if (c == 0 || max > this.mergedPeaks[2 * i]) {\n this.mergedPeaks[2 * i] = max;\n }\n\n if (c == 0 || min < this.mergedPeaks[2 * i + 1]) {\n this.mergedPeaks[2 * i + 1] = min;\n }\n }\n }\n\n return this.params.splitChannels ? this.splitPeaks : this.mergedPeaks;\n }\n\n /**\n * Get the position from 0 to 1\n *\n * @return {number}\n */\n getPlayedPercents() {\n return this.state.getPlayedPercents.call(this);\n }\n\n /** @private */\n disconnectSource() {\n if (this.source) {\n this.source.disconnect();\n }\n }\n\n /**\n * This is called when wavesurfer is destroyed\n */\n destroy() {\n if (!this.isPaused()) {\n this.pause();\n }\n this.unAll();\n this.buffer = null;\n this.disconnectFilters();\n this.disconnectSource();\n this.gainNode.disconnect();\n this.scriptNode.disconnect();\n this.analyser.disconnect();\n\n // close the audioContext if closeAudioContext option is set to true\n if (this.params.closeAudioContext) {\n // check if browser supports AudioContext.close()\n if (\n typeof this.ac.close === 'function' &&\n this.ac.state != 'closed'\n ) {\n this.ac.close();\n }\n // clear the reference to the audiocontext\n this.ac = null;\n // clear the actual audiocontext, either passed as param or the\n // global singleton\n if (!this.params.audioContext) {\n window.WaveSurferAudioContext = null;\n } else {\n this.params.audioContext = null;\n }\n // clear the offlineAudioContext\n window.WaveSurferOfflineAudioContext = null;\n }\n }\n\n /**\n * Loaded a decoded audio buffer\n *\n * @param {Object} buffer\n */\n load(buffer) {\n this.startPosition = 0;\n this.lastPlay = this.ac.currentTime;\n this.buffer = buffer;\n this.createSource();\n }\n\n /** @private */\n createSource() {\n this.disconnectSource();\n this.source = this.ac.createBufferSource();\n\n // adjust for old browsers\n this.source.start = this.source.start || this.source.noteGrainOn;\n this.source.stop = this.source.stop || this.source.noteOff;\n\n this.source.playbackRate.setValueAtTime(\n this.playbackRate,\n this.ac.currentTime\n );\n this.source.buffer = this.buffer;\n this.source.connect(this.analyser);\n }\n\n /**\n * Used by `wavesurfer.isPlaying()` and `wavesurfer.playPause()`\n *\n * @return {boolean}\n */\n isPaused() {\n return this.state !== this.states[PLAYING];\n }\n\n /**\n * Used by `wavesurfer.getDuration()`\n *\n * @return {number}\n */\n getDuration() {\n if (!this.buffer) {\n if (this.explicitDuration) {\n return this.explicitDuration;\n }\n return 0;\n }\n return this.buffer.duration;\n }\n\n /**\n * Used by `wavesurfer.seekTo()`\n *\n * @param {number} start Position to start at in seconds\n * @param {number} end Position to end at in seconds\n * @return {{start: number, end: number}}\n */\n seekTo(start, end) {\n if (!this.buffer) {\n return;\n }\n\n this.scheduledPause = null;\n\n if (start == null) {\n start = this.getCurrentTime();\n if (start >= this.getDuration()) {\n start = 0;\n }\n }\n if (end == null) {\n end = this.getDuration();\n }\n\n this.startPosition = start;\n this.lastPlay = this.ac.currentTime;\n\n if (this.state === this.states[FINISHED]) {\n this.setState(PAUSED);\n }\n\n return {\n start: start,\n end: end\n };\n }\n\n /**\n * Get the playback position in seconds\n *\n * @return {number}\n */\n getPlayedTime() {\n return (this.ac.currentTime - this.lastPlay) * this.playbackRate;\n }\n\n /**\n * Plays the loaded audio region.\n *\n * @param {number} start Start offset in seconds, relative to the beginning\n * of a clip.\n * @param {number} end When to stop relative to the beginning of a clip.\n */\n play(start, end) {\n if (!this.buffer) {\n return;\n }\n\n // need to re-create source on each playback\n this.createSource();\n\n const adjustedTime = this.seekTo(start, end);\n\n start = adjustedTime.start;\n end = adjustedTime.end;\n\n this.scheduledPause = end;\n\n this.source.start(0, start, end - start);\n\n if (this.ac.state == 'suspended') {\n this.ac.resume && this.ac.resume();\n }\n\n this.setState(PLAYING);\n\n this.fireEvent('play');\n }\n\n /**\n * Pauses the loaded audio.\n */\n pause() {\n this.scheduledPause = null;\n\n this.startPosition += this.getPlayedTime();\n this.source && this.source.stop(0);\n\n this.setState(PAUSED);\n\n this.fireEvent('pause');\n }\n\n /**\n * Returns the current time in seconds relative to the audio-clip's\n * duration.\n *\n * @return {number}\n */\n getCurrentTime() {\n return this.state.getCurrentTime.call(this);\n }\n\n /**\n * Returns the current playback rate. (0=no playback, 1=normal playback)\n *\n * @return {number}\n */\n getPlaybackRate() {\n return this.playbackRate;\n }\n\n /**\n * Set the audio source playback rate.\n *\n * @param {number} value\n */\n setPlaybackRate(value) {\n value = value || 1;\n if (this.isPaused()) {\n this.playbackRate = value;\n } else {\n this.pause();\n this.playbackRate = value;\n this.play();\n }\n }\n}\n","import * as util from './util';\nimport MultiCanvas from './drawer.multicanvas';\nimport WebAudio from './webaudio';\nimport MediaElement from './mediaelement';\nimport PeakCache from './peakcache';\n\n/*\n * This work is licensed under a BSD-3-Clause License.\n */\n\n/** @external {HTMLElement} https://developer.mozilla.org/en/docs/Web/API/HTMLElement */\n/** @external {OfflineAudioContext} https://developer.mozilla.org/en-US/docs/Web/API/OfflineAudioContext */\n/** @external {File} https://developer.mozilla.org/en-US/docs/Web/API/File */\n/** @external {Blob} https://developer.mozilla.org/en-US/docs/Web/API/Blob */\n/** @external {CanvasRenderingContext2D} https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D */\n/** @external {MediaStreamConstraints} https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamConstraints */\n/** @external {AudioNode} https://developer.mozilla.org/de/docs/Web/API/AudioNode */\n\n/**\n * @typedef {Object} WavesurferParams\n * @property {AudioContext} audioContext=null Use your own previously\n * initialized AudioContext or leave blank.\n * @property {number} audioRate=1 Speed at which to play audio. Lower number is\n * slower.\n * @property {ScriptProcessorNode} audioScriptProcessor=null Use your own previously\n * initialized ScriptProcessorNode or leave blank.\n * @property {boolean} autoCenter=true If a scrollbar is present, center the\n * waveform around the progress\n * @property {string} backend='WebAudio' `'WebAudio'|'MediaElement'` In most cases\n * you don't have to set this manually. MediaElement is a fallback for\n * unsupported browsers.\n * @property {number} barHeight=1 The height of the wave\n * @property {number} barGap=null The optional spacing between bars of the wave,\n * if not provided will be calculated in legacy format.\n * @property {boolean} closeAudioContext=false Close and nullify all audio\n * contexts when the destroy method is called.\n * @property {!string|HTMLElement} container CSS selector or HTML element where\n * the waveform should be drawn. This is the only required parameter.\n * @property {string} cursorColor='#333' The fill color of the cursor indicating\n * the playhead position.\n * @property {number} cursorWidth=1 Measured in pixels.\n * @property {boolean} fillParent=true Whether to fill the entire container or\n * draw only according to `minPxPerSec`.\n * @property {boolean} forceDecode=false Force decoding of audio using web audio\n * when zooming to get a more detailed waveform.\n * @property {number} height=128 The height of the waveform. Measured in\n * pixels.\n * @property {boolean} hideScrollbar=false Whether to hide the horizontal\n * scrollbar when one would normally be shown.\n * @property {boolean} interact=true Whether the mouse interaction will be\n * enabled at initialization. You can switch this parameter at any time later\n * on.\n * @property {boolean} loopSelection=true (Use with regions plugin) Enable\n * looping of selected regions\n * @property {number} maxCanvasWidth=4000 Maximum width of a single canvas in\n * pixels, excluding a small overlap (2 * `pixelRatio`, rounded up to the next\n * even integer). If the waveform is longer than this value, additional canvases\n * will be used to render the waveform, which is useful for very large waveforms\n * that may be too wide for browsers to draw on a single canvas.\n * @property {boolean} mediaControls=false (Use with backend `MediaElement`)\n * this enables the native controls for the media element\n * @property {string} mediaType='audio' (Use with backend `MediaElement`)\n * `'audio'|'video'`\n * @property {number} minPxPerSec=20 Minimum number of pixels per second of\n * audio.\n * @property {boolean} normalize=false If true, normalize by the maximum peak\n * instead of 1.0.\n * @property {boolean} partialRender=false Use the PeakCache to improve\n * rendering speed of large waveforms\n * @property {number} pixelRatio=window.devicePixelRatio The pixel ratio used to\n * calculate display\n * @property {PluginDefinition[]} plugins=[] An array of plugin definitions to\n * register during instantiation, they will be directly initialised unless they\n * are added with the `deferInit` property set to true.\n * @property {string} progressColor='#555' The fill color of the part of the\n * waveform behind the cursor.\n * @property {boolean} removeMediaElementOnDestroy=true Set to false to keep the\n * media element in the DOM when the player is destroyed. This is useful when\n * reusing an existing media element via the `loadMediaElement` method.\n * @property {Object} renderer=MultiCanvas Can be used to inject a custom\n * renderer.\n * @property {boolean|number} responsive=false If set to `true` resize the\n * waveform, when the window is resized. This is debounced with a `100ms`\n * timeout by default. If this parameter is a number it represents that timeout.\n * @property {boolean} scrollParent=false Whether to scroll the container with a\n * lengthy waveform. Otherwise the waveform is shrunk to the container width\n * (see fillParent).\n * @property {number} skipLength=2 Number of seconds to skip with the\n * skipForward() and skipBackward() methods.\n * @property {boolean} splitChannels=false Render with separate waveforms for\n * the channels of the audio\n * @property {string} waveColor='#999' The fill color of the waveform after the\n * cursor.\n * @property {object} xhr={} XHR options.\n */\n\n/**\n * @typedef {Object} PluginDefinition\n * @desc The Object used to describe a plugin\n * @example wavesurfer.addPlugin(pluginDefinition);\n * @property {string} name The name of the plugin, the plugin instance will be\n * added as a property to the wavesurfer instance under this name\n * @property {?Object} staticProps The properties that should be added to the\n * wavesurfer instance as static properties\n * @property {?boolean} deferInit Don't initialise plugin\n * automatically\n * @property {Object} params={} The plugin parameters, they are the first parameter\n * passed to the plugin class constructor function\n * @property {PluginClass} instance The plugin instance factory, is called with\n * the dependency specified in extends. Returns the plugin class.\n */\n\n/**\n * @interface PluginClass\n *\n * @desc This is the interface which is implemented by all plugin classes. Note\n * that this only turns into an observer after being passed through\n * `wavesurfer.addPlugin`.\n *\n * @extends {Observer}\n */\nclass PluginClass {\n /**\n * Plugin definition factory\n *\n * This function must be used to create a plugin definition which can be\n * used by wavesurfer to correctly instantiate the plugin.\n *\n * @param {Object} params={} The plugin params (specific to the plugin)\n * @return {PluginDefinition} an object representing the plugin\n */\n create(params) {}\n /**\n * Construct the plugin\n *\n * @param {Object} params={} The plugin params (specific to the plugin)\n * @param {Object} ws The wavesurfer instance\n */\n constructor(params, ws) {}\n /**\n * Initialise the plugin\n *\n * Start doing something. This is called by\n * `wavesurfer.initPlugin(pluginName)`\n */\n init() {}\n /**\n * Destroy the plugin instance\n *\n * Stop doing something. This is called by\n * `wavesurfer.destroyPlugin(pluginName)`\n */\n destroy() {}\n}\n\n/**\n * WaveSurfer core library class\n *\n * @extends {Observer}\n * @example\n * const params = {\n * container: '#waveform',\n * waveColor: 'violet',\n * progressColor: 'purple'\n * };\n *\n * // initialise like this\n * const wavesurfer = WaveSurfer.create(params);\n *\n * // or like this ...\n * const wavesurfer = new WaveSurfer(params);\n * wavesurfer.init();\n *\n * // load audio file\n * wavesurfer.load('example/media/demo.wav');\n */\nexport default class WaveSurfer extends util.Observer {\n /** @private */\n defaultParams = {\n audioContext: null,\n audioScriptProcessor: null,\n audioRate: 1,\n autoCenter: true,\n backend: 'WebAudio',\n barHeight: 1,\n barGap: null,\n container: null,\n cursorColor: '#333',\n cursorWidth: 1,\n dragSelection: true,\n fillParent: true,\n forceDecode: false,\n height: 128,\n hideScrollbar: false,\n interact: true,\n loopSelection: true,\n maxCanvasWidth: 4000,\n mediaContainer: null,\n mediaControls: false,\n mediaType: 'audio',\n minPxPerSec: 20,\n normalize: false,\n partialRender: false,\n pixelRatio:\n window.devicePixelRatio || screen.deviceXDPI / screen.logicalXDPI,\n plugins: [],\n progressColor: '#555',\n removeMediaElementOnDestroy: true,\n renderer: MultiCanvas,\n responsive: false,\n scrollParent: false,\n skipLength: 2,\n splitChannels: false,\n waveColor: '#999',\n xhr: {}\n };\n\n /** @private */\n backends = {\n MediaElement,\n WebAudio\n };\n\n /**\n * Instantiate this class, call its `init` function and returns it\n *\n * @param {WavesurferParams} params\n * @return {Object} WaveSurfer instance\n * @example const wavesurfer = WaveSurfer.create(params);\n */\n static create(params) {\n const wavesurfer = new WaveSurfer(params);\n return wavesurfer.init();\n }\n\n /**\n * The library version number is available as a static property of the\n * WaveSurfer class\n *\n * @type {String}\n * @example\n * console.log('Using wavesurfer.js ' + WaveSurfer.VERSION);\n */\n static VERSION = __VERSION__;\n\n /**\n * Functions in the `util` property are available as a prototype property to\n * all instances\n *\n * @type {Object}\n * @example\n * const wavesurfer = WaveSurfer.create(params);\n * wavesurfer.util.style(myElement, { background: 'blue' });\n */\n util = util;\n\n /**\n * Functions in the `util` property are available as a static property of the\n * WaveSurfer class\n *\n * @type {Object}\n * @example\n * WaveSurfer.util.style(myElement, { background: 'blue' });\n */\n static util = util;\n\n /**\n * Initialise wavesurfer instance\n *\n * @param {WavesurferParams} params Instantiation options for wavesurfer\n * @example\n * const wavesurfer = new WaveSurfer(params);\n * @returns {this}\n */\n constructor(params) {\n super();\n /**\n * Extract relevant parameters (or defaults)\n * @private\n */\n this.params = util.extend({}, this.defaultParams, params);\n\n /** @private */\n this.container =\n 'string' == typeof params.container\n ? document.querySelector(this.params.container)\n : this.params.container;\n\n if (!this.container) {\n throw new Error('Container element not found');\n }\n\n if (this.params.mediaContainer == null) {\n /** @private */\n this.mediaContainer = this.container;\n } else if (typeof this.params.mediaContainer == 'string') {\n /** @private */\n this.mediaContainer = document.querySelector(\n this.params.mediaContainer\n );\n } else {\n /** @private */\n this.mediaContainer = this.params.mediaContainer;\n }\n\n if (!this.mediaContainer) {\n throw new Error('Media Container element not found');\n }\n\n if (this.params.maxCanvasWidth <= 1) {\n throw new Error('maxCanvasWidth must be greater than 1');\n } else if (this.params.maxCanvasWidth % 2 == 1) {\n throw new Error('maxCanvasWidth must be an even number');\n }\n\n /**\n * @private Used to save the current volume when muting so we can\n * restore once unmuted\n * @type {number}\n */\n this.savedVolume = 0;\n\n /**\n * @private The current muted state\n * @type {boolean}\n */\n this.isMuted = false;\n\n /**\n * @private Will hold a list of event descriptors that need to be\n * canceled on subsequent loads of audio\n * @type {Object[]}\n */\n this.tmpEvents = [];\n\n /**\n * @private Holds any running audio downloads\n * @type {Observer}\n */\n this.currentAjax = null;\n /** @private */\n this.arraybuffer = null;\n /** @private */\n this.drawer = null;\n /** @private */\n this.backend = null;\n /** @private */\n this.peakCache = null;\n\n // cache constructor objects\n if (typeof this.params.renderer !== 'function') {\n throw new Error('Renderer parameter is invalid');\n }\n /**\n * @private The uninitialised Drawer class\n */\n this.Drawer = this.params.renderer;\n /**\n * @private The uninitialised Backend class\n */\n this.Backend = this.backends[this.params.backend];\n\n /**\n * @private map of plugin names that are currently initialised\n */\n this.initialisedPluginList = {};\n /** @private */\n this.isDestroyed = false;\n /** @private */\n this.isReady = false;\n\n // responsive debounced event listener. If this.params.responsive is not\n // set, this is never called. Use 100ms or this.params.responsive as\n // timeout for the debounce function.\n let prevWidth = 0;\n this._onResize = util.debounce(\n () => {\n if (\n prevWidth != this.drawer.wrapper.clientWidth &&\n !this.params.scrollParent\n ) {\n prevWidth = this.drawer.wrapper.clientWidth;\n this.drawer.fireEvent('redraw');\n }\n },\n typeof this.params.responsive === 'number'\n ? this.params.responsive\n : 100\n );\n\n return this;\n }\n\n /**\n * Initialise the wave\n *\n * @example\n * var wavesurfer = new WaveSurfer(params);\n * wavesurfer.init();\n * @return {this}\n */\n init() {\n this.registerPlugins(this.params.plugins);\n this.createDrawer();\n this.createBackend();\n this.createPeakCache();\n return this;\n }\n\n /**\n * Add and initialise array of plugins (if `plugin.deferInit` is falsey),\n * this function is called in the init function of wavesurfer\n *\n * @param {PluginDefinition[]} plugins An array of plugin definitions\n * @emits {WaveSurfer#plugins-registered} Called with the array of plugin definitions\n * @return {this}\n */\n registerPlugins(plugins) {\n // first instantiate all the plugins\n plugins.forEach(plugin => this.addPlugin(plugin));\n\n // now run the init functions\n plugins.forEach(plugin => {\n // call init function of the plugin if deferInit is falsey\n // in that case you would manually use initPlugins()\n if (!plugin.deferInit) {\n this.initPlugin(plugin.name);\n }\n });\n this.fireEvent('plugins-registered', plugins);\n return this;\n }\n\n /**\n * Add a plugin object to wavesurfer\n *\n * @param {PluginDefinition} plugin A plugin definition\n * @emits {WaveSurfer#plugin-added} Called with the name of the plugin that was added\n * @example wavesurfer.addPlugin(WaveSurfer.minimap());\n * @return {this}\n */\n addPlugin(plugin) {\n if (!plugin.name) {\n throw new Error('Plugin does not have a name!');\n }\n if (!plugin.instance) {\n throw new Error(\n `Plugin ${plugin.name} does not have an instance property!`\n );\n }\n\n // staticProps properties are applied to wavesurfer instance\n if (plugin.staticProps) {\n Object.keys(plugin.staticProps).forEach(pluginStaticProp => {\n /**\n * Properties defined in a plugin definition's `staticProps` property are added as\n * staticProps properties of the WaveSurfer instance\n */\n this[pluginStaticProp] = plugin.staticProps[pluginStaticProp];\n });\n }\n\n const Instance = plugin.instance;\n\n // turn the plugin instance into an observer\n const observerPrototypeKeys = Object.getOwnPropertyNames(\n util.Observer.prototype\n );\n observerPrototypeKeys.forEach(key => {\n Instance.prototype[key] = util.Observer.prototype[key];\n });\n\n /**\n * Instantiated plugin classes are added as a property of the wavesurfer\n * instance\n * @type {Object}\n */\n this[plugin.name] = new Instance(plugin.params || {}, this);\n this.fireEvent('plugin-added', plugin.name);\n return this;\n }\n\n /**\n * Initialise a plugin\n *\n * @param {string} name A plugin name\n * @emits WaveSurfer#plugin-initialised\n * @example wavesurfer.initPlugin('minimap');\n * @return {this}\n */\n initPlugin(name) {\n if (!this[name]) {\n throw new Error(`Plugin ${name} has not been added yet!`);\n }\n if (this.initialisedPluginList[name]) {\n // destroy any already initialised plugins\n this.destroyPlugin(name);\n }\n this[name].init();\n this.initialisedPluginList[name] = true;\n this.fireEvent('plugin-initialised', name);\n return this;\n }\n\n /**\n * Destroy a plugin\n *\n * @param {string} name A plugin name\n * @emits WaveSurfer#plugin-destroyed\n * @example wavesurfer.destroyPlugin('minimap');\n * @returns {this}\n */\n destroyPlugin(name) {\n if (!this[name]) {\n throw new Error(\n `Plugin ${name} has not been added yet and cannot be destroyed!`\n );\n }\n if (!this.initialisedPluginList[name]) {\n throw new Error(\n `Plugin ${name} is not active and cannot be destroyed!`\n );\n }\n if (typeof this[name].destroy !== 'function') {\n throw new Error(`Plugin ${name} does not have a destroy function!`);\n }\n\n this[name].destroy();\n delete this.initialisedPluginList[name];\n this.fireEvent('plugin-destroyed', name);\n return this;\n }\n\n /**\n * Destroy all initialised plugins. Convenience function to use when\n * wavesurfer is removed\n *\n * @private\n */\n destroyAllPlugins() {\n Object.keys(this.initialisedPluginList).forEach(name =>\n this.destroyPlugin(name)\n );\n }\n\n /**\n * Create the drawer and draw the waveform\n *\n * @private\n * @emits WaveSurfer#drawer-created\n */\n createDrawer() {\n this.drawer = new this.Drawer(this.container, this.params);\n this.drawer.init();\n this.fireEvent('drawer-created', this.drawer);\n\n if (this.params.responsive !== false) {\n window.addEventListener('resize', this._onResize, true);\n window.addEventListener('orientationchange', this._onResize, true);\n }\n\n this.drawer.on('redraw', () => {\n this.drawBuffer();\n this.drawer.progress(this.backend.getPlayedPercents());\n });\n\n // Click-to-seek\n this.drawer.on('click', (e, progress) => {\n setTimeout(() => this.seekTo(progress), 0);\n });\n\n // Relay the scroll event from the drawer\n this.drawer.on('scroll', e => {\n if (this.params.partialRender) {\n this.drawBuffer();\n }\n this.fireEvent('scroll', e);\n });\n }\n\n /**\n * Create the backend\n *\n * @private\n * @emits WaveSurfer#backend-created\n */\n createBackend() {\n if (this.backend) {\n this.backend.destroy();\n }\n\n // Back compat\n if (this.params.backend == 'AudioElement') {\n this.params.backend = 'MediaElement';\n }\n\n if (\n this.params.backend == 'WebAudio' &&\n !this.Backend.prototype.supportsWebAudio.call(null)\n ) {\n this.params.backend = 'MediaElement';\n }\n\n this.backend = new this.Backend(this.params);\n this.backend.init();\n this.fireEvent('backend-created', this.backend);\n\n this.backend.on('finish', () => {\n this.drawer.progress(this.backend.getPlayedPercents());\n this.fireEvent('finish');\n });\n this.backend.on('play', () => this.fireEvent('play'));\n this.backend.on('pause', () => this.fireEvent('pause'));\n\n this.backend.on('audioprocess', time => {\n this.drawer.progress(this.backend.getPlayedPercents());\n this.fireEvent('audioprocess', time);\n });\n }\n\n /**\n * Create the peak cache\n *\n * @private\n */\n createPeakCache() {\n if (this.params.partialRender) {\n this.peakCache = new PeakCache();\n }\n }\n\n /**\n * Get the duration of the audio clip\n *\n * @example const duration = wavesurfer.getDuration();\n * @return {number} Duration in seconds\n */\n getDuration() {\n return this.backend.getDuration();\n }\n\n /**\n * Get the current playback position\n *\n * @example const currentTime = wavesurfer.getCurrentTime();\n * @return {number} Playback position in seconds\n */\n getCurrentTime() {\n return this.backend.getCurrentTime();\n }\n\n /**\n * Set the current play time in seconds.\n *\n * @param {number} seconds A positive number in seconds. E.g. 10 means 10\n * seconds, 60 means 1 minute\n */\n setCurrentTime(seconds) {\n if (seconds >= this.getDuration()) {\n this.seekTo(1);\n } else {\n this.seekTo(seconds / this.getDuration());\n }\n }\n\n /**\n * Starts playback from the current position. Optional start and end\n * measured in seconds can be used to set the range of audio to play.\n *\n * @param {?number} start Position to start at\n * @param {?number} end Position to end at\n * @emits WaveSurfer#interaction\n * @return {Promise}\n * @example\n * // play from second 1 to 5\n * wavesurfer.play(1, 5);\n */\n play(start, end) {\n this.fireEvent('interaction', () => this.play(start, end));\n return this.backend.play(start, end);\n }\n\n /**\n * Stops playback\n *\n * @example wavesurfer.pause();\n * @return {Promise}\n */\n pause() {\n if (!this.backend.isPaused()) {\n return this.backend.pause();\n }\n }\n\n /**\n * Toggle playback\n *\n * @example wavesurfer.playPause();\n * @return {Promise}\n */\n playPause() {\n return this.backend.isPaused() ? this.play() : this.pause();\n }\n\n /**\n * Get the current playback state\n *\n * @example const isPlaying = wavesurfer.isPlaying();\n * @return {boolean} False if paused, true if playing\n */\n isPlaying() {\n return !this.backend.isPaused();\n }\n\n /**\n * Skip backward\n *\n * @param {?number} seconds Amount to skip back, if not specified `skipLength`\n * is used\n * @example wavesurfer.skipBackward();\n */\n skipBackward(seconds) {\n this.skip(-seconds || -this.params.skipLength);\n }\n\n /**\n * Skip forward\n *\n * @param {?number} seconds Amount to skip back, if not specified `skipLength`\n * is used\n * @example wavesurfer.skipForward();\n */\n skipForward(seconds) {\n this.skip(seconds || this.params.skipLength);\n }\n\n /**\n * Skip a number of seconds from the current position (use a negative value\n * to go backwards).\n *\n * @param {number} offset Amount to skip back or forwards\n * @example\n * // go back 2 seconds\n * wavesurfer.skip(-2);\n */\n skip(offset) {\n const duration = this.getDuration() || 1;\n let position = this.getCurrentTime() || 0;\n position = Math.max(0, Math.min(duration, position + (offset || 0)));\n this.seekAndCenter(position / duration);\n }\n\n /**\n * Seeks to a position and centers the view\n *\n * @param {number} progress Between 0 (=beginning) and 1 (=end)\n * @example\n * // seek and go to the middle of the audio\n * wavesurfer.seekTo(0.5);\n */\n seekAndCenter(progress) {\n this.seekTo(progress);\n this.drawer.recenter(progress);\n }\n\n /**\n * Seeks to a position\n *\n * @param {number} progress Between 0 (=beginning) and 1 (=end)\n * @emits WaveSurfer#interaction\n * @emits WaveSurfer#seek\n * @example\n * // seek to the middle of the audio\n * wavesurfer.seekTo(0.5);\n */\n seekTo(progress) {\n // return an error if progress is not a number between 0 and 1\n if (\n typeof progress !== 'number' ||\n !isFinite(progress) ||\n progress < 0 ||\n progress > 1\n ) {\n return console.error(\n 'Error calling wavesurfer.seekTo, parameter must be a number between 0 and 1!'\n );\n }\n this.fireEvent('interaction', () => this.seekTo(progress));\n\n const paused = this.backend.isPaused();\n // avoid draw wrong position while playing backward seeking\n if (!paused) {\n this.backend.pause();\n }\n // avoid small scrolls while paused seeking\n const oldScrollParent = this.params.scrollParent;\n this.params.scrollParent = false;\n this.backend.seekTo(progress * this.getDuration());\n this.drawer.progress(progress);\n\n if (!paused) {\n this.backend.play();\n }\n this.params.scrollParent = oldScrollParent;\n this.fireEvent('seek', progress);\n }\n\n /**\n * Stops and goes to the beginning.\n *\n * @example wavesurfer.stop();\n */\n stop() {\n this.pause();\n this.seekTo(0);\n this.drawer.progress(0);\n }\n\n /**\n * Set the playback volume.\n *\n * @param {string} deviceId String value representing underlying output device\n */\n setSinkId(deviceId) {\n return this.backend.setSinkId(deviceId);\n }\n\n /**\n * Set the playback volume.\n *\n * @param {number} newVolume A value between 0 and 1, 0 being no\n * volume and 1 being full volume.\n * @emits WaveSurfer#volume\n */\n setVolume(newVolume) {\n this.backend.setVolume(newVolume);\n this.fireEvent('volume', newVolume);\n }\n\n /**\n * Get the playback volume.\n *\n * @return {number} A value between 0 and 1, 0 being no\n * volume and 1 being full volume.\n */\n getVolume() {\n return this.backend.getVolume();\n }\n\n /**\n * Set the playback rate.\n *\n * @param {number} rate A positive number. E.g. 0.5 means half the normal\n * speed, 2 means double speed and so on.\n * @example wavesurfer.setPlaybackRate(2);\n */\n setPlaybackRate(rate) {\n this.backend.setPlaybackRate(rate);\n }\n\n /**\n * Get the playback rate.\n *\n * @return {number}\n */\n getPlaybackRate() {\n return this.backend.getPlaybackRate();\n }\n\n /**\n * Toggle the volume on and off. If not currently muted it will save the\n * current volume value and turn the volume off. If currently muted then it\n * will restore the volume to the saved value, and then rest the saved\n * value.\n *\n * @example wavesurfer.toggleMute();\n */\n toggleMute() {\n this.setMute(!this.isMuted);\n }\n\n /**\n * Enable or disable muted audio\n *\n * @param {boolean} mute\n * @emits WaveSurfer#volume\n * @emits WaveSurfer#mute\n * @example\n * // unmute\n * wavesurfer.setMute(false);\n */\n setMute(mute) {\n // ignore all muting requests if the audio is already in that state\n if (mute === this.isMuted) {\n this.fireEvent('mute', this.isMuted);\n return;\n }\n\n if (mute) {\n // If currently not muted then save current volume,\n // turn off the volume and update the mute properties\n this.savedVolume = this.backend.getVolume();\n this.backend.setVolume(0);\n this.isMuted = true;\n this.fireEvent('volume', 0);\n } else {\n // If currently muted then restore to the saved volume\n // and update the mute properties\n this.backend.setVolume(this.savedVolume);\n this.isMuted = false;\n this.fireEvent('volume', this.savedVolume);\n }\n this.fireEvent('mute', this.isMuted);\n }\n\n /**\n * Get the current mute status.\n *\n * @example const isMuted = wavesurfer.getMute();\n * @return {boolean}\n */\n getMute() {\n return this.isMuted;\n }\n\n /**\n * Get the current ready status.\n *\n * @example const isReady = wavesurfer.isReady();\n * @return {boolean}\n */\n isReady() {\n return this.isReady;\n }\n\n /**\n * Get the list of current set filters as an array.\n *\n * Filters must be set with setFilters method first\n *\n * @return {array}\n */\n getFilters() {\n return this.backend.filters || [];\n }\n\n /**\n * Toggles `scrollParent` and redraws\n *\n * @example wavesurfer.toggleScroll();\n */\n toggleScroll() {\n this.params.scrollParent = !this.params.scrollParent;\n this.drawBuffer();\n }\n\n /**\n * Toggle mouse interaction\n *\n * @example wavesurfer.toggleInteraction();\n */\n toggleInteraction() {\n this.params.interact = !this.params.interact;\n }\n\n /**\n * Get the fill color of the waveform after the cursor.\n *\n * @return {string} A CSS color string.\n */\n getWaveColor() {\n return this.params.waveColor;\n }\n\n /**\n * Set the fill color of the waveform after the cursor.\n *\n * @param {string} color A CSS color string.\n * @example wavesurfer.setWaveColor('#ddd');\n */\n setWaveColor(color) {\n this.params.waveColor = color;\n this.drawBuffer();\n }\n\n /**\n * Get the fill color of the waveform behind the cursor.\n *\n * @return {string} A CSS color string.\n */\n getProgressColor() {\n return this.params.progressColor;\n }\n\n /**\n * Set the fill color of the waveform behind the cursor.\n *\n * @param {string} color A CSS color string.\n * @example wavesurfer.setProgressColor('#400');\n */\n setProgressColor(color) {\n this.params.progressColor = color;\n this.drawBuffer();\n }\n\n /**\n * Get the fill color of the cursor indicating the playhead\n * position.\n *\n * @return {string} A CSS color string.\n */\n getCursorColor() {\n return this.params.cursorColor;\n }\n\n /**\n * Set the fill color of the cursor indicating the playhead\n * position.\n *\n * @param {string} color A CSS color string.\n * @example wavesurfer.setCursorColor('#222');\n */\n setCursorColor(color) {\n this.params.cursorColor = color;\n this.drawer.updateCursor();\n }\n\n /**\n * Get the height of the waveform.\n *\n * @return {number} Height measured in pixels.\n */\n getHeight() {\n return this.params.height;\n }\n\n /**\n * Set the height of the waveform.\n *\n * @param {number} height Height measured in pixels.\n * @example wavesurfer.setHeight(200);\n */\n setHeight(height) {\n this.params.height = height;\n this.drawer.setHeight(height * this.params.pixelRatio);\n this.drawBuffer();\n }\n\n /**\n * Get the correct peaks for current wave view-port and render wave\n *\n * @private\n * @emits WaveSurfer#redraw\n */\n drawBuffer() {\n const nominalWidth = Math.round(\n this.getDuration() *\n this.params.minPxPerSec *\n this.params.pixelRatio\n );\n const parentWidth = this.drawer.getWidth();\n let width = nominalWidth;\n let start = this.drawer.getScrollX();\n let end = Math.max(start + parentWidth, width);\n // Fill container\n if (\n this.params.fillParent &&\n (!this.params.scrollParent || nominalWidth < parentWidth)\n ) {\n width = parentWidth;\n start = 0;\n end = width;\n }\n\n let peaks;\n if (this.params.partialRender) {\n const newRanges = this.peakCache.addRangeToPeakCache(\n width,\n start,\n end\n );\n let i;\n for (i = 0; i < newRanges.length; i++) {\n peaks = this.backend.getPeaks(\n width,\n newRanges[i][0],\n newRanges[i][1]\n );\n this.drawer.drawPeaks(\n peaks,\n width,\n newRanges[i][0],\n newRanges[i][1]\n );\n }\n } else {\n peaks = this.backend.getPeaks(width, start, end);\n this.drawer.drawPeaks(peaks, width, start, end);\n }\n this.fireEvent('redraw', peaks, width);\n }\n\n /**\n * Horizontally zooms the waveform in and out. It also changes the parameter\n * `minPxPerSec` and enables the `scrollParent` option. Calling the function\n * with a falsey parameter will reset the zoom state.\n *\n * @param {?number} pxPerSec Number of horizontal pixels per second of\n * audio, if none is set the waveform returns to unzoomed state\n * @emits WaveSurfer#zoom\n * @example wavesurfer.zoom(20);\n */\n zoom(pxPerSec) {\n if (!pxPerSec) {\n this.params.minPxPerSec = this.defaultParams.minPxPerSec;\n this.params.scrollParent = false;\n } else {\n this.params.minPxPerSec = pxPerSec;\n this.params.scrollParent = true;\n }\n\n this.drawBuffer();\n this.drawer.progress(this.backend.getPlayedPercents());\n\n this.drawer.recenter(this.getCurrentTime() / this.getDuration());\n this.fireEvent('zoom', pxPerSec);\n }\n\n /**\n * Decode buffer and load\n *\n * @private\n * @param {ArrayBuffer} arraybuffer\n */\n loadArrayBuffer(arraybuffer) {\n this.decodeArrayBuffer(arraybuffer, data => {\n if (!this.isDestroyed) {\n this.loadDecodedBuffer(data);\n }\n });\n }\n\n /**\n * Directly load an externally decoded AudioBuffer\n *\n * @private\n * @param {AudioBuffer} buffer\n * @emits WaveSurfer#ready\n */\n loadDecodedBuffer(buffer) {\n this.backend.load(buffer);\n this.drawBuffer();\n this.fireEvent('ready');\n this.isReady = true;\n }\n\n /**\n * Loads audio data from a Blob or File object\n *\n * @param {Blob|File} blob Audio data\n * @example\n */\n loadBlob(blob) {\n // Create file reader\n const reader = new FileReader();\n reader.addEventListener('progress', e => this.onProgress(e));\n reader.addEventListener('load', e =>\n this.loadArrayBuffer(e.target.result)\n );\n reader.addEventListener('error', () =>\n this.fireEvent('error', 'Error reading file')\n );\n reader.readAsArrayBuffer(blob);\n this.empty();\n }\n\n /**\n * Loads audio and re-renders the waveform.\n *\n * @param {string|HTMLMediaElement} url The url of the audio file or the\n * audio element with the audio\n * @param {?number[]|number[][]} peaks Wavesurfer does not have to decode\n * the audio to render the waveform if this is specified\n * @param {?string} preload (Use with backend `MediaElement`)\n * `'none'|'metadata'|'auto'` Preload attribute for the media element\n * @param {?number} duration The duration of the audio. This is used to\n * render the peaks data in the correct size for the audio duration (as\n * befits the current minPxPerSec and zoom value) without having to decode\n * the audio.\n * @example\n * // using ajax or media element to load (depending on backend)\n * wavesurfer.load('http://example.com/demo.wav');\n *\n * // setting preload attribute with media element backend and supplying\n * peaks wavesurfer.load(\n * 'http://example.com/demo.wav',\n * [0.0218, 0.0183, 0.0165, 0.0198, 0.2137, 0.2888],\n * true,\n * );\n */\n load(url, peaks, preload, duration) {\n this.empty();\n\n if (preload) {\n // check whether the preload attribute will be usable and if not log\n // a warning listing the reasons why not and nullify the variable\n const preloadIgnoreReasons = {\n \"Preload is not 'auto', 'none' or 'metadata'\":\n ['auto', 'metadata', 'none'].indexOf(preload) === -1,\n 'Peaks are not provided': !peaks,\n 'Backend is not of type MediaElement':\n this.params.backend !== 'MediaElement',\n 'Url is not of type string': typeof url !== 'string'\n };\n const activeReasons = Object.keys(preloadIgnoreReasons).filter(\n reason => preloadIgnoreReasons[reason]\n );\n if (activeReasons.length) {\n console.warn(\n 'Preload parameter of wavesurfer.load will be ignored because:\\n\\t- ' +\n activeReasons.join('\\n\\t- ')\n );\n // stop invalid values from being used\n preload = null;\n }\n }\n\n switch (this.params.backend) {\n case 'WebAudio':\n return this.loadBuffer(url, peaks, duration);\n case 'MediaElement':\n return this.loadMediaElement(url, peaks, preload, duration);\n }\n }\n\n /**\n * Loads audio using Web Audio buffer backend.\n *\n * @private\n * @param {string} url\n * @param {?number[]|number[][]} peaks\n * @param {?number} duration\n */\n loadBuffer(url, peaks, duration) {\n const load = action => {\n if (action) {\n this.tmpEvents.push(this.once('ready', action));\n }\n return this.getArrayBuffer(url, data => this.loadArrayBuffer(data));\n };\n\n if (peaks) {\n this.backend.setPeaks(peaks, duration);\n this.drawBuffer();\n this.tmpEvents.push(this.once('interaction', load));\n } else {\n return load();\n }\n }\n\n /**\n * Either create a media element, or load an existing media element.\n *\n * @private\n * @param {string|HTMLMediaElement} urlOrElt Either a path to a media file, or an\n * existing HTML5 Audio/Video Element\n * @param {number[]|number[][]} peaks Array of peaks. Required to bypass web audio\n * dependency\n * @param {?boolean} preload Set to true if the preload attribute of the\n * audio element should be enabled\n * @param {?number} duration\n */\n loadMediaElement(urlOrElt, peaks, preload, duration) {\n let url = urlOrElt;\n\n if (typeof urlOrElt === 'string') {\n this.backend.load(url, this.mediaContainer, peaks, preload);\n } else {\n const elt = urlOrElt;\n this.backend.loadElt(elt, peaks);\n\n // If peaks are not provided,\n // url = element.src so we can get peaks with web audio\n url = elt.src;\n }\n\n this.tmpEvents.push(\n this.backend.once('canplay', () => {\n this.drawBuffer();\n this.fireEvent('ready');\n this.isReady = true;\n }),\n this.backend.once('error', err => this.fireEvent('error', err))\n );\n\n // If no pre-decoded peaks provided or pre-decoded peaks are\n // provided with forceDecode flag, attempt to download the\n // audio file and decode it with Web Audio.\n if (peaks) {\n this.backend.setPeaks(peaks, duration);\n }\n\n if (\n (!peaks || this.params.forceDecode) &&\n this.backend.supportsWebAudio()\n ) {\n this.getArrayBuffer(url, arraybuffer => {\n this.decodeArrayBuffer(arraybuffer, buffer => {\n this.backend.buffer = buffer;\n this.backend.setPeaks(null);\n this.drawBuffer();\n this.fireEvent('waveform-ready');\n });\n });\n }\n }\n\n /**\n * Decode an array buffer and pass data to a callback\n *\n * @private\n * @param {Object} arraybuffer\n * @param {function} callback\n */\n decodeArrayBuffer(arraybuffer, callback) {\n this.arraybuffer = arraybuffer;\n\n this.backend.decodeArrayBuffer(\n arraybuffer,\n data => {\n // Only use the decoded data if we haven't been destroyed or\n // another decode started in the meantime\n if (!this.isDestroyed && this.arraybuffer == arraybuffer) {\n callback(data);\n this.arraybuffer = null;\n }\n },\n () => this.fireEvent('error', 'Error decoding audiobuffer')\n );\n }\n\n /**\n * Load an array buffer by ajax and pass to a callback\n *\n * @param {string} url\n * @param {function} callback\n * @private\n */\n getArrayBuffer(url, callback) {\n const ajax = util.ajax({\n url: url,\n responseType: 'arraybuffer',\n xhr: this.params.xhr\n });\n\n this.currentAjax = ajax;\n\n this.tmpEvents.push(\n ajax.on('progress', e => {\n this.onProgress(e);\n }),\n ajax.on('success', (data, e) => {\n callback(data);\n this.currentAjax = null;\n }),\n ajax.on('error', e => {\n this.fireEvent('error', 'XHR error: ' + e.target.statusText);\n this.currentAjax = null;\n })\n );\n\n return ajax;\n }\n\n /**\n * Called while the audio file is loading\n *\n * @private\n * @param {Event} e\n * @emits WaveSurfer#loading\n */\n onProgress(e) {\n let percentComplete;\n if (e.lengthComputable) {\n percentComplete = e.loaded / e.total;\n } else {\n // Approximate progress with an asymptotic\n // function, and assume downloads in the 1-3 MB range.\n percentComplete = e.loaded / (e.loaded + 1000000);\n }\n this.fireEvent('loading', Math.round(percentComplete * 100), e.target);\n }\n\n /**\n * Exports PCM data into a JSON array and opens in a new window.\n *\n * @param {number} length=1024 The scale in which to export the peaks. (Integer)\n * @param {number} accuracy=10000 (Integer)\n * @param {?boolean} noWindow Set to true to disable opening a new\n * window with the JSON\n * @param {number} start\n * @todo Update exportPCM to work with new getPeaks signature\n * @return {string} JSON of peaks\n */\n exportPCM(length, accuracy, noWindow, start) {\n length = length || 1024;\n start = start || 0;\n accuracy = accuracy || 10000;\n noWindow = noWindow || false;\n const peaks = this.backend.getPeaks(length, start);\n const arr = [].map.call(\n peaks,\n val => Math.round(val * accuracy) / accuracy\n );\n const json = JSON.stringify(arr);\n if (!noWindow) {\n window.open(\n 'data:application/json;charset=utf-8,' +\n encodeURIComponent(json)\n );\n }\n return json;\n }\n\n /**\n * Save waveform image as data URI.\n *\n * The default format is `image/png`. Other supported types are\n * `image/jpeg` and `image/webp`.\n *\n * @param {string} format='image/png'\n * @param {number} quality=1\n * @return {string} data URI of image\n */\n exportImage(format, quality) {\n if (!format) {\n format = 'image/png';\n }\n if (!quality) {\n quality = 1;\n }\n\n return this.drawer.getImage(format, quality);\n }\n\n /**\n * Cancel any ajax request currently in progress\n */\n cancelAjax() {\n if (this.currentAjax) {\n this.currentAjax.xhr.abort();\n this.currentAjax = null;\n }\n }\n\n /**\n * @private\n */\n clearTmpEvents() {\n this.tmpEvents.forEach(e => e.un());\n }\n\n /**\n * Display empty waveform.\n */\n empty() {\n if (!this.backend.isPaused()) {\n this.stop();\n this.backend.disconnectSource();\n }\n this.isReady = false;\n this.cancelAjax();\n this.clearTmpEvents();\n this.drawer.progress(0);\n this.drawer.setWidth(0);\n this.drawer.drawPeaks({ length: this.drawer.getWidth() }, 0);\n }\n\n /**\n * Remove events, elements and disconnect WebAudio nodes.\n *\n * @emits WaveSurfer#destroy\n */\n destroy() {\n this.destroyAllPlugins();\n this.fireEvent('destroy');\n this.cancelAjax();\n this.clearTmpEvents();\n this.unAll();\n if (this.params.responsive !== false) {\n window.removeEventListener('resize', this._onResize, true);\n window.removeEventListener(\n 'orientationchange',\n this._onResize,\n true\n );\n }\n this.backend.destroy();\n this.drawer.destroy();\n this.isDestroyed = true;\n this.isReady = false;\n this.arraybuffer = null;\n }\n}\n","import Observer from './observer';\n\n/**\n * Perform an ajax request\n *\n * @param {Options} options Description\n *\n * @returns {Object} Observer instance\n */\nexport default function ajax(options) {\n const instance = new Observer();\n const xhr = new XMLHttpRequest();\n let fired100 = false;\n xhr.open(options.method || 'GET', options.url, true);\n xhr.responseType = options.responseType || 'json';\n\n if (options.xhr) {\n if (options.xhr.requestHeaders) {\n // add custom request headers\n options.xhr.requestHeaders.forEach(header => {\n xhr.setRequestHeader(header.key, header.value);\n });\n }\n if (options.xhr.withCredentials) {\n // use credentials\n xhr.withCredentials = true;\n }\n }\n\n xhr.addEventListener('progress', e => {\n instance.fireEvent('progress', e);\n if (e.lengthComputable && e.loaded == e.total) {\n fired100 = true;\n }\n });\n xhr.addEventListener('load', e => {\n if (!fired100) {\n instance.fireEvent('progress', e);\n }\n instance.fireEvent('load', e);\n if (200 == xhr.status || 206 == xhr.status) {\n instance.fireEvent('success', xhr.response, e);\n } else {\n instance.fireEvent('error', e);\n }\n });\n xhr.addEventListener('error', e => instance.fireEvent('error', e));\n xhr.send();\n instance.xhr = xhr;\n return instance;\n}\n","/**\n * Get a random prefixed ID\n *\n * @returns {String} Random ID\n */\nexport default function getId() {\n return (\n 'wavesurfer_' +\n Math.random()\n .toString(32)\n .substring(2)\n );\n}\n","/**\n * Get the largest value\n *\n * @param {Array} values Array of numbers\n * @returns {Number} Largest number found\n */\nexport default function max(values) {\n let largest = -Infinity;\n Object.keys(values).forEach(i => {\n if (values[i] > largest) {\n largest = values[i];\n }\n });\n return largest;\n}\n","/**\n * Get the smallest value\n *\n * @param {Array} values Array of numbers\n * @returns {Number} Smallest number found\n */\nexport default function min(values) {\n let smallest = Number(Infinity);\n Object.keys(values).forEach(i => {\n if (values[i] < smallest) {\n smallest = values[i];\n }\n });\n return smallest;\n}\n","/**\n * Extend an object shallowly with others\n *\n * @param {Object} dest The target object\n * @param {Object[]} sources The objects to use for extending\n *\n * @return {Object} Merged object\n */\nexport default function extend(dest, ...sources) {\n sources.forEach(source => {\n Object.keys(source).forEach(key => {\n dest[key] = source[key];\n });\n });\n return dest;\n}\n","/**\n * Apply a map of styles to an element\n *\n * @param {HTMLElement} el The element that the styles will be applied to\n * @param {Object} styles The map of propName: attribute, both are used as-is\n *\n * @return {HTMLElement} el\n */\nexport default function style(el, styles) {\n Object.keys(styles).forEach(prop => {\n if (el.style[prop] !== styles[prop]) {\n el.style[prop] = styles[prop];\n }\n });\n return el;\n}\n","import reqAnimationFrame from './request-animation-frame';\n\n/**\n * Create a function which will be called at the next requestAnimationFrame\n * cycle\n *\n * @param {function} func The function to call\n *\n * @return {func} The function wrapped within a requestAnimationFrame\n */\nexport default function frame(func) {\n return (...args) => reqAnimationFrame(() => func(...args));\n}\n","/**\n * Returns a function, that, as long as it continues to be invoked, will not\n * be triggered. The function will be called after it stops being called for\n * N milliseconds. If `immediate` is passed, trigger the function on the\n * leading edge, instead of the trailing. The function also has a property 'clear' \n * that is a function which will clear the timer to prevent previously scheduled executions. \n *\n * @source underscore.js\n * @see http://unscriptable.com/2009/03/20/debouncing-javascript-methods/\n * @param {Function} function to wrap\n * @param {Number} timeout in ms (`100`)\n * @param {Boolean} whether to execute at the beginning (`false`)\n * @api public\n */\nfunction debounce(func, wait, immediate){\n var timeout, args, context, timestamp, result;\n if (null == wait) wait = 100;\n\n function later() {\n var last = Date.now() - timestamp;\n\n if (last < wait && last >= 0) {\n timeout = setTimeout(later, wait - last);\n } else {\n timeout = null;\n if (!immediate) {\n result = func.apply(context, args);\n context = args = null;\n }\n }\n };\n\n var debounced = function(){\n context = this;\n args = arguments;\n timestamp = Date.now();\n var callNow = immediate && !timeout;\n if (!timeout) timeout = setTimeout(later, wait);\n if (callNow) {\n result = func.apply(context, args);\n context = args = null;\n }\n\n return result;\n };\n\n debounced.clear = function() {\n if (timeout) {\n clearTimeout(timeout);\n timeout = null;\n }\n };\n \n debounced.flush = function() {\n if (timeout) {\n result = func.apply(context, args);\n context = args = null;\n \n clearTimeout(timeout);\n timeout = null;\n }\n };\n\n return debounced;\n};\n\n// Adds compatibility for ES modules\ndebounce.debounce = debounce;\n\nmodule.exports = debounce;\n","function preventClickHandler(e) {\n e.stopPropagation();\n document.body.removeEventListener('click', preventClickHandler, true);\n}\n\nexport default function preventClick(values) {\n document.body.addEventListener('click', preventClickHandler, true);\n}\n","import Drawer from './drawer';\nimport * as util from './util';\n\n/**\n * @typedef {Object} CanvasEntry\n * @private\n * @property {HTMLElement} wave The wave node\n * @property {CanvasRenderingContext2D} waveCtx The canvas rendering context\n * @property {?HTMLElement} progress The progress wave node\n * @property {?CanvasRenderingContext2D} progressCtx The progress wave canvas\n * rendering context\n * @property {?number} start Start of the area the canvas should render, between 0 and 1\n * @property {?number} end End of the area the canvas should render, between 0 and 1\n */\n\n/**\n * MultiCanvas renderer for wavesurfer. Is currently the default and sole built\n * in renderer.\n */\nexport default class MultiCanvas extends Drawer {\n /**\n * @param {HTMLElement} container The container node of the wavesurfer instance\n * @param {WavesurferParams} params The wavesurfer initialisation options\n */\n constructor(container, params) {\n super(container, params);\n /**\n * @type {number}\n * @private\n */\n this.maxCanvasWidth = params.maxCanvasWidth;\n /**\n * @private\n * @type {number}\n */\n this.maxCanvasElementWidth = Math.round(\n params.maxCanvasWidth / params.pixelRatio\n );\n\n /**\n * Whether or not the progress wave is rendered. If the `waveColor`\n * and `progressColor` are the same color it is not.\n * @type {boolean}\n */\n this.hasProgressCanvas = params.waveColor != params.progressColor;\n /**\n * @private\n * @type {number}\n */\n this.halfPixel = 0.5 / params.pixelRatio;\n /**\n * @private\n * @type {Array}\n */\n this.canvases = [];\n /** @private */\n this.progressWave = null;\n }\n\n /**\n * Initialize the drawer\n */\n init() {\n this.createWrapper();\n this.createElements();\n }\n\n /**\n * Create the canvas elements and style them\n *\n * @private\n */\n createElements() {\n this.progressWave = this.wrapper.appendChild(\n this.style(document.createElement('wave'), {\n position: 'absolute',\n zIndex: 3,\n left: 0,\n top: 0,\n bottom: 0,\n overflow: 'hidden',\n width: '0',\n display: 'none',\n boxSizing: 'border-box',\n borderRightStyle: 'solid',\n pointerEvents: 'none'\n })\n );\n\n this.addCanvas();\n this.updateCursor();\n }\n\n /**\n * Update cursor style from params.\n */\n updateCursor() {\n this.style(this.progressWave, {\n borderRightWidth: this.params.cursorWidth + 'px',\n borderRightColor: this.params.cursorColor\n });\n }\n\n /**\n * Adjust to the updated size by adding or removing canvases\n */\n updateSize() {\n const totalWidth = Math.round(this.width / this.params.pixelRatio);\n const requiredCanvases = Math.ceil(\n totalWidth / this.maxCanvasElementWidth\n );\n\n while (this.canvases.length < requiredCanvases) {\n this.addCanvas();\n }\n\n while (this.canvases.length > requiredCanvases) {\n this.removeCanvas();\n }\n\n this.canvases.forEach((entry, i) => {\n // Add some overlap to prevent vertical white stripes, keep the\n // width even for simplicity\n let canvasWidth =\n this.maxCanvasWidth + 2 * Math.ceil(this.params.pixelRatio / 2);\n\n if (i == this.canvases.length - 1) {\n canvasWidth =\n this.width -\n this.maxCanvasWidth * (this.canvases.length - 1);\n }\n\n this.updateDimensions(entry, canvasWidth, this.height);\n this.clearWaveForEntry(entry);\n });\n }\n\n /**\n * Add a canvas to the canvas list\n *\n * @private\n */\n addCanvas() {\n const entry = {};\n const leftOffset = this.maxCanvasElementWidth * this.canvases.length;\n\n entry.wave = this.wrapper.appendChild(\n this.style(document.createElement('canvas'), {\n position: 'absolute',\n zIndex: 2,\n left: leftOffset + 'px',\n top: 0,\n bottom: 0,\n height: '100%',\n pointerEvents: 'none'\n })\n );\n entry.waveCtx = entry.wave.getContext('2d');\n\n if (this.hasProgressCanvas) {\n entry.progress = this.progressWave.appendChild(\n this.style(document.createElement('canvas'), {\n position: 'absolute',\n left: leftOffset + 'px',\n top: 0,\n bottom: 0,\n height: '100%'\n })\n );\n entry.progressCtx = entry.progress.getContext('2d');\n }\n\n this.canvases.push(entry);\n }\n\n /**\n * Pop one canvas from the list\n *\n * @private\n */\n removeCanvas() {\n const lastEntry = this.canvases.pop();\n lastEntry.wave.parentElement.removeChild(lastEntry.wave);\n if (this.hasProgressCanvas) {\n lastEntry.progress.parentElement.removeChild(lastEntry.progress);\n }\n }\n\n /**\n * Update the dimensions of a canvas element\n *\n * @private\n * @param {CanvasEntry} entry\n * @param {number} width The new width of the element\n * @param {number} height The new height of the element\n */\n updateDimensions(entry, width, height) {\n const elementWidth = Math.round(width / this.params.pixelRatio);\n const totalWidth = Math.round(this.width / this.params.pixelRatio);\n\n // Where the canvas starts and ends in the waveform, represented as a\n // decimal between 0 and 1.\n entry.start = entry.waveCtx.canvas.offsetLeft / totalWidth || 0;\n entry.end = entry.start + elementWidth / totalWidth;\n\n entry.waveCtx.canvas.width = width;\n entry.waveCtx.canvas.height = height;\n this.style(entry.waveCtx.canvas, { width: elementWidth + 'px' });\n\n this.style(this.progressWave, { display: 'block' });\n\n if (this.hasProgressCanvas) {\n entry.progressCtx.canvas.width = width;\n entry.progressCtx.canvas.height = height;\n this.style(entry.progressCtx.canvas, {\n width: elementWidth + 'px'\n });\n }\n }\n\n /**\n * Clear the whole waveform\n */\n clearWave() {\n this.canvases.forEach(entry => this.clearWaveForEntry(entry));\n }\n\n /**\n * Clear one canvas\n *\n * @private\n * @param {CanvasEntry} entry\n */\n clearWaveForEntry(entry) {\n entry.waveCtx.clearRect(\n 0,\n 0,\n entry.waveCtx.canvas.width,\n entry.waveCtx.canvas.height\n );\n if (this.hasProgressCanvas) {\n entry.progressCtx.clearRect(\n 0,\n 0,\n entry.progressCtx.canvas.width,\n entry.progressCtx.canvas.height\n );\n }\n }\n\n /**\n * Draw a waveform with bars\n *\n * @param {number[]|number[][]} peaks Can also be an array of arrays for split channel\n * rendering\n * @param {number} channelIndex The index of the current channel. Normally\n * should be 0. Must be an integer.\n * @param {number} start The x-offset of the beginning of the area that\n * should be rendered\n * @param {number} end The x-offset of the end of the area that should be\n * rendered\n */\n drawBars(peaks, channelIndex, start, end) {\n return this.prepareDraw(\n peaks,\n channelIndex,\n start,\n end,\n ({ absmax, hasMinVals, height, offsetY, halfH, peaks }) => {\n // if drawBars was called within ws.empty we don't pass a start and\n // don't want anything to happen\n if (start === undefined) {\n return;\n }\n // Skip every other value if there are negatives.\n const peakIndexScale = hasMinVals ? 2 : 1;\n const length = peaks.length / peakIndexScale;\n const bar = this.params.barWidth * this.params.pixelRatio;\n const gap =\n this.params.barGap === null\n ? Math.max(this.params.pixelRatio, ~~(bar / 2))\n : Math.max(\n this.params.pixelRatio,\n this.params.barGap * this.params.pixelRatio\n );\n const step = bar + gap;\n\n const scale = length / this.width;\n const first = start;\n const last = end;\n let i;\n\n for (i = first; i < last; i += step) {\n const peak =\n peaks[Math.floor(i * scale * peakIndexScale)] || 0;\n const h = Math.round((peak / absmax) * halfH);\n this.fillRect(\n i + this.halfPixel,\n halfH - h + offsetY,\n bar + this.halfPixel,\n h * 2\n );\n }\n }\n );\n }\n\n /**\n * Draw a waveform\n *\n * @param {number[]|number[][]} peaks Can also be an array of arrays for split channel\n * rendering\n * @param {number} channelIndex The index of the current channel. Normally\n * should be 0\n * @param {number?} start The x-offset of the beginning of the area that\n * should be rendered (If this isn't set only a flat line is rendered)\n * @param {number?} end The x-offset of the end of the area that should be\n * rendered\n */\n drawWave(peaks, channelIndex, start, end) {\n return this.prepareDraw(\n peaks,\n channelIndex,\n start,\n end,\n ({ absmax, hasMinVals, height, offsetY, halfH, peaks }) => {\n if (!hasMinVals) {\n const reflectedPeaks = [];\n const len = peaks.length;\n let i;\n for (i = 0; i < len; i++) {\n reflectedPeaks[2 * i] = peaks[i];\n reflectedPeaks[2 * i + 1] = -peaks[i];\n }\n peaks = reflectedPeaks;\n }\n\n // if drawWave was called within ws.empty we don't pass a start and\n // end and simply want a flat line\n if (start !== undefined) {\n this.drawLine(peaks, absmax, halfH, offsetY, start, end);\n }\n\n // Always draw a median line\n this.fillRect(\n 0,\n halfH + offsetY - this.halfPixel,\n this.width,\n this.halfPixel\n );\n }\n );\n }\n\n /**\n * Tell the canvas entries to render their portion of the waveform\n *\n * @private\n * @param {number[]} peaks Peak data\n * @param {number} absmax Maximum peak value (absolute)\n * @param {number} halfH Half the height of the waveform\n * @param {number} offsetY Offset to the top\n * @param {number} start The x-offset of the beginning of the area that\n * should be rendered\n * @param {number} end The x-offset of the end of the area that\n * should be rendered\n */\n drawLine(peaks, absmax, halfH, offsetY, start, end) {\n this.canvases.forEach(entry => {\n this.setFillStyles(entry);\n this.drawLineToContext(\n entry,\n entry.waveCtx,\n peaks,\n absmax,\n halfH,\n offsetY,\n start,\n end\n );\n this.drawLineToContext(\n entry,\n entry.progressCtx,\n peaks,\n absmax,\n halfH,\n offsetY,\n start,\n end\n );\n });\n }\n\n /**\n * Render the actual waveform line on a canvas\n *\n * @private\n * @param {CanvasEntry} entry\n * @param {Canvas2DContextAttributes} ctx Essentially `entry.[wave|progress]Ctx`\n * @param {number[]} peaks\n * @param {number} absmax Maximum peak value (absolute)\n * @param {number} halfH Half the height of the waveform\n * @param {number} offsetY Offset to the top\n * @param {number} start The x-offset of the beginning of the area that\n * should be rendered\n * @param {number} end The x-offset of the end of the area that\n * should be rendered\n */\n drawLineToContext(entry, ctx, peaks, absmax, halfH, offsetY, start, end) {\n if (!ctx) {\n return;\n }\n\n const length = peaks.length / 2;\n const scale =\n this.params.fillParent && this.width != length\n ? this.width / length\n : 1;\n\n const first = Math.round(length * entry.start);\n // Use one more peak value to make sure we join peaks at ends -- unless,\n // of course, this is the last canvas.\n const last = Math.round(length * entry.end) + 1;\n if (first > end || last < start) {\n return;\n }\n const canvasStart = Math.min(first, start);\n const canvasEnd = Math.max(last, end);\n let i;\n let j;\n\n ctx.beginPath();\n ctx.moveTo(\n (canvasStart - first) * scale + this.halfPixel,\n halfH + offsetY\n );\n\n for (i = canvasStart; i < canvasEnd; i++) {\n const peak = peaks[2 * i] || 0;\n const h = Math.round((peak / absmax) * halfH);\n ctx.lineTo(\n (i - first) * scale + this.halfPixel,\n halfH - h + offsetY\n );\n }\n\n // Draw the bottom edge going backwards, to make a single\n // closed hull to fill.\n for (j = canvasEnd - 1; j >= canvasStart; j--) {\n const peak = peaks[2 * j + 1] || 0;\n const h = Math.round((peak / absmax) * halfH);\n ctx.lineTo(\n (j - first) * scale + this.halfPixel,\n halfH - h + offsetY\n );\n }\n\n ctx.closePath();\n ctx.fill();\n }\n\n /**\n * Draw a rectangle on the waveform\n *\n * @param {number} x\n * @param {number} y\n * @param {number} width\n * @param {number} height\n */\n fillRect(x, y, width, height) {\n const startCanvas = Math.floor(x / this.maxCanvasWidth);\n const endCanvas = Math.min(\n Math.ceil((x + width) / this.maxCanvasWidth) + 1,\n this.canvases.length\n );\n let i;\n for (i = startCanvas; i < endCanvas; i++) {\n const entry = this.canvases[i];\n const leftOffset = i * this.maxCanvasWidth;\n\n const intersection = {\n x1: Math.max(x, i * this.maxCanvasWidth),\n y1: y,\n x2: Math.min(\n x + width,\n i * this.maxCanvasWidth + entry.waveCtx.canvas.width\n ),\n y2: y + height\n };\n\n if (intersection.x1 < intersection.x2) {\n this.setFillStyles(entry);\n\n this.fillRectToContext(\n entry.waveCtx,\n intersection.x1 - leftOffset,\n intersection.y1,\n intersection.x2 - intersection.x1,\n intersection.y2 - intersection.y1\n );\n\n this.fillRectToContext(\n entry.progressCtx,\n intersection.x1 - leftOffset,\n intersection.y1,\n intersection.x2 - intersection.x1,\n intersection.y2 - intersection.y1\n );\n }\n }\n }\n\n /**\n * Performs preparation tasks and calculations which are shared by drawBars and drawWave\n *\n * @private\n * @param {number[]|number[][]} peaks Can also be an array of arrays for split channel\n * rendering\n * @param {number} channelIndex The index of the current channel. Normally\n * should be 0\n * @param {number?} start The x-offset of the beginning of the area that\n * should be rendered (If this isn't set only a flat line is rendered)\n * @param {number?} end The x-offset of the end of the area that should be\n * rendered\n * @param {function} fn The render function to call\n */\n prepareDraw(peaks, channelIndex, start, end, fn) {\n return util.frame(() => {\n // Split channels and call this function with the channelIndex set\n if (peaks[0] instanceof Array) {\n const channels = peaks;\n if (this.params.splitChannels) {\n this.setHeight(\n channels.length *\n this.params.height *\n this.params.pixelRatio\n );\n return channels.forEach((channelPeaks, i) =>\n this.prepareDraw(channelPeaks, i, start, end, fn)\n );\n }\n peaks = channels[0];\n }\n // calculate maximum modulation value, either from the barHeight\n // parameter or if normalize=true from the largest value in the peak\n // set\n let absmax = 1 / this.params.barHeight;\n if (this.params.normalize) {\n const max = util.max(peaks);\n const min = util.min(peaks);\n absmax = -min > max ? -min : max;\n }\n\n // Bar wave draws the bottom only as a reflection of the top,\n // so we don't need negative values\n const hasMinVals = [].some.call(peaks, val => val < 0);\n const height = this.params.height * this.params.pixelRatio;\n const offsetY = height * channelIndex || 0;\n const halfH = height / 2;\n\n return fn({\n absmax: absmax,\n hasMinVals: hasMinVals,\n height: height,\n offsetY: offsetY,\n halfH: halfH,\n peaks: peaks\n });\n })();\n }\n\n /**\n * Draw the actual rectangle on a canvas\n *\n * @private\n * @param {Canvas2DContextAttributes} ctx\n * @param {number} x\n * @param {number} y\n * @param {number} width\n * @param {number} height\n */\n fillRectToContext(ctx, x, y, width, height) {\n if (!ctx) {\n return;\n }\n ctx.fillRect(x, y, width, height);\n }\n\n /**\n * Set the fill styles for a certain entry (wave and progress)\n *\n * @private\n * @param {CanvasEntry} entry\n */\n setFillStyles(entry) {\n entry.waveCtx.fillStyle = this.params.waveColor;\n if (this.hasProgressCanvas) {\n entry.progressCtx.fillStyle = this.params.progressColor;\n }\n }\n\n /**\n * Return image data of the waveform\n *\n * @param {string} type='image/png' An optional value of a format type.\n * @param {number} quality=0.92 An optional value between 0 and 1.\n * @return {string|string[]} images A data URL or an array of data URLs\n */\n getImage(type, quality) {\n const images = this.canvases.map(entry =>\n entry.wave.toDataURL(type, quality)\n );\n return images.length > 1 ? images : images[0];\n }\n\n /**\n * Render the new progress\n *\n * @param {number} position X-Offset of progress position in pixels\n */\n updateProgress(position) {\n this.style(this.progressWave, { width: position + 'px' });\n }\n}\n","import * as util from './util';\n\n/**\n * Parent class for renderers\n *\n * @extends {Observer}\n */\nexport default class Drawer extends util.Observer {\n /**\n * @param {HTMLElement} container The container node of the wavesurfer instance\n * @param {WavesurferParams} params The wavesurfer initialisation options\n */\n constructor(container, params) {\n super();\n /** @private */\n this.container = container;\n /**\n * @type {WavesurferParams}\n * @private\n */\n this.params = params;\n /**\n * The width of the renderer\n * @type {number}\n */\n this.width = 0;\n /**\n * The height of the renderer\n * @type {number}\n */\n this.height = params.height * this.params.pixelRatio;\n /** @private */\n this.lastPos = 0;\n /**\n * The `` element which is added to the container\n * @type {HTMLElement}\n */\n this.wrapper = null;\n }\n\n /**\n * Alias of `util.style`\n *\n * @param {HTMLElement} el The element that the styles will be applied to\n * @param {Object} styles The map of propName: attribute, both are used as-is\n * @return {HTMLElement} el\n */\n style(el, styles) {\n return util.style(el, styles);\n }\n\n /**\n * Create the wrapper `` element, style it and set up the events for\n * interaction\n */\n createWrapper() {\n this.wrapper = this.container.appendChild(\n document.createElement('wave')\n );\n\n this.style(this.wrapper, {\n display: 'block',\n position: 'relative',\n userSelect: 'none',\n webkitUserSelect: 'none',\n height: this.params.height + 'px'\n });\n\n if (this.params.fillParent || this.params.scrollParent) {\n this.style(this.wrapper, {\n width: '100%',\n overflowX: this.params.hideScrollbar ? 'hidden' : 'auto',\n overflowY: 'hidden'\n });\n }\n\n this.setupWrapperEvents();\n }\n\n /**\n * Handle click event\n *\n * @param {Event} e Click event\n * @param {?boolean} noPrevent Set to true to not call `e.preventDefault()`\n * @return {number} Playback position from 0 to 1\n */\n handleEvent(e, noPrevent) {\n !noPrevent && e.preventDefault();\n\n const clientX = e.targetTouches\n ? e.targetTouches[0].clientX\n : e.clientX;\n const bbox = this.wrapper.getBoundingClientRect();\n\n const nominalWidth = this.width;\n const parentWidth = this.getWidth();\n\n let progress;\n\n if (!this.params.fillParent && nominalWidth < parentWidth) {\n progress =\n (clientX - bbox.left) *\n (this.params.pixelRatio / nominalWidth) || 0;\n\n if (progress > 1) {\n progress = 1;\n }\n } else {\n progress =\n (clientX - bbox.left + this.wrapper.scrollLeft) /\n this.wrapper.scrollWidth || 0;\n }\n\n return progress;\n }\n\n /**\n * @private\n */\n setupWrapperEvents() {\n this.wrapper.addEventListener('click', e => {\n const scrollbarHeight =\n this.wrapper.offsetHeight - this.wrapper.clientHeight;\n if (scrollbarHeight != 0) {\n // scrollbar is visible. Check if click was on it\n const bbox = this.wrapper.getBoundingClientRect();\n if (e.clientY >= bbox.bottom - scrollbarHeight) {\n // ignore mousedown as it was on the scrollbar\n return;\n }\n }\n\n if (this.params.interact) {\n this.fireEvent('click', e, this.handleEvent(e));\n }\n });\n\n this.wrapper.addEventListener('scroll', e =>\n this.fireEvent('scroll', e)\n );\n }\n\n /**\n * Draw peaks on the canvas\n *\n * @param {number[]|number[][]} peaks Can also be an array of arrays for split channel\n * rendering\n * @param {number} length The width of the area that should be drawn\n * @param {number} start The x-offset of the beginning of the area that\n * should be rendered\n * @param {number} end The x-offset of the end of the area that should be\n * rendered\n */\n drawPeaks(peaks, length, start, end) {\n if (!this.setWidth(length)) {\n this.clearWave();\n }\n\n this.params.barWidth\n ? this.drawBars(peaks, 0, start, end)\n : this.drawWave(peaks, 0, start, end);\n }\n\n /**\n * Scroll to the beginning\n */\n resetScroll() {\n if (this.wrapper !== null) {\n this.wrapper.scrollLeft = 0;\n }\n }\n\n /**\n * Recenter the view-port at a certain percent of the waveform\n *\n * @param {number} percent Value from 0 to 1 on the waveform\n */\n recenter(percent) {\n const position = this.wrapper.scrollWidth * percent;\n this.recenterOnPosition(position, true);\n }\n\n /**\n * Recenter the view-port on a position, either scroll there immediately or\n * in steps of 5 pixels\n *\n * @param {number} position X-offset in pixels\n * @param {boolean} immediate Set to true to immediately scroll somewhere\n */\n recenterOnPosition(position, immediate) {\n const scrollLeft = this.wrapper.scrollLeft;\n const half = ~~(this.wrapper.clientWidth / 2);\n const maxScroll = this.wrapper.scrollWidth - this.wrapper.clientWidth;\n let target = position - half;\n let offset = target - scrollLeft;\n\n if (maxScroll == 0) {\n // no need to continue if scrollbar is not there\n return;\n }\n\n // if the cursor is currently visible...\n if (!immediate && -half <= offset && offset < half) {\n // we'll limit the \"re-center\" rate.\n const rate = 5;\n offset = Math.max(-rate, Math.min(rate, offset));\n target = scrollLeft + offset;\n }\n\n // limit target to valid range (0 to maxScroll)\n target = Math.max(0, Math.min(maxScroll, target));\n // no use attempting to scroll if we're not moving\n if (target != scrollLeft) {\n this.wrapper.scrollLeft = target;\n }\n }\n\n /**\n * Get the current scroll position in pixels\n *\n * @return {number}\n */\n getScrollX() {\n const pixelRatio = this.params.pixelRatio;\n let x = Math.round(this.wrapper.scrollLeft * pixelRatio);\n\n // In cases of elastic scroll (safari with mouse wheel) you can\n // scroll beyond the limits of the container\n // Calculate and floor the scrollable extent to make sure an out\n // of bounds value is not returned\n // Ticket #1312\n if (this.params.scrollParent) {\n const maxScroll = ~~(\n this.wrapper.scrollWidth * pixelRatio -\n this.getWidth()\n );\n x = Math.min(maxScroll, Math.max(0, x));\n }\n\n return x;\n }\n\n /**\n * Get the width of the container\n *\n * @return {number}\n */\n getWidth() {\n return Math.round(this.container.clientWidth * this.params.pixelRatio);\n }\n\n /**\n * Set the width of the container\n *\n * @param {number} width\n */\n setWidth(width) {\n if (this.width == width) {\n return false;\n }\n\n this.width = width;\n\n if (this.params.fillParent || this.params.scrollParent) {\n this.style(this.wrapper, {\n width: ''\n });\n } else {\n this.style(this.wrapper, {\n width: ~~(this.width / this.params.pixelRatio) + 'px'\n });\n }\n\n this.updateSize();\n return true;\n }\n\n /**\n * Set the height of the container\n *\n * @param {number} height\n */\n setHeight(height) {\n if (height == this.height) {\n return false;\n }\n this.height = height;\n\n this.style(this.wrapper, {\n height: ~~(this.height / this.params.pixelRatio) + 'px'\n });\n\n this.updateSize();\n return true;\n }\n\n /**\n * Called by wavesurfer when progress should be rendered\n *\n * @param {number} progress From 0 to 1\n */\n progress(progress) {\n const minPxDelta = 1 / this.params.pixelRatio;\n const pos = Math.round(progress * this.width) * minPxDelta;\n\n if (pos < this.lastPos || pos - this.lastPos >= minPxDelta) {\n this.lastPos = pos;\n\n if (this.params.scrollParent && this.params.autoCenter) {\n const newPos = ~~(this.wrapper.scrollWidth * progress);\n this.recenterOnPosition(newPos);\n }\n\n this.updateProgress(pos);\n }\n }\n\n /**\n * This is called when wavesurfer is destroyed\n */\n destroy() {\n this.unAll();\n if (this.wrapper) {\n if (this.wrapper.parentNode == this.container) {\n this.container.removeChild(this.wrapper);\n }\n this.wrapper = null;\n }\n }\n\n /* Renderer-specific methods */\n\n /**\n * Called after cursor related params have changed.\n *\n * @abstract\n */\n updateCursor() {}\n\n /**\n * Called when the size of the container changes so the renderer can adjust\n *\n * @abstract\n */\n updateSize() {}\n\n /**\n * Draw a waveform with bars\n *\n * @abstract\n * @param {number[]|number[][]} peaks Can also be an array of arrays for split channel\n * rendering\n * @param {number} channelIndex The index of the current channel. Normally\n * should be 0\n * @param {number} start The x-offset of the beginning of the area that\n * should be rendered\n * @param {number} end The x-offset of the end of the area that should be\n * rendered\n */\n drawBars(peaks, channelIndex, start, end) {}\n\n /**\n * Draw a waveform\n *\n * @abstract\n * @param {number[]|number[][]} peaks Can also be an array of arrays for split channel\n * rendering\n * @param {number} channelIndex The index of the current channel. Normally\n * should be 0\n * @param {number} start The x-offset of the beginning of the area that\n * should be rendered\n * @param {number} end The x-offset of the end of the area that should be\n * rendered\n */\n drawWave(peaks, channelIndex, start, end) {}\n\n /**\n * Clear the waveform\n *\n * @abstract\n */\n clearWave() {}\n\n /**\n * Render the new progress\n *\n * @abstract\n * @param {number} position X-Offset of progress position in pixels\n */\n updateProgress(position) {}\n}\n","import WebAudio from './webaudio';\nimport * as util from './util';\n\n/**\n * MediaElement backend\n */\nexport default class MediaElement extends WebAudio {\n /**\n * Construct the backend\n *\n * @param {WavesurferParams} params\n */\n constructor(params) {\n super(params);\n /** @private */\n this.params = params;\n\n // Dummy media to catch errors\n /** @private */\n this.media = {\n currentTime: 0,\n duration: 0,\n paused: true,\n playbackRate: 1,\n play() {},\n pause() {},\n volume: 0\n };\n\n /** @private */\n this.mediaType = params.mediaType.toLowerCase();\n /** @private */\n this.elementPosition = params.elementPosition;\n /** @private */\n this.peaks = null;\n /** @private */\n this.playbackRate = 1;\n /** @private */\n this.volume = 1;\n /** @private */\n this.buffer = null;\n /** @private */\n this.onPlayEnd = null;\n }\n\n /**\n * Initialise the backend, called in `wavesurfer.createBackend()`\n */\n init() {\n this.setPlaybackRate(this.params.audioRate);\n this.createTimer();\n }\n\n /**\n * Create a timer to provide a more precise `audioprocess` event.\n *\n * @private\n */\n createTimer() {\n const onAudioProcess = () => {\n if (this.isPaused()) {\n return;\n }\n this.fireEvent('audioprocess', this.getCurrentTime());\n\n // Call again in the next frame\n const requestAnimationFrame =\n window.requestAnimationFrame ||\n window.webkitRequestAnimationFrame;\n requestAnimationFrame(onAudioProcess);\n };\n\n this.on('play', onAudioProcess);\n\n // Update the progress one more time to prevent it from being stuck in\n // case of lower framerates\n this.on('pause', () => {\n this.fireEvent('audioprocess', this.getCurrentTime());\n });\n }\n\n /**\n * Create media element with url as its source,\n * and append to container element.\n *\n * @param {string} url Path to media file\n * @param {HTMLElement} container HTML element\n * @param {number[]|number[][]} peaks Array of peak data\n * @param {string} preload HTML 5 preload attribute value\n */\n load(url, container, peaks, preload) {\n const media = document.createElement(this.mediaType);\n media.controls = this.params.mediaControls;\n media.autoplay = this.params.autoplay || false;\n media.preload = preload == null ? 'auto' : preload;\n media.src = url;\n media.style.width = '100%';\n\n const prevMedia = container.querySelector(this.mediaType);\n if (prevMedia) {\n container.removeChild(prevMedia);\n }\n container.appendChild(media);\n\n this._load(media, peaks);\n }\n\n /**\n * Load existing media element.\n *\n * @param {HTMLMediaElement} elt HTML5 Audio or Video element\n * @param {number[]|number[][]} peaks Array of peak data\n */\n loadElt(elt, peaks) {\n elt.controls = this.params.mediaControls;\n elt.autoplay = this.params.autoplay || false;\n\n this._load(elt, peaks);\n }\n\n /**\n * Private method called by both load (from url)\n * and loadElt (existing media element).\n *\n * @param {HTMLMediaElement} media HTML5 Audio or Video element\n * @param {number[]|number[][]} peaks Array of peak data\n * @private\n */\n _load(media, peaks) {\n // load must be called manually on iOS, otherwise peaks won't draw\n // until a user interaction triggers load --> 'ready' event\n if (typeof media.load == 'function') {\n // Resets the media element and restarts the media resource. Any\n // pending events are discarded. How much media data is fetched is\n // still affected by the preload attribute.\n media.load();\n }\n\n media.addEventListener('error', () => {\n this.fireEvent('error', 'Error loading media element');\n });\n\n media.addEventListener('canplay', () => {\n this.fireEvent('canplay');\n });\n\n media.addEventListener('ended', () => {\n this.fireEvent('finish');\n });\n\n // Listen to and relay play and pause events to enable\n // playback control from the external media element\n media.addEventListener('play', () => {\n this.fireEvent('play');\n });\n\n media.addEventListener('pause', () => {\n this.fireEvent('pause');\n });\n\n this.media = media;\n this.peaks = peaks;\n this.onPlayEnd = null;\n this.buffer = null;\n this.setPlaybackRate(this.playbackRate);\n this.setVolume(this.volume);\n }\n\n /**\n * Used by `wavesurfer.isPlaying()` and `wavesurfer.playPause()`\n *\n * @return {boolean}\n */\n isPaused() {\n return !this.media || this.media.paused;\n }\n\n /**\n * Used by `wavesurfer.getDuration()`\n *\n * @return {number}\n */\n getDuration() {\n if (this.explicitDuration) {\n return this.explicitDuration;\n }\n let duration = (this.buffer || this.media).duration;\n if (duration >= Infinity) {\n // streaming audio\n duration = this.media.seekable.end(0);\n }\n return duration;\n }\n\n /**\n * Returns the current time in seconds relative to the audio-clip's\n * duration.\n *\n * @return {number}\n */\n getCurrentTime() {\n return this.media && this.media.currentTime;\n }\n\n /**\n * Get the position from 0 to 1\n *\n * @return {number}\n */\n getPlayedPercents() {\n return this.getCurrentTime() / this.getDuration() || 0;\n }\n\n /**\n * Get the audio source playback rate.\n *\n * @return {number}\n */\n getPlaybackRate() {\n return this.playbackRate || this.media.playbackRate;\n }\n\n /**\n * Set the audio source playback rate.\n *\n * @param {number} value\n */\n setPlaybackRate(value) {\n this.playbackRate = value || 1;\n this.media.playbackRate = this.playbackRate;\n }\n\n /**\n * Used by `wavesurfer.seekTo()`\n *\n * @param {number} start Position to start at in seconds\n */\n seekTo(start) {\n if (start != null) {\n this.media.currentTime = start;\n }\n this.clearPlayEnd();\n }\n\n /**\n * Plays the loaded audio region.\n *\n * @param {number} start Start offset in seconds, relative to the beginning\n * of a clip.\n * @param {number} end When to stop, relative to the beginning of a clip.\n * @emits MediaElement#play\n * @return {Promise}\n */\n play(start, end) {\n this.seekTo(start);\n const promise = this.media.play();\n end && this.setPlayEnd(end);\n\n return promise;\n }\n\n /**\n * Pauses the loaded audio.\n *\n * @emits MediaElement#pause\n * @return {Promise}\n */\n pause() {\n let promise;\n\n if (this.media) {\n promise = this.media.pause();\n }\n this.clearPlayEnd();\n\n return promise;\n }\n\n /** @private */\n setPlayEnd(end) {\n this._onPlayEnd = time => {\n if (time >= end) {\n this.pause();\n this.seekTo(end);\n }\n };\n this.on('audioprocess', this._onPlayEnd);\n }\n\n /** @private */\n clearPlayEnd() {\n if (this._onPlayEnd) {\n this.un('audioprocess', this._onPlayEnd);\n this._onPlayEnd = null;\n }\n }\n\n /**\n * Compute the max and min value of the waveform when broken into\n * subranges.\n *\n * @param {number} length How many subranges to break the waveform into.\n * @param {number} first First sample in the required range.\n * @param {number} last Last sample in the required range.\n * @return {number[]|number[][]} Array of 2* peaks or array of\n * arrays of peaks consisting of (max, min) values for each subrange.\n */\n getPeaks(length, first, last) {\n if (this.buffer) {\n return super.getPeaks(length, first, last);\n }\n return this.peaks || [];\n }\n\n /**\n * Set the sink id for the media player\n *\n * @param {string} deviceId String value representing audio device id.\n */\n setSinkId(deviceId) {\n if (deviceId) {\n if (!this.media.setSinkId) {\n return Promise.reject(\n new Error('setSinkId is not supported in your browser')\n );\n }\n return this.media.setSinkId(deviceId);\n }\n\n return Promise.reject(new Error('Invalid deviceId: ' + deviceId));\n }\n\n /**\n * Get the current volume\n *\n * @return {number} value A floating point value between 0 and 1.\n */\n getVolume() {\n return this.volume || this.media.volume;\n }\n\n /**\n * Set the audio volume\n *\n * @param {number} value A floating point value between 0 and 1.\n */\n setVolume(value) {\n this.volume = value;\n this.media.volume = this.volume;\n }\n\n /**\n * This is called when wavesurfer is destroyed\n *\n */\n destroy() {\n this.pause();\n this.unAll();\n\n if (\n this.params.removeMediaElementOnDestroy &&\n this.media &&\n this.media.parentNode\n ) {\n this.media.parentNode.removeChild(this.media);\n }\n\n this.media = null;\n }\n}\n","/**\n * Caches the decoded peaks data to improve rendering speed for large audio\n *\n * Is used if the option parameter `partialRender` is set to `true`\n */\nexport default class PeakCache {\n /**\n * Instantiate cache\n */\n constructor() {\n this.clearPeakCache();\n }\n\n /**\n * Empty the cache\n */\n clearPeakCache() {\n /**\n * Flat array with entries that are always in pairs to mark the\n * beginning and end of each subrange. This is a convenience so we can\n * iterate over the pairs for easy set difference operations.\n * @private\n */\n this.peakCacheRanges = [];\n /**\n * Length of the entire cachable region, used for resetting the cache\n * when this changes (zoom events, for instance).\n * @private\n */\n this.peakCacheLength = -1;\n }\n\n /**\n * Add a range of peaks to the cache\n *\n * @param {number} length The length of the range\n * @param {number} start The x offset of the start of the range\n * @param {number} end The x offset of the end of the range\n * @return {number[][]}\n */\n addRangeToPeakCache(length, start, end) {\n if (length != this.peakCacheLength) {\n this.clearPeakCache();\n this.peakCacheLength = length;\n }\n\n // Return ranges that weren't in the cache before the call.\n let uncachedRanges = [];\n let i = 0;\n // Skip ranges before the current start.\n while (\n i < this.peakCacheRanges.length &&\n this.peakCacheRanges[i] < start\n ) {\n i++;\n }\n // If |i| is even, |start| falls after an existing range. Otherwise,\n // |start| falls between an existing range, and the uncached region\n // starts when we encounter the next node in |peakCacheRanges| or\n // |end|, whichever comes first.\n if (i % 2 == 0) {\n uncachedRanges.push(start);\n }\n while (\n i < this.peakCacheRanges.length &&\n this.peakCacheRanges[i] <= end\n ) {\n uncachedRanges.push(this.peakCacheRanges[i]);\n i++;\n }\n // If |i| is even, |end| is after all existing ranges.\n if (i % 2 == 0) {\n uncachedRanges.push(end);\n }\n\n // Filter out the 0-length ranges.\n uncachedRanges = uncachedRanges.filter((item, pos, arr) => {\n if (pos == 0) {\n return item != arr[pos + 1];\n } else if (pos == arr.length - 1) {\n return item != arr[pos - 1];\n }\n return item != arr[pos - 1] && item != arr[pos + 1];\n });\n\n // Merge the two ranges together, uncachedRanges will either contain\n // wholly new points, or duplicates of points in peakCacheRanges. If\n // duplicates are detected, remove both and extend the range.\n this.peakCacheRanges = this.peakCacheRanges.concat(uncachedRanges);\n this.peakCacheRanges = this.peakCacheRanges\n .sort((a, b) => a - b)\n .filter((item, pos, arr) => {\n if (pos == 0) {\n return item != arr[pos + 1];\n } else if (pos == arr.length - 1) {\n return item != arr[pos - 1];\n }\n return item != arr[pos - 1] && item != arr[pos + 1];\n });\n\n // Push the uncached ranges into an array of arrays for ease of\n // iteration in the functions that call this.\n const uncachedRangePairs = [];\n for (i = 0; i < uncachedRanges.length; i += 2) {\n uncachedRangePairs.push([uncachedRanges[i], uncachedRanges[i + 1]]);\n }\n\n return uncachedRangePairs;\n }\n\n /**\n * For testing\n *\n * @return {number[][]}\n */\n getCacheRanges() {\n const peakCacheRangePairs = [];\n let i;\n for (i = 0; i < this.peakCacheRanges.length; i += 2) {\n peakCacheRangePairs.push([\n this.peakCacheRanges[i],\n this.peakCacheRanges[i + 1]\n ]);\n }\n return peakCacheRangePairs;\n }\n}\n"],"sourceRoot":""}