{"version":3,"file":"wavesurfer.min.js","mappings":"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","sources":["webpack://WaveSurfer/webpack/universalModuleDefinition","webpack://WaveSurfer/./src/drawer.canvasentry.js","webpack://WaveSurfer/./src/drawer.js","webpack://WaveSurfer/./src/drawer.multicanvas.js","webpack://WaveSurfer/./src/mediaelement-webaudio.js","webpack://WaveSurfer/./src/mediaelement.js","webpack://WaveSurfer/./src/peakcache.js","webpack://WaveSurfer/./src/util/absMax.js","webpack://WaveSurfer/./src/util/clamp.js","webpack://WaveSurfer/./src/util/fetch.js","webpack://WaveSurfer/./src/util/frame.js","webpack://WaveSurfer/./src/util/get-id.js","webpack://WaveSurfer/./src/util/index.js","webpack://WaveSurfer/./src/util/max.js","webpack://WaveSurfer/./src/util/min.js","webpack://WaveSurfer/./src/util/observer.js","webpack://WaveSurfer/./src/util/orientation.js","webpack://WaveSurfer/./src/util/prevent-click.js","webpack://WaveSurfer/./src/util/request-animation-frame.js","webpack://WaveSurfer/./src/util/silence-mode.js","webpack://WaveSurfer/./src/util/style.js","webpack://WaveSurfer/./src/wavesurfer.js","webpack://WaveSurfer/./src/webaudio.js","webpack://WaveSurfer/./node_modules/debounce/index.js","webpack://WaveSurfer/webpack/bootstrap","webpack://WaveSurfer/webpack/startup"],"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})(self, () => {\nreturn ","/**\n * @since 3.0.0\n */\n\nimport style from './util/style';\nimport getId from './util/get-id';\n\n/**\n * The `CanvasEntry` class represents an element consisting of a wave `canvas`\n * and an (optional) progress wave `canvas`.\n *\n * The `MultiCanvas` renderer uses one or more `CanvasEntry` instances to\n * render a waveform, depending on the zoom level.\n */\nexport default class CanvasEntry {\n    constructor() {\n        /**\n         * The wave node\n         *\n         * @type {HTMLCanvasElement}\n         */\n        this.wave = null;\n        /**\n         * The wave canvas rendering context\n         *\n         * @type {CanvasRenderingContext2D}\n         */\n        this.waveCtx = null;\n        /**\n         * The (optional) progress wave node\n         *\n         * @type {HTMLCanvasElement}\n         */\n        this.progress = null;\n        /**\n         * The (optional) progress wave canvas rendering context\n         *\n         * @type {CanvasRenderingContext2D}\n         */\n        this.progressCtx = null;\n        /**\n         * Start of the area the canvas should render, between 0 and 1\n         *\n         * @type {number}\n         */\n        this.start = 0;\n        /**\n         * End of the area the canvas should render, between 0 and 1\n         *\n         * @type {number}\n         */\n        this.end = 1;\n        /**\n         * Unique identifier for this entry\n         *\n         * @type {string}\n         */\n        this.id = getId(\n            typeof this.constructor.name !== 'undefined'\n                ? this.constructor.name.toLowerCase() + '_'\n                : 'canvasentry_'\n        );\n        /**\n         * Canvas 2d context attributes\n         *\n         * @type {object}\n         */\n        this.canvasContextAttributes = {};\n    }\n\n    /**\n     * Store the wave canvas element and create the 2D rendering context\n     *\n     * @param {HTMLCanvasElement} element The wave `canvas` element.\n     */\n    initWave(element) {\n        this.wave = element;\n        this.waveCtx = this.wave.getContext('2d', this.canvasContextAttributes);\n    }\n\n    /**\n     * Store the progress wave canvas element and create the 2D rendering\n     * context\n     *\n     * @param {HTMLCanvasElement} element The progress wave `canvas` element.\n     */\n    initProgress(element) {\n        this.progress = element;\n        this.progressCtx = this.progress.getContext(\n            '2d',\n            this.canvasContextAttributes\n        );\n    }\n\n    /**\n     * Update the dimensions\n     *\n     * @param {number} elementWidth Width of the entry\n     * @param {number} totalWidth Total width of the multi canvas renderer\n     * @param {number} width The new width of the element\n     * @param {number} height The new height of the element\n     */\n    updateDimensions(elementWidth, totalWidth, width, height) {\n        // where the canvas starts and ends in the waveform, represented as a\n        // decimal between 0 and 1\n        this.start = this.wave.offsetLeft / totalWidth || 0;\n        this.end = this.start + elementWidth / totalWidth;\n\n        // set wave canvas dimensions\n        this.wave.width = width;\n        this.wave.height = height;\n        let elementSize = { width: elementWidth + 'px' };\n        style(this.wave, elementSize);\n\n        if (this.hasProgressCanvas) {\n            // set progress canvas dimensions\n            this.progress.width = width;\n            this.progress.height = height;\n            style(this.progress, elementSize);\n        }\n    }\n\n    /**\n     * Clear the wave and progress rendering contexts\n     */\n    clearWave() {\n        // wave\n        this.waveCtx.clearRect(\n            0,\n            0,\n            this.waveCtx.canvas.width,\n            this.waveCtx.canvas.height\n        );\n\n        // progress\n        if (this.hasProgressCanvas) {\n            this.progressCtx.clearRect(\n                0,\n                0,\n                this.progressCtx.canvas.width,\n                this.progressCtx.canvas.height\n            );\n        }\n    }\n\n    /**\n     * Set the fill styles for wave and progress\n     * @param {string|string[]} waveColor Fill color for the wave canvas,\n     * or an array of colors to apply as a gradient\n     * @param {?string|string[]} progressColor Fill color for the progress canvas,\n     * or an array of colors to apply as a gradient\n     */\n    setFillStyles(waveColor, progressColor) {\n        this.waveCtx.fillStyle = this.getFillStyle(this.waveCtx, waveColor);\n\n        if (this.hasProgressCanvas) {\n            this.progressCtx.fillStyle = this.getFillStyle(this.progressCtx, progressColor);\n        }\n    }\n\n    /**\n     * Utility function to handle wave color arguments\n     *\n     * When the color argument type is a string or CanvasGradient instance,\n     * it will be returned as is. Otherwise, it will be treated as an array,\n     * and a new CanvasGradient will be returned\n     *\n     * @since 6.0.0\n     * @param {CanvasRenderingContext2D} ctx Rendering context of target canvas\n     * @param {string|string[]|CanvasGradient} color Either a single fill color\n     *     for the wave canvas, an existing CanvasGradient instance, or an array\n     *     of colors to apply as a gradient\n     * @returns {string|CanvasGradient} Returns a string fillstyle value, or a\n     *     canvas gradient\n     */\n    getFillStyle(ctx, color) {\n        if (typeof color == 'string' || color instanceof CanvasGradient) {\n            return color;\n        }\n\n        const waveGradient = ctx.createLinearGradient(0, 0, 0, ctx.canvas.height);\n        color.forEach((value, index) => waveGradient.addColorStop((index / color.length), value));\n\n        return waveGradient;\n    }\n\n    /**\n     * Set the canvas transforms for wave and progress\n     *\n     * @param {boolean} vertical Whether to render vertically\n     */\n    applyCanvasTransforms(vertical) {\n        if (vertical) {\n            // Reflect the waveform across the line y = -x\n            this.waveCtx.setTransform(0, 1, 1, 0, 0, 0);\n\n            if (this.hasProgressCanvas) {\n                this.progressCtx.setTransform(0, 1, 1, 0, 0, 0);\n            }\n        }\n    }\n\n    /**\n     * Draw a rectangle for wave and progress\n     *\n     * @param {number} x X start position\n     * @param {number} y Y start position\n     * @param {number} width Width of the rectangle\n     * @param {number} height Height of the rectangle\n     * @param {number} radius Radius of the rectangle\n     */\n    fillRects(x, y, width, height, radius) {\n        this.fillRectToContext(this.waveCtx, x, y, width, height, radius);\n\n        if (this.hasProgressCanvas) {\n            this.fillRectToContext(\n                this.progressCtx,\n                x,\n                y,\n                width,\n                height,\n                radius\n            );\n        }\n    }\n\n    /**\n     * Draw the actual rectangle on a `canvas` element\n     *\n     * @param {CanvasRenderingContext2D} ctx Rendering context of target canvas\n     * @param {number} x X start position\n     * @param {number} y Y start position\n     * @param {number} width Width of the rectangle\n     * @param {number} height Height of the rectangle\n     * @param {number} radius Radius of the rectangle\n     */\n    fillRectToContext(ctx, x, y, width, height, radius) {\n        if (!ctx) {\n            return;\n        }\n\n        if (radius) {\n            this.drawRoundedRect(ctx, x, y, width, height, radius);\n        } else {\n            ctx.fillRect(x, y, width, height);\n        }\n    }\n\n    /**\n     * Draw a rounded rectangle on Canvas\n     *\n     * @param {CanvasRenderingContext2D} ctx Canvas context\n     * @param {number} x X-position of the rectangle\n     * @param {number} y Y-position of the rectangle\n     * @param {number} width Width of the rectangle\n     * @param {number} height Height of the rectangle\n     * @param {number} radius Radius of the rectangle\n     *\n     * @return {void}\n     * @example drawRoundedRect(ctx, 50, 50, 5, 10, 3)\n     */\n    drawRoundedRect(ctx, x, y, width, height, radius) {\n        if (height === 0) {\n            return;\n        }\n        // peaks are float values from -1 to 1. Use absolute height values in\n        // order to correctly calculate rounded rectangle coordinates\n        if (height < 0) {\n            height *= -1;\n            y -= height;\n        }\n        ctx.beginPath();\n        ctx.moveTo(x + radius, y);\n        ctx.lineTo(x + width - radius, y);\n        ctx.quadraticCurveTo(x + width, y, x + width, y + radius);\n        ctx.lineTo(x + width, y + height - radius);\n        ctx.quadraticCurveTo(\n            x + width,\n            y + height,\n            x + width - radius,\n            y + height\n        );\n        ctx.lineTo(x + radius, y + height);\n        ctx.quadraticCurveTo(x, y + height, x, y + height - radius);\n        ctx.lineTo(x, y + radius);\n        ctx.quadraticCurveTo(x, y, x + radius, y);\n        ctx.closePath();\n        ctx.fill();\n    }\n\n    /**\n     * Render the actual wave and progress lines\n     *\n     * @param {number[]} peaks Array with peaks 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    drawLines(peaks, absmax, halfH, offsetY, start, end) {\n        this.drawLineToContext(\n            this.waveCtx,\n            peaks,\n            absmax,\n            halfH,\n            offsetY,\n            start,\n            end\n        );\n\n        if (this.hasProgressCanvas) {\n            this.drawLineToContext(\n                this.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` element\n     *\n     * @param {CanvasRenderingContext2D} ctx Rendering context of target canvas\n     * @param {number[]} peaks Array with peaks 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    drawLineToContext(ctx, peaks, absmax, halfH, offsetY, start, end) {\n        if (!ctx) {\n            return;\n        }\n\n        const length = peaks.length / 2;\n        const first = Math.round(length * this.start);\n\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 * this.end) + 1;\n\n        const canvasStart = first;\n        const canvasEnd = last;\n        const scale = this.wave.width / (canvasEnd - canvasStart - 1);\n\n        // optimization\n        const halfOffset = halfH + offsetY;\n        const absmaxHalf = absmax / halfH;\n\n        ctx.beginPath();\n        ctx.moveTo((canvasStart - first) * scale, halfOffset);\n\n        ctx.lineTo(\n            (canvasStart - first) * scale,\n            halfOffset - Math.round((peaks[2 * canvasStart] || 0) / absmaxHalf)\n        );\n\n        let i, peak, h;\n        for (i = canvasStart; i < canvasEnd; i++) {\n            peak = peaks[2 * i] || 0;\n            h = Math.round(peak / absmaxHalf);\n            ctx.lineTo((i - first) * scale + this.halfPixel, halfOffset - h);\n        }\n\n        // draw the bottom edge going backwards, to make a single\n        // closed hull to fill\n        let j = canvasEnd - 1;\n        for (j; j >= canvasStart; j--) {\n            peak = peaks[2 * j + 1] || 0;\n            h = Math.round(peak / absmaxHalf);\n            ctx.lineTo((j - first) * scale + this.halfPixel, halfOffset - h);\n        }\n\n        ctx.lineTo(\n            (canvasStart - first) * scale,\n            halfOffset -\n            Math.round((peaks[2 * canvasStart + 1] || 0) / absmaxHalf)\n        );\n\n        ctx.closePath();\n        ctx.fill();\n    }\n\n    /**\n     * Destroys this entry\n     */\n    destroy() {\n        this.waveCtx = null;\n        this.wave = null;\n\n        this.progressCtx = null;\n        this.progress = null;\n    }\n\n    /**\n     * Return image data of the wave `canvas` element\n     *\n     * When using a `type` of `'blob'`, this will return a `Promise` that\n     * resolves with a `Blob` instance.\n     *\n     * @param {string} format='image/png' An optional value of a format type.\n     * @param {number} quality=0.92 An optional value between 0 and 1.\n     * @param {string} type='dataURL' Either 'dataURL' or 'blob'.\n     * @return {string|Promise} When using the default `'dataURL'` `type` this\n     * returns a data URL. When using the `'blob'` `type` this returns a\n     * `Promise` that resolves with a `Blob` instance.\n     */\n    getImage(format, quality, type) {\n        if (type === 'blob') {\n            return new Promise(resolve => {\n                this.wave.toBlob(resolve, format, quality);\n            });\n        } else if (type === 'dataURL') {\n            return this.wave.toDataURL(format, quality);\n        }\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\n        this.container = util.withOrientation(container, params.vertical);\n        /**\n         * @type {WavesurferParams}\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\n        this.lastPos = 0;\n        /**\n         * The `<wave>` 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 `<wave>` element, style it and set up the events for\n     * interaction\n     */\n    createWrapper() {\n        this.wrapper = util.withOrientation(\n            this.container.appendChild(document.createElement('wave')),\n            this.params.vertical\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                cursor: this.params.hideCursor ? 'none' : 'auto',\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 = util.withOrientation(\n            e.targetTouches ? e.targetTouches[0] : e,\n            this.params.vertical\n        ).clientX;\n        const bbox = this.wrapper.getBoundingClientRect();\n\n        const nominalWidth = this.width;\n        const parentWidth = this.getWidth();\n        const progressPixels = this.getProgressPixels(bbox, clientX);\n\n        let progress;\n        if (!this.params.fillParent && nominalWidth < parentWidth) {\n            progress = progressPixels *\n                (this.params.pixelRatio / nominalWidth) || 0;\n        } else {\n            progress = (progressPixels + this.wrapper.scrollLeft) /\n                this.wrapper.scrollWidth || 0;\n        }\n\n        return util.clamp(progress, 0, 1);\n    }\n\n    getProgressPixels(wrapperBbox, clientX) {\n        if (this.params.rtl) {\n            return wrapperBbox.right - clientX;\n        } else {\n            return clientX - wrapperBbox.left;\n        }\n    }\n\n    setupWrapperEvents() {\n        this.wrapper.addEventListener('click', e => {\n            const orientedEvent = util.withOrientation(e, this.params.vertical);\n            const scrollbarHeight = this.wrapper.offsetHeight -\n                  this.wrapper.clientHeight;\n\n            if (scrollbarHeight !== 0) {\n                // scrollbar is visible.  Check if click was on it\n                const bbox = this.wrapper.getBoundingClientRect();\n                if (orientedEvent.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('dblclick', e => {\n            if (this.params.interact) {\n                this.fireEvent('dblclick', 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.<Array[]>} peaks Can also be an array of arrays\n     * for split channel 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            // set rate at which waveform is centered\n            let rate = this.params.autoCenterRate;\n\n            // make rate depend on width of view and length of waveform\n            rate /= half;\n            rate *= maxScroll;\n\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} Horizontal scroll position in pixels\n     */\n    getScrollX() {\n        let x = 0;\n        if (this.wrapper) {\n            const pixelRatio = this.params.pixelRatio;\n            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} The width of the container\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 The new width of the container\n     * @return {boolean} Whether the width of the container was updated or not\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            const newWidth = ~~(this.width / this.params.pixelRatio) + 'px';\n            this.style(this.wrapper, {\n                width: newWidth\n            });\n        }\n\n        this.updateSize();\n        return true;\n    }\n\n    /**\n     * Set the height of the container\n     *\n     * @param {number} height The new height of the container.\n     * @return {boolean} Whether the height of the container was updated or not\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(\n                    newPos,\n                    this.params.autoCenterImmediately\n                );\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.domElement) {\n                this.container.removeChild(this.wrapper.domElement);\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.<Array[]>} 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.<Array[]>} 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 Drawer from './drawer';\nimport * as util from './util';\nimport CanvasEntry from './drawer.canvasentry';\n\n/**\n * MultiCanvas renderer for wavesurfer. Is currently the default and sole\n * builtin renderer.\n *\n * A `MultiCanvas` consists of one or more `CanvasEntry` instances, depending\n * on the zoom level.\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        /**\n         * @type {number}\n         */\n        this.maxCanvasWidth = params.maxCanvasWidth;\n\n        /**\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         *\n         * @type {boolean}\n         */\n        this.hasProgressCanvas = params.waveColor != params.progressColor;\n\n        /**\n         * @type {number}\n         */\n        this.halfPixel = 0.5 / params.pixelRatio;\n\n        /**\n         * List of `CanvasEntry` instances.\n         *\n         * @type {Array}\n         */\n        this.canvases = [];\n\n        /**\n         * @type {HTMLElement}\n         */\n        this.progressWave = null;\n\n        /**\n         * Class used to generate entries.\n         *\n         * @type {function}\n         */\n        this.EntryClass = CanvasEntry;\n\n        /**\n         * Canvas 2d context attributes.\n         *\n         * @type {object}\n         */\n        this.canvasContextAttributes = params.drawingContextAttributes;\n\n        /**\n         * Overlap added between entries to prevent vertical white stripes\n         * between `canvas` elements.\n         *\n         * @type {number}\n         */\n        this.overlap = 2 * Math.ceil(params.pixelRatio / 2);\n\n        /**\n         * The radius of the wave bars. Makes bars rounded\n         *\n         * @type {number}\n         */\n        this.barRadius = params.barRadius || 0;\n\n        /**\n         * Whether to render the waveform vertically. Defaults to false.\n         *\n         * @type {boolean}\n         */\n        this.vertical = params.vertical;\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     */\n    createElements() {\n        this.progressWave = util.withOrientation(\n            this.wrapper.appendChild(document.createElement('wave')),\n            this.params.vertical\n        );\n        this.style(this.progressWave, {\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        this.addCanvas();\n        this.updateCursor();\n    }\n\n    /**\n     * Update cursor style\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 + this.overlap)\n        );\n\n        // add required canvases\n        while (this.canvases.length < requiredCanvases) {\n            this.addCanvas();\n        }\n\n        // remove older existing canvases, if any\n        while (this.canvases.length > requiredCanvases) {\n            this.removeCanvas();\n        }\n\n        let canvasWidth = this.maxCanvasWidth + this.overlap;\n        const lastCanvas = this.canvases.length - 1;\n        this.canvases.forEach((entry, i) => {\n            if (i == lastCanvas) {\n                canvasWidth = this.width - this.maxCanvasWidth * lastCanvas;\n            }\n            this.updateDimensions(entry, canvasWidth, this.height);\n\n            entry.clearWave();\n        });\n    }\n\n    /**\n     * Add a canvas to the canvas list\n     *\n     */\n    addCanvas() {\n        const entry = new this.EntryClass();\n        entry.canvasContextAttributes = this.canvasContextAttributes;\n        entry.hasProgressCanvas = this.hasProgressCanvas;\n        entry.halfPixel = this.halfPixel;\n        const leftOffset = this.maxCanvasElementWidth * this.canvases.length;\n\n        // wave\n        let wave = util.withOrientation(\n            this.wrapper.appendChild(document.createElement('canvas')),\n            this.params.vertical\n        );\n        this.style(wave, {\n            position: 'absolute',\n            zIndex: 2,\n            left: leftOffset + 'px',\n            top: 0,\n            bottom: 0,\n            height: '100%',\n            pointerEvents: 'none'\n        });\n        entry.initWave(wave);\n\n        // progress\n        if (this.hasProgressCanvas) {\n            let progress = util.withOrientation(\n                this.progressWave.appendChild(document.createElement('canvas')),\n                this.params.vertical\n            );\n            this.style(progress, {\n                position: 'absolute',\n                left: leftOffset + 'px',\n                top: 0,\n                bottom: 0,\n                height: '100%'\n            });\n            entry.initProgress(progress);\n        }\n\n        this.canvases.push(entry);\n    }\n\n    /**\n     * Pop single canvas from the list\n     *\n     */\n    removeCanvas() {\n        let lastEntry = this.canvases[this.canvases.length - 1];\n\n        // wave\n        lastEntry.wave.parentElement.removeChild(lastEntry.wave.domElement);\n\n        // progress\n        if (this.hasProgressCanvas) {\n            lastEntry.progress.parentElement.removeChild(lastEntry.progress.domElement);\n        }\n\n        // cleanup\n        if (lastEntry) {\n            lastEntry.destroy();\n            lastEntry = null;\n        }\n\n        this.canvases.pop();\n    }\n\n    /**\n     * Update the dimensions of a canvas element\n     *\n     * @param {CanvasEntry} entry Target 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        // update canvas dimensions\n        entry.updateDimensions(elementWidth, totalWidth, width, height);\n\n        // style element\n        this.style(this.progressWave, { display: 'block' });\n    }\n\n    /**\n     * Clear the whole multi-canvas\n     */\n    clearWave() {\n        util.frame(() => {\n            this.canvases.forEach(entry => entry.clearWave());\n        })();\n    }\n\n    /**\n     * Draw a waveform with bars\n     *\n     * @param {number[]|Number.<Array[]>} peaks Can also be an array of arrays\n     * for split channel 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     * @returns {void}\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, channelIndex: ch }) => {\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 peakIndex = first;\n                for (peakIndex; peakIndex < last; peakIndex += step) {\n\n                    // search for the highest peak in the range this bar falls into\n                    let peak = 0;\n                    let peakIndexRange = Math.floor(peakIndex * scale) * peakIndexScale; // start index\n                    const peakIndexEnd = Math.floor((peakIndex + step) * scale) * peakIndexScale;\n                    do { // do..while makes sure at least one peak is always evaluated\n                        const newPeak = Math.abs(peaks[peakIndexRange]); // for arrays starting with negative values\n                        if (newPeak > peak) {\n                            peak = newPeak; // higher\n                        }\n                        peakIndexRange += peakIndexScale; // skip every other value for negatives\n                    } while (peakIndexRange < peakIndexEnd);\n\n                    // calculate the height of this bar according to the highest peak found\n                    let h = Math.round((peak / absmax) * halfH);\n\n                    // raise the bar height to the specified minimum height\n                    // Math.max is used to replace any value smaller than barMinHeight (not just 0) with barMinHeight\n                    if (this.params.barMinHeight) {\n                        h = Math.max(h, this.params.barMinHeight);\n                    }\n\n                    this.fillRect(\n                        peakIndex + this.halfPixel,\n                        halfH - h + offsetY,\n                        bar + this.halfPixel,\n                        h * 2,\n                        this.barRadius,\n                        ch\n                    );\n                }\n            }\n        );\n    }\n\n    /**\n     * Draw a waveform\n     *\n     * @param {number[]|Number.<Array[]>} peaks Can also be an array of arrays\n     * for split channel 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     * @returns {void}\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, channelIndex }) => {\n                if (!hasMinVals) {\n                    const reflectedPeaks = [];\n                    const len = peaks.length;\n                    let i = 0;\n                    for (i; 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, channelIndex);\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                    this.barRadius,\n                    channelIndex\n                );\n            }\n        );\n    }\n\n    /**\n     * Tell the canvas entries to render their portion of the waveform\n     *\n     * @param {number[]} peaks Peaks 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     * @param {channelIndex} channelIndex The channel index of the line drawn\n     */\n    drawLine(peaks, absmax, halfH, offsetY, start, end, channelIndex) {\n        const { waveColor, progressColor } = this.params.splitChannelsOptions.channelColors[channelIndex] || {};\n        this.canvases.forEach((entry, i) => {\n            this.setFillStyles(entry, waveColor, progressColor);\n            this.applyCanvasTransforms(entry, this.params.vertical);\n            entry.drawLines(peaks, absmax, halfH, offsetY, start, end);\n        });\n    }\n\n    /**\n     * Draw a rectangle on the multi-canvas\n     *\n     * @param {number} x X-position of the rectangle\n     * @param {number} y Y-position of the rectangle\n     * @param {number} width Width of the rectangle\n     * @param {number} height Height of the rectangle\n     * @param {number} radius Radius of the rectangle\n     * @param {channelIndex} channelIndex The channel index of the bar drawn\n     */\n    fillRect(x, y, width, height, radius, channelIndex) {\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 = startCanvas;\n        for (i; 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.wave.width\n                ),\n                y2: y + height\n            };\n\n            if (intersection.x1 < intersection.x2) {\n                const { waveColor, progressColor } = this.params.splitChannelsOptions.channelColors[channelIndex] || {};\n                this.setFillStyles(entry, waveColor, progressColor);\n                this.applyCanvasTransforms(entry, this.params.vertical);\n\n                entry.fillRects(\n                    intersection.x1 - leftOffset,\n                    intersection.y1,\n                    intersection.x2 - intersection.x1,\n                    intersection.y2 - intersection.y1,\n                    radius\n                );\n            }\n        }\n    }\n\n    /**\n     * Returns whether to hide the channel from being drawn based on params.\n     *\n     * @param {number} channelIndex The index of the current channel.\n     * @returns {bool} True to hide the channel, false to draw.\n     */\n    hideChannel(channelIndex) {\n        return this.params.splitChannels && this.params.splitChannelsOptions.filterChannels.includes(channelIndex);\n    }\n\n    /**\n     * Performs preparation tasks and calculations which are shared by `drawBars`\n     * and `drawWave`\n     *\n     * @param {number[]|Number.<Array[]>} peaks Can also be an array of arrays for\n     * split channel 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, e.g. `drawWave`\n     * @param {number} drawIndex The index of the current channel after filtering.\n     * @param {number?} normalizedMax Maximum modulation value across channels for use with relativeNormalization. Ignored when undefined\n     * @returns {void}\n     */\n    prepareDraw(peaks, channelIndex, start, end, fn, drawIndex, normalizedMax) {\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\n                if (this.params.splitChannels) {\n                    const filteredChannels = channels.filter((c, i) => !this.hideChannel(i));\n                    if (!this.params.splitChannelsOptions.overlay) {\n                        this.setHeight(\n                            Math.max(filteredChannels.length, 1) *\n                                this.params.height *\n                                this.params.pixelRatio\n                        );\n                    }\n\n                    let overallAbsMax;\n                    if (this.params.splitChannelsOptions && this.params.splitChannelsOptions.relativeNormalization) {\n                        // calculate maximum peak across channels to use for normalization\n                        overallAbsMax = util.max(channels.map((channelPeaks => util.absMax(channelPeaks))));\n                    }\n\n\n                    return channels.forEach((channelPeaks, i) =>\n                        this.prepareDraw(channelPeaks, i, start, end, fn, filteredChannels.indexOf(channelPeaks), overallAbsMax)\n                    );\n                }\n                peaks = channels[0];\n            }\n\n            // Return and do not draw channel peaks if hidden.\n            if (this.hideChannel(channelIndex)) {\n                return;\n            }\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                absmax = normalizedMax === undefined ? util.absMax(peaks) : normalizedMax;\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 halfH = height / 2;\n\n            let offsetY = height * drawIndex || 0;\n\n            // Override offsetY if overlay is true\n            if (this.params.splitChannelsOptions && this.params.splitChannelsOptions.overlay) {\n                offsetY = 0;\n            }\n\n            return fn({\n                absmax: absmax,\n                hasMinVals: hasMinVals,\n                height: height,\n                offsetY: offsetY,\n                halfH: halfH,\n                peaks: peaks,\n                channelIndex: channelIndex\n            });\n        })();\n    }\n\n    /**\n     * Set the fill styles for a certain entry (wave and progress)\n     *\n     * @param {CanvasEntry} entry Target entry\n     * @param {string} waveColor Wave color to draw this entry\n     * @param {string} progressColor Progress color to draw this entry\n     */\n    setFillStyles(entry, waveColor = this.params.waveColor, progressColor = this.params.progressColor) {\n        entry.setFillStyles(waveColor, progressColor);\n    }\n\n    /**\n     * Set the canvas transforms for a certain entry (wave and progress)\n     *\n     * @param {CanvasEntry} entry Target entry\n     * @param {boolean} vertical Whether to render the waveform vertically\n     */\n    applyCanvasTransforms(entry, vertical = false) {\n        entry.applyCanvasTransforms(vertical);\n    }\n\n    /**\n     * Return image data of the multi-canvas\n     *\n     * When using a `type` of `'blob'`, this will return a `Promise`.\n     *\n     * @param {string} format='image/png' An optional value of a format type.\n     * @param {number} quality=0.92 An optional value between 0 and 1.\n     * @param {string} type='dataURL' Either 'dataURL' or 'blob'.\n     * @return {string|string[]|Promise} When using the default `'dataURL'`\n     * `type` this returns a single data URL or an array of data URLs,\n     * one for each canvas. When using the `'blob'` `type` this returns a\n     * `Promise` that resolves with an array of `Blob` instances, one for each\n     * canvas.\n     */\n    getImage(format, quality, type) {\n        if (type === 'blob') {\n            return Promise.all(\n                this.canvases.map(entry => {\n                    return entry.getImage(format, quality, type);\n                })\n            );\n        } else if (type === 'dataURL') {\n            let images = this.canvases.map(entry =>\n                entry.getImage(format, quality, type)\n            );\n            return images.length > 1 ? images : images[0];\n        }\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 MediaElement from './mediaelement';\n\n/**\n * MediaElementWebAudio backend: load audio via an HTML5 audio tag, but playback with the WebAudio API.\n * The advantage here is that the html5 <audio> tag can perform range requests on the server and not\n * buffer the entire file in one request, and you still get the filtering and scripting functionality\n * of the webaudio API.\n * Note that in order to use range requests and prevent buffering, you must provide peak data.\n *\n * @since 3.2.0\n */\nexport default class MediaElementWebAudio extends MediaElement {\n    /**\n     * Construct the backend\n     *\n     * @param {WavesurferParams} params Wavesurfer parameters\n     */\n    constructor(params) {\n        super(params);\n        /** @private */\n        this.params = params;\n        /** @private */\n        this.sourceMediaElement = 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        this.createVolumeNode();\n        this.createScriptNode();\n        this.createAnalyserNode();\n    }\n    /**\n     * Private method called by both `load` (from url)\n     * and `loadElt` (existing media element) methods.\n     *\n     * @param {HTMLMediaElement} media HTML5 Audio or Video element\n     * @param {number[]|Number.<Array[]>} peaks Array of peak data\n     * @param {string} preload HTML 5 preload attribute value\n     * @private\n     */\n    _load(media, peaks, preload) {\n        super._load(media, peaks, preload);\n        this.createMediaElementSource(media);\n    }\n\n    /**\n     * Create MediaElementSource node\n     *\n     * @since 3.2.0\n     * @param {HTMLMediaElement} mediaElement HTML5 Audio to load\n     */\n    createMediaElementSource(mediaElement) {\n        this.sourceMediaElement = this.ac.createMediaElementSource(\n            mediaElement\n        );\n        this.sourceMediaElement.connect(this.analyser);\n    }\n\n    play(start, end) {\n        this.resumeAudioContext();\n        return super.play(start, end);\n    }\n\n    /**\n     * This is called when wavesurfer is destroyed\n     *\n     */\n    destroy() {\n        super.destroy();\n\n        this.destroyWebAudio();\n    }\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 Wavesurfer parameters\n     */\n    constructor(params) {\n        super(params);\n        /** @private */\n        this.params = params;\n\n        /**\n         * Initially a dummy media element to catch errors. Once `_load` is\n         * called, this will contain the actual `HTMLMediaElement`.\n         * @private\n         */\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.isMuted = false;\n        /** @private */\n        this.buffer = null;\n        /** @private */\n        this.onPlayEnd = null;\n        /** @private */\n        this.mediaListeners = {};\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     * Attach event listeners to media element.\n     */\n    _setupMediaListeners() {\n        this.mediaListeners.error = () => {\n            this.fireEvent('error', 'Error loading media element');\n        };\n        this.mediaListeners.canplay = () => {\n            this.fireEvent('canplay');\n        };\n        this.mediaListeners.ended = () => {\n            this.fireEvent('finish');\n        };\n        // listen to and relay play, pause and seeked events to enable\n        // playback control from the external media element\n        this.mediaListeners.play = () => {\n            this.fireEvent('play');\n        };\n        this.mediaListeners.pause = () => {\n            this.fireEvent('pause');\n        };\n        this.mediaListeners.seeked = event => {\n            this.fireEvent('seek');\n        };\n        this.mediaListeners.volumechange = event => {\n            this.isMuted = this.media.muted;\n            if (this.isMuted) {\n                this.volume = 0;\n            } else {\n                this.volume = this.media.volume;\n            }\n            this.fireEvent('volume');\n        };\n\n        // reset event listeners\n        Object.keys(this.mediaListeners).forEach(id => {\n            this.media.removeEventListener(id, this.mediaListeners[id]);\n            this.media.addEventListener(id, this.mediaListeners[id]);\n        });\n    }\n\n    /**\n     * Create a timer to provide a more precise `audioprocess` event.\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            util.frame(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.<Array[]>} peaks Array of peak data\n     * @param {string} preload HTML 5 preload attribute value\n     * @throws Will throw an error if the `url` argument is not a valid media\n     * element.\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, preload);\n    }\n\n    /**\n     * Load existing media element.\n     *\n     * @param {HTMLMediaElement} elt HTML5 Audio or Video element\n     * @param {number[]|Number.<Array[]>} 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, elt.preload);\n    }\n\n    /**\n     * Method called by both `load` (from url)\n     * and `loadElt` (existing media element) methods.\n     *\n     * @param {HTMLMediaElement} media HTML5 Audio or Video element\n     * @param {number[]|Number.<Array[]>} peaks Array of peak data\n     * @param {string} preload HTML 5 preload attribute value\n     * @throws Will throw an error if the `media` argument is not a valid media\n     * element.\n     * @private\n     */\n    _load(media, peaks, preload) {\n        // verify media element is valid\n        if (\n            !(media instanceof HTMLMediaElement) ||\n            typeof media.addEventListener === 'undefined'\n        ) {\n            throw new Error('media parameter is not a valid media element');\n        }\n\n        // load must be called manually on iOS, otherwise peaks won't draw\n        // until a user interaction triggers load --> 'ready' event\n        //\n        // note that we avoid calling media.load here when given peaks and preload == 'none'\n        // as this almost always triggers some browser fetch of the media.\n        if (typeof media.load == 'function' && !(peaks && preload == 'none')) {\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        this.media = media;\n        this._setupMediaListeners();\n        this.peaks = peaks;\n        this.onPlayEnd = null;\n        this.buffer = null;\n        this.isMuted = media.muted;\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} Media paused or not\n     */\n    isPaused() {\n        return !this.media || this.media.paused;\n    }\n\n    /**\n     * Used by `wavesurfer.getDuration()`\n     *\n     * @return {number} Duration\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} Current time\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} Current position\n     */\n    getPlayedPercents() {\n        return this.getCurrentTime() / this.getDuration() || 0;\n    }\n\n    /**\n     * Get the audio source playback rate.\n     *\n     * @return {number} Playback rate\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 Playback rate\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 && !isNaN(start)) {\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} Result\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} Result\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    /**\n     * Set the play end\n     *\n     * @param {number} end Where to end\n     */\n    setPlayEnd(end) {\n        this.clearPlayEnd();\n\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     * <length> 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[]>} Array of 2*<length> 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     * @returns {Promise} A Promise that resolves to `undefined` when there\n     * are no errors.\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;\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        // no need to change when it's already at that volume\n        if (this.media.volume !== this.volume) {\n            this.media.volume = this.volume;\n        }\n    }\n\n    /**\n     * Enable or disable muted audio\n     *\n     * @since 4.0.0\n     * @param {boolean} muted Specify `true` to mute audio.\n     */\n    setMute(muted) {\n        // This causes a volume change to be emitted too through the\n        // volumechange event listener.\n        this.isMuted = this.media.muted = muted;\n    }\n\n    /**\n     * This is called when wavesurfer is destroyed\n     *\n     */\n    destroy() {\n        this.pause();\n        this.unAll();\n        this.destroyed = true;\n\n        // cleanup media event listeners\n        Object.keys(this.mediaListeners).forEach(id => {\n            if (this.media) {\n                this.media.removeEventListener(id, this.mediaListeners[id]);\n            }\n        });\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.<Array[]>} Array with arrays of numbers\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.<Array[]>} Array with arrays of numbers\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","import utilMax from './max';\r\nimport utilmin from './min';\r\n\r\n/**\r\n * Get the largest absolute value in an array\r\n *\r\n * @param   {Array} values Array of numbers\r\n * @returns {Number} Largest number found\r\n * @example console.log(max([-3, 2, 1]), max([-3, 2, 4])); // logs 3 4\r\n * @since 4.3.0\r\n */\r\nexport default function absMax(values) {\r\n    const max = utilMax(values);\r\n    const min = utilmin(values);\r\n    return -min > max ? -min : max;\r\n}\r\n","/**\n * Returns a number limited to the given range.\n *\n * @param {number} val The number to be limited to a range\n * @param {number} min The lower boundary of the limit range\n * @param {number} max The upper boundary of the limit range\n * @returns {number} A number in the range [min, max]\n */\nexport default function clamp(val, min, max) {\n    return Math.min(Math.max(min, val), max);\n}\n","/**\n * @since 3.0.0\n */\n\nimport Observer from './observer';\n\nclass ProgressHandler {\n    /**\n     * Instantiate ProgressHandler\n     *\n     * @param {Observer} instance The `fetchFile` observer instance.\n     * @param {Number} contentLength Content length.\n     * @param {Response} response Response object.\n     */\n    constructor(instance, contentLength, response) {\n        this.instance = instance;\n        this.instance._reader = response.body.getReader();\n\n        this.total = parseInt(contentLength, 10);\n        this.loaded = 0;\n    }\n\n    /**\n     * A method that is called once, immediately after the `ReadableStream``\n     * is constructed.\n     *\n     * @param {ReadableStreamDefaultController} controller Controller instance\n     *     used to control the stream.\n     */\n    start(controller) {\n        const read = () => {\n            // instance._reader.read() returns a promise that resolves\n            // when a value has been received\n            this.instance._reader\n                .read()\n                .then(({ done, value }) => {\n                    // result objects contain two properties:\n                    // done  - true if the stream has already given you all its data.\n                    // value - some data. Always undefined when done is true.\n                    if (done) {\n                        // ensure onProgress called when content-length=0\n                        if (this.total === 0) {\n                            this.instance.onProgress.call(this.instance, {\n                                loaded: this.loaded,\n                                total: this.total,\n                                lengthComputable: false\n                            });\n                        }\n                        // no more data needs to be consumed, close the stream\n                        controller.close();\n                        return;\n                    }\n\n                    this.loaded += value.byteLength;\n                    this.instance.onProgress.call(this.instance, {\n                        loaded: this.loaded,\n                        total: this.total,\n                        lengthComputable: !(this.total === 0)\n                    });\n                    // enqueue the next data chunk into our target stream\n                    controller.enqueue(value);\n                    read();\n                })\n                .catch(error => {\n                    controller.error(error);\n                });\n        };\n\n        read();\n    }\n}\n\n/**\n * Load a file using `fetch`.\n *\n * @param {object} options Request options to use. See example below.\n * @returns {Observer} Observer instance\n * @example\n * // default options\n * let options = {\n *     url: undefined,\n *     method: 'GET',\n *     mode: 'cors',\n *     credentials: 'same-origin',\n *     cache: 'default',\n *     responseType: 'json',\n *     requestHeaders: [],\n *     redirect: 'follow',\n *     referrer: 'client'\n * };\n *\n * // override some options\n * options.url = '../media/demo.wav';\n\n * // available types: 'arraybuffer', 'blob', 'json' or 'text'\n * options.responseType = 'arraybuffer';\n *\n * // make fetch call\n * let request = util.fetchFile(options);\n *\n * // listen for events\n * request.on('progress', e => {\n *     console.log('progress', e);\n * });\n *\n * request.on('success', data => {\n *     console.log('success!', data);\n * });\n *\n * request.on('error', e => {\n *     console.warn('fetchFile error: ', e);\n * });\n */\nexport default function fetchFile(options) {\n    if (!options) {\n        throw new Error('fetch options missing');\n    } else if (!options.url) {\n        throw new Error('fetch url missing');\n    }\n    const instance = new Observer();\n    const fetchHeaders = new Headers();\n    const fetchRequest = new Request(options.url);\n\n    // add ability to abort\n    instance.controller = new AbortController();\n\n    // check if headers have to be added\n    if (options && options.requestHeaders) {\n        // add custom request headers\n        options.requestHeaders.forEach(header => {\n            fetchHeaders.append(header.key, header.value);\n        });\n    }\n\n    // parse fetch options\n    const responseType = options.responseType || 'json';\n    const fetchOptions = {\n        method: options.method || 'GET',\n        headers: fetchHeaders,\n        mode: options.mode || 'cors',\n        credentials: options.credentials || 'same-origin',\n        cache: options.cache || 'default',\n        redirect: options.redirect || 'follow',\n        referrer: options.referrer || 'client',\n        signal: instance.controller.signal\n    };\n\n    fetch(fetchRequest, fetchOptions)\n        .then(response => {\n            // store response reference\n            instance.response = response;\n\n            let progressAvailable = true;\n            if (!response.body) {\n                // ReadableStream is not yet supported in this browser\n                // see https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream\n                progressAvailable = false;\n            }\n\n            // Server must send CORS header \"Access-Control-Expose-Headers: content-length\"\n            const contentLength = response.headers.get('content-length');\n            if (contentLength === null) {\n                // Content-Length server response header missing.\n                // Don't evaluate download progress if we can't compare against a total size\n                // see https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Access-Control-Expose-Headers\n                progressAvailable = false;\n            }\n\n            if (!progressAvailable) {\n                // not able to check download progress so skip it\n                return response;\n            }\n\n            // fire progress event when during load\n            instance.onProgress = e => {\n                instance.fireEvent('progress', e);\n            };\n\n            return new Response(\n                new ReadableStream(\n                    new ProgressHandler(instance, contentLength, response)\n                ),\n                fetchOptions\n            );\n        })\n        .then(response => {\n            let errMsg;\n            if (response.ok) {\n                switch (responseType) {\n                    case 'arraybuffer':\n                        return response.arrayBuffer();\n\n                    case 'json':\n                        return response.json();\n\n                    case 'blob':\n                        return response.blob();\n\n                    case 'text':\n                        return response.text();\n\n                    default:\n                        errMsg = 'Unknown responseType: ' + responseType;\n                        break;\n                }\n            }\n            if (!errMsg) {\n                errMsg = 'HTTP error status: ' + response.status;\n            }\n            throw new Error(errMsg);\n        })\n        .then(response => {\n            instance.fireEvent('success', response);\n        })\n        .catch(error => {\n            instance.fireEvent('error', error);\n        });\n\n    // return the fetch request\n    instance.fetchRequest = fetchRequest;\n    return instance;\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 * Get a random prefixed ID\n *\n * @param {String} prefix Prefix to use. Default is `'wavesurfer_'`.\n * @returns {String} Random prefixed ID\n * @example\n * console.log(getId()); // logs 'wavesurfer_b5pors4ru6g'\n *\n * let prefix = 'foo-';\n * console.log(getId(prefix)); // logs 'foo-b5pors4ru6g'\n */\nexport default function getId(prefix) {\n    if (prefix === undefined) {\n        prefix = 'wavesurfer_';\n    }\n    return (\n        prefix +\n        Math.random()\n            .toString(32)\n            .substring(2)\n    );\n}\n","export { default as getId } from './get-id';\nexport { default as max } from './max';\nexport { default as min } from './min';\nexport { default as absMax } from './absMax';\nexport { default as Observer } from './observer';\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';\nexport { default as fetchFile } from './fetch';\nexport { default as clamp } from './clamp';\nexport { default as withOrientation } from './orientation';\nexport { default as ignoreSilenceMode } from './silence-mode';\n","/**\n * Get the largest value\n *\n * @param   {Array} values Array of numbers\n * @returns {Number} Largest number found\n * @example console.log(max([1, 2, 3])); // logs 3\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 * @example console.log(min([1, 2, 3])); // logs 1\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 * @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._disabledEventEmissions = [];\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} The event descriptor\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} The event descriptor\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     * Disable firing a list of events by name. When specified, event handlers for any event type\n     * passed in here will not be called.\n     *\n     * @since 4.0.0\n     * @param {string[]} eventNames an array of event names to disable emissions for\n     * @example\n     * // disable seek and interaction events\n     * wavesurfer.setDisabledEventEmissions(['seek', 'interaction']);\n     */\n    setDisabledEventEmissions(eventNames) {\n        this._disabledEventEmissions = eventNames;\n    }\n\n    /**\n     * plugins borrow part of this class without calling the constructor,\n     * so we have to be careful about _disabledEventEmissions\n     */\n\n    _isDisabledEventEmission(event) {\n        return this._disabledEventEmissions && this._disabledEventEmissions.includes(event);\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 || this._isDisabledEventEmission(event)) {\n            return;\n        }\n\n        const handlers = this.handlers[event];\n        handlers &&\n            handlers.forEach(fn => {\n                fn(...args);\n            });\n    }\n}\n","const verticalPropMap = {\n    width: 'height',\n    height: 'width',\n\n    overflowX: 'overflowY',\n    overflowY: 'overflowX',\n\n    clientWidth: 'clientHeight',\n    clientHeight: 'clientWidth',\n\n    clientX: 'clientY',\n    clientY: 'clientX',\n\n    scrollWidth: 'scrollHeight',\n    scrollLeft: 'scrollTop',\n\n    offsetLeft: 'offsetTop',\n    offsetTop: 'offsetLeft',\n    offsetHeight: 'offsetWidth',\n    offsetWidth: 'offsetHeight',\n\n    left: 'top',\n    right: 'bottom',\n    top: 'left',\n    bottom: 'right',\n\n    borderRightStyle: 'borderBottomStyle',\n    borderRightWidth: 'borderBottomWidth',\n    borderRightColor: 'borderBottomColor'\n};\n\n/**\n * Convert a horizontally-oriented property name to a vertical one.\n *\n * @param {string} prop A property name\n * @param {bool} vertical Whether the element is oriented vertically\n * @returns {string} prop, converted appropriately\n */\nfunction mapProp(prop, vertical) {\n    if (Object.prototype.hasOwnProperty.call(verticalPropMap, prop)) {\n        return vertical ? verticalPropMap[prop] : prop;\n    } else {\n        return prop;\n    }\n}\n\nconst isProxy = Symbol(\"isProxy\");\n\n/**\n * Returns an appropriately oriented object based on vertical.\n * If vertical is true, attribute getting and setting will be mapped through\n * verticalPropMap, so that e.g. getting the object's .width will give its\n * .height instead.\n * Certain methods of an oriented object will return oriented objects as well.\n * Oriented objects can't be added to the DOM directly since they are Proxy objects\n * and thus fail typechecks. Use domElement to get the actual element for this.\n *\n * @param {object} target The object to be wrapped and oriented\n * @param {bool} vertical Whether the element is oriented vertically\n * @returns {Proxy} An oriented object with attr translation via verticalAttrMap\n * @since 5.0.0\n */\nexport default function withOrientation(target, vertical) {\n    if (target[isProxy]) {\n        return target;\n    } else {\n        return new Proxy(\n            target, {\n                get: function(obj, prop, receiver) {\n                    if (prop === isProxy) {\n                        return true;\n                    } else if (prop === 'domElement') {\n                        return obj;\n                    } else if (prop === 'style') {\n                        return withOrientation(obj.style, vertical);\n                    } else if (prop === 'canvas') {\n                        return withOrientation(obj.canvas, vertical);\n                    } else if (prop === 'getBoundingClientRect') {\n                        return function(...args) {\n                            return withOrientation(obj.getBoundingClientRect(...args), vertical);\n                        };\n                    } else if (prop === 'getContext') {\n                        return function(...args) {\n                            return withOrientation(obj.getContext(...args), vertical);\n                        };\n                    } else {\n                        let value = obj[mapProp(prop, vertical)];\n                        return typeof value == 'function' ? value.bind(obj) : value;\n                    }\n                },\n                set: function(obj, prop, value) {\n                    obj[mapProp(prop, vertical)] = value;\n                    return true;\n                }\n            }\n        );\n    }\n}\n","/**\n * Stops propagation of click event and removes event listener\n *\n * @private\n * @param {object} event The click event\n */\nfunction preventClickHandler(event) {\n    event.stopPropagation();\n    document.body.removeEventListener('click', preventClickHandler, true);\n}\n\n/**\n * Starts listening for click event and prevent propagation\n *\n * @param {object} values Values\n */\nexport default function preventClick(values) {\n    document.body.addEventListener('click', preventClickHandler, true);\n}\n","/* eslint-disable valid-jsdoc */\n/**\n * Returns the `requestAnimationFrame` function for the browser, or a shim with\n * `setTimeout` if the function is not found\n *\n * @return {function} Available `requestAnimationFrame` function for the browser\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","/**\n * Ignores device silence mode when using the `WebAudio` backend.\n *\n * Many mobile devices contain a hardware button to mute the ringtone for incoming\n * calls and messages. Unfortunately, on some platforms like iOS, this also mutes\n * wavesurfer's audio when using the `WebAudio` backend. This function creates a\n * temporary `<audio>` element that makes sure the WebAudio backend keeps playing\n * when muting the device ringer.\n *\n * @since 5.2.0\n */\nexport default function ignoreSilenceMode() {\n    // Set the src to a short bit of url encoded as a silent mp3\n    // NOTE The silence MP3 must be high quality, when web audio sounds are played\n    // in parallel the web audio sound is mixed to match the bitrate of the html sound\n    // 0.01 seconds of silence VBR220-260 Joint Stereo 859B\n    const audioData = \"data:audio/mpeg;base64,//uQxAAAAAAAAAAAAAAAAAAAAAAAWGluZwAAAA8AAAACAAACcQCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA//////////////////////////////////////////////////////////////////8AAABhTEFNRTMuMTAwA8MAAAAAAAAAABQgJAUHQQAB9AAAAnGMHkkIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//sQxAADgnABGiAAQBCqgCRMAAgEAH///////////////7+n/9FTuQsQH//////2NG0jWUGlio5gLQTOtIoeR2WX////X4s9Atb/JRVCbBUpeRUq//////////////////9RUi0f2jn/+xDECgPCjAEQAABN4AAANIAAAAQVTEFNRTMuMTAwVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVQ==\";\n\n    // disable iOS Airplay (setting the attribute in js doesn't work)\n    let tmp = document.createElement(\"div\");\n    tmp.innerHTML = '<audio x-webkit-airplay=\"deny\"></audio>';\n\n    let audioSilentMode = tmp.children.item(0);\n    audioSilentMode.src = audioData;\n    audioSilentMode.preload = \"auto\";\n    audioSilentMode.type = \"audio/mpeg\";\n    audioSilentMode.disableRemotePlayback = true;\n\n    // play\n    audioSilentMode.play();\n\n    // cleanup\n    audioSilentMode.remove();\n    tmp.remove();\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 * as util from './util';\nimport MultiCanvas from './drawer.multicanvas';\nimport WebAudio from './webaudio';\nimport MediaElement from './mediaelement';\nimport PeakCache from './peakcache';\nimport MediaElementWebAudio from './mediaelement-webaudio';\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 on current progress\n * @property {number} autoCenterRate=5 If autoCenter is active, rate at which the\n * waveform is centered\n * @property {boolean} autoCenterImmediately=false If autoCenter is active, immediately\n * center waveform on current progress\n * @property {string} backend='WebAudio' `'WebAudio'|'MediaElement'|'MediaElementWebAudio'` In most cases\n * you don't have to set this manually. MediaElement is a fallback for unsupported browsers.\n * MediaElementWebAudio allows to use WebAudio API also with big audio files, loading audio like with\n * MediaElement backend (HTML5 audio tag). You have to use the same methods of MediaElement backend for loading and\n * playback, giving also peaks, so the audio data are not decoded. In this way you can use WebAudio features, like filters,\n * also with audio with big duration. For example:\n * ` wavesurfer.load(url | HTMLMediaElement, peaks, preload, duration);\n *   wavesurfer.play();\n *   wavesurfer.setFilter(customFilter);\n * `\n * @property {string} backgroundColor=null Change background color of the\n * waveform container.\n * @property {number} barHeight=1 The height of the wave bars.\n * @property {number} barRadius=0 The radius of the wave bars. Makes bars rounded\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 {number} barWidth=null Draw the waveform using bars.\n * @property {number} barMinHeight=null If specified, draw at least a bar of this height,\n * eliminating waveform gaps\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 {object} drawingContextAttributes={desynchronized: false} Drawing context\n * attributes.\n * @property {number} duration=null Optional audio length so pre-rendered peaks\n * can be display immediately for example.\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} hideCursor=false Whether to hide the mouse cursor\n * when one would normally be shown by default.\n * @property {boolean} ignoreSilenceMode=false If true, ignores device silence mode\n * when using the `WebAudio` backend.\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` or `MediaElementWebAudio`)\n * this enables the native controls for the media element\n * @property {string} mediaType='audio' (Use with backend `MediaElement` or `MediaElementWebAudio`)\n * `'audio'|'video'` ('video' only for `MediaElement`)\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. When `progressColor` and `waveColor` are the same\n * the progress wave is not rendered at all.\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} rtl=false If set to `true`, renders waveform from\n * right-to-left.\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 {SplitChannelOptions} splitChannelsOptions={} Options for splitChannel rendering\n * @property {boolean} vertical=false Render the waveform vertically instead of horizontally.\n * @property {string} waveColor='#999' The fill color of the waveform after the\n * cursor.\n * @property {object} xhr={} XHR options. For example:\n * `let xhr = {\n *     cache: 'default',\n *     mode: 'cors',\n *     method: 'GET',\n *     credentials: 'same-origin',\n *     redirect: 'follow',\n *     referrer: 'client',\n *     requestHeaders: [\n *         {\n *             key: 'Authorization',\n *             value: 'my-token'\n *         }\n *     ]\n * };`\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 * @typedef {Object} SplitChannelOptions\n * @desc parameters applied when splitChannels option is true\n * @property {boolean} overlay=false determines whether channels are rendered on top of each other or on separate tracks\n * @property {object} channelColors={} object describing color for each channel. Example:\n * {\n *     0: {\n *         progressColor: 'green',\n *         waveColor: 'pink'\n *     },\n *     1: {\n *         progressColor: 'orange',\n *         waveColor: 'purple'\n *     }\n * }\n * @property {number[]} filterChannels=[] indexes of channels to be hidden from rendering\n * @property {boolean} relativeNormalization=false determines whether\n * normalization is done per channel or maintains proportionality between\n * channels. Only applied when normalize and splitChannels are both true.\n * @property {boolean} splitDragSelection=false determines if drag selection in regions\n * plugin works separately on each channel or only one selection for all channels\n * @since 4.3.0\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     * It returns a `PluginDefinition` object representing the plugin.\n     *\n     * @param {Object} params={} The plugin params (specific to 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        autoCenterRate: 5,\n        autoCenterImmediately: false,\n        backend: 'WebAudio',\n        backgroundColor: null,\n        barHeight: 1,\n        barRadius: 0,\n        barGap: null,\n        barMinHeight: null,\n        container: null,\n        cursorColor: '#333',\n        cursorWidth: 1,\n        dragSelection: true,\n        drawingContextAttributes: {\n            // Boolean that hints the user agent to reduce the latency\n            // by desynchronizing the canvas paint cycle from the event\n            // loop\n            desynchronized: false\n        },\n        duration: null,\n        fillParent: true,\n        forceDecode: false,\n        height: 128,\n        hideScrollbar: false,\n        hideCursor: false,\n        ignoreSilenceMode: 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        rtl: false,\n        scrollParent: false,\n        skipLength: 2,\n        splitChannels: false,\n        splitChannelsOptions: {\n            overlay: false,\n            channelColors: {},\n            filterChannels: [],\n            relativeNormalization: false,\n            splitDragSelection: false\n        },\n        vertical: false,\n        waveColor: '#999',\n        xhr: {}\n    };\n\n    /** @private */\n    backends = {\n        MediaElement,\n        WebAudio,\n        MediaElementWebAudio\n    };\n\n    /**\n     * Instantiate this class, call its `init` function and returns it\n     *\n     * @param {WavesurferParams} params The wavesurfer parameters\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} Wavesurfer instance\n     */\n    constructor(params) {\n        super();\n        /**\n         * Extract relevant parameters (or defaults)\n         * @private\n         */\n        this.params = Object.assign({}, this.defaultParams, params);\n        this.params.splitChannelsOptions = Object.assign(\n            {},\n            this.defaultParams.splitChannelsOptions,\n            params.splitChannelsOptions\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        if (this.params.rtl === true) {\n            if (this.params.vertical === true) {\n                util.style(this.container, { transform: 'rotateX(180deg)' });\n            } else {\n                util.style(this.container, { transform: 'rotateY(180deg)' });\n            }\n        }\n\n        if (this.params.backgroundColor) {\n            this.setBackgroundColor(this.params.backgroundColor);\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.currentRequest = 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        // Back compat\n        if (this.params.backend == 'AudioElement') {\n            this.params.backend = 'MediaElement';\n        }\n\n        if (\n            (this.params.backend == 'WebAudio' ||\n                this.params.backend === 'MediaElementWebAudio') &&\n            !WebAudio.prototype.supportsWebAudio.call(null)\n        ) {\n            this.params.backend = 'MediaElement';\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\n        /**\n         * Get the current ready status.\n         *\n         * @example const isReady = wavesurfer.isReady;\n         * @return {boolean}\n         */\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                    this.drawer.wrapper &&\n                    prevWidth != this.drawer.wrapper.clientWidth &&\n                    !this.params.scrollParent\n                ) {\n                    prevWidth = this.drawer.wrapper.clientWidth;\n                    if (prevWidth) {\n                        // redraw only if waveform container is rendered and has a width\n                        this.drawer.fireEvent('redraw');\n                    }\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} The wavesurfer instance\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} The wavesurfer instance\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     * Get a map of plugin names that are currently initialised\n     *\n     * @example wavesurfer.getPlugins();\n     * @return {Object} Object with plugin names\n     */\n    getActivePlugins() {\n        return this.initialisedPluginList;\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} The wavesurfer instance\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} The wavesurfer instance\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} The wavesurfer instance\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        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        // only needed for MediaElement and MediaElementWebAudio backend\n        if (\n            this.params.backend === 'MediaElement' ||\n            this.params.backend === 'MediaElementWebAudio'\n        ) {\n            this.backend.on('seek', () => {\n                this.drawer.progress(this.backend.getPlayedPercents());\n            });\n\n            this.backend.on('volume', () => {\n                let newVolume = this.getVolume();\n                this.fireEvent('volume', newVolume);\n\n                if (this.backend.isMuted !== this.isMuted) {\n                    this.isMuted = this.backend.isMuted;\n                    this.fireEvent('mute', this.isMuted);\n                }\n            });\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} Result of the backend play method\n     * @example\n     * // play from second 1 to 5\n     * wavesurfer.play(1, 5);\n     */\n    play(start, end) {\n        if (this.params.ignoreSilenceMode) {\n            // ignores device hardware silence mode\n            util.ignoreSilenceMode();\n        }\n\n        this.fireEvent('interaction', () => this.play(start, end));\n        return this.backend.play(start, end);\n    }\n\n    /**\n     * Set a point in seconds for playback to stop at.\n     *\n     * @param {number} position Position (in seconds) to stop at\n     * @version 3.3.0\n     */\n    setPlayEnd(position) {\n        this.backend.setPlayEnd(position);\n    }\n\n    /**\n     * Stops and pauses playback\n     *\n     * @example wavesurfer.pause();\n     * @return {Promise} Result of the backend pause method\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} Result of the backend play or pause method\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            throw new 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 isWebAudioBackend = this.params.backend === 'WebAudio';\n        const paused = this.backend.isPaused();\n\n        if (isWebAudioBackend && !paused) {\n            this.backend.pause();\n        }\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 (isWebAudioBackend && !paused) {\n            this.backend.play();\n        }\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     * Sets the ID of the audio device to use for output and returns a Promise.\n     *\n     * @param {string} deviceId String value representing underlying output\n     * device\n     * @returns {Promise} `Promise` that resolves to `undefined` when there are\n     * no errors detected.\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} The current playback rate.\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 Specify `true` to mute audio.\n     * @emits WaveSurfer#volume\n     * @emits WaveSurfer#mute\n     * @example\n     * // unmute\n     * wavesurfer.setMute(false);\n     * console.log(wavesurfer.getMute()) // logs 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 (this.backend.setMute) {\n            // Backends such as the MediaElement backend have their own handling\n            // of mute, let them handle it.\n            this.backend.setMute(mute);\n            this.isMuted = mute;\n        } else {\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        }\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} Current mute status\n     */\n    getMute() {\n        return this.isMuted;\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} List of enabled filters\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     * @param {?number} channelIdx Optional index of the channel to get its wave color if splitChannels is true\n     * @return {string|object} A CSS color string, or an array of CSS color strings.\n     */\n    getWaveColor(channelIdx = null) {\n        if (this.params.splitChannelsOptions.channelColors[channelIdx]) {\n            return this.params.splitChannelsOptions.channelColors[channelIdx].waveColor;\n        }\n        return this.params.waveColor;\n    }\n\n    /**\n     * Set the fill color of the waveform after the cursor.\n     *\n     * @param {string|object} color A CSS color string, or an array of CSS color strings.\n     * @param {?number} channelIdx Optional index of the channel to set its wave color if splitChannels is true\n     * @example wavesurfer.setWaveColor('#ddd');\n     */\n    setWaveColor(color, channelIdx = null) {\n        if (this.params.splitChannelsOptions.channelColors[channelIdx]) {\n            this.params.splitChannelsOptions.channelColors[channelIdx].waveColor = color;\n        } else {\n            this.params.waveColor = color;\n        }\n        this.drawBuffer();\n    }\n\n    /**\n     * Get the fill color of the waveform behind the cursor.\n     *\n     * @param {?number} channelIdx Optional index of the channel to get its progress color if splitChannels is true\n     * @return {string|object} A CSS color string, or an array of CSS color strings.\n     */\n    getProgressColor(channelIdx = null) {\n        if (this.params.splitChannelsOptions.channelColors[channelIdx]) {\n            return this.params.splitChannelsOptions.channelColors[channelIdx].progressColor;\n        }\n        return this.params.progressColor;\n    }\n\n    /**\n     * Set the fill color of the waveform behind the cursor.\n     *\n     * @param {string|object} color A CSS color string, or an array of CSS color strings.\n     * @param {?number} channelIdx Optional index of the channel to set its progress color if splitChannels is true\n     * @example wavesurfer.setProgressColor('#400');\n     */\n    setProgressColor(color, channelIdx) {\n        if (this.params.splitChannelsOptions.channelColors[channelIdx]) {\n            this.params.splitChannelsOptions.channelColors[channelIdx].progressColor = color;\n        } else {\n            this.params.progressColor = color;\n        }\n        this.drawBuffer();\n    }\n\n    /**\n     * Get the background color of the waveform container.\n     *\n     * @return {string} A CSS color string.\n     */\n    getBackgroundColor() {\n        return this.params.backgroundColor;\n    }\n\n    /**\n     * Set the background color of the waveform container.\n     *\n     * @param {string} color A CSS color string.\n     * @example wavesurfer.setBackgroundColor('#FF00FF');\n     */\n    setBackgroundColor(color) {\n        this.params.backgroundColor = color;\n        util.style(this.container, { background: this.params.backgroundColor });\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     * Hide channels from being drawn on the waveform if splitting channels.\n     *\n     * For example, if we want to draw only the peaks for the right stereo channel:\n     *\n     * const wavesurfer = new WaveSurfer.create({...splitChannels: true});\n     * wavesurfer.load('stereo_audio.mp3');\n     *\n     * wavesurfer.setFilteredChannel([0]); <-- hide left channel peaks.\n     *\n     * @param {array} channelIndices Channels to be filtered out from drawing.\n     * @version 4.0.0\n     */\n    setFilteredChannels(channelIndices) {\n        this.params.splitChannelsOptions.filterChannels = channelIndices;\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        // always start at 0 after zooming for scrolling : issue redraw left part\n        let start = 0;\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 Buffer to process\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 Buffer to process\n     * @emits WaveSurfer#ready\n     */\n    loadDecodedBuffer(buffer) {\n        this.backend.load(buffer);\n        this.drawBuffer();\n        this.isReady = true;\n        this.fireEvent('ready');\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.<Array[]>} 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` and `MediaElementWebAudio`)\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     * @returns {void}\n     * @throws Will throw an error if the `url` argument is empty.\n     * @example\n     * // uses fetch or media element to load file (depending on backend)\n     * wavesurfer.load('http://example.com/demo.wav');\n     *\n     * // setting preload attribute with media element backend and supplying\n     * // peaks\n     * 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        if (!url) {\n            throw new Error('url parameter cannot be empty');\n        }\n        this.empty();\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' or 'MediaElementWebAudio'\":\n                    ['MediaElement', 'MediaElementWebAudio'].indexOf(\n                        this.params.backend\n                    ) === -1,\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                // eslint-disable-next-line no-console\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        // loadBuffer(url, peaks, duration) requires that url is a string\n        // but users can pass in a HTMLMediaElement to WaveSurfer\n        if (this.params.backend === 'WebAudio' && url instanceof HTMLMediaElement) {\n            url = url.src;\n        }\n\n        switch (this.params.backend) {\n            case 'WebAudio':\n                return this.loadBuffer(url, peaks, duration);\n            case 'MediaElement':\n            case 'MediaElementWebAudio':\n                return this.loadMediaElement(url, peaks, preload, duration);\n        }\n    }\n\n    /**\n     * Loads audio using Web Audio buffer backend.\n     *\n     * @private\n     * @emits WaveSurfer#waveform-ready\n     * @param {string} url URL of audio file\n     * @param {number[]|Number.<Array[]>} peaks Peaks data\n     * @param {?number} duration Optional duration of audio file\n     * @returns {void}\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.fireEvent('waveform-ready');\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     * @emits WaveSurfer#waveform-ready\n     * @param {string|HTMLMediaElement} urlOrElt Either a path to a media file, or an\n     * existing HTML5 Audio/Video Element\n     * @param {number[]|Number.<Array[]>} 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 Optional duration of audio file\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                // ignore when backend was already destroyed\n                if (!this.backend.destroyed) {\n                    this.drawBuffer();\n                    this.isReady = true;\n                    this.fireEvent('ready');\n                }\n            }),\n            this.backend.once('error', err => this.fireEvent('error', err))\n        );\n\n        // If peaks are provided, render them and fire the `waveform-ready` event.\n        if (peaks) {\n            this.backend.setPeaks(peaks, duration);\n            this.drawBuffer();\n            this.fireEvent('waveform-ready');\n        }\n\n        // If no pre-decoded peaks are provided, or are provided with\n        // forceDecode flag, attempt to download the audio file and decode it\n        // with Web Audio.\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 The array buffer to decode\n     * @param {function} callback The function to call on complete\n     */\n    decodeArrayBuffer(arraybuffer, callback) {\n        if (!this.isDestroyed) {\n            this.arraybuffer = arraybuffer;\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    /**\n     * Load an array buffer using fetch and pass the result to a callback\n     *\n     * @param {string} url The URL of the file object\n     * @param {function} callback The function to call on complete\n     * @returns {util.fetchFile} fetch call\n     * @private\n     */\n    getArrayBuffer(url, callback) {\n        let options = Object.assign(\n            {\n                url: url,\n                responseType: 'arraybuffer'\n            },\n            this.params.xhr\n        );\n        const request = util.fetchFile(options);\n\n        this.currentRequest = request;\n\n        this.tmpEvents.push(\n            request.on('progress', e => {\n                this.onProgress(e);\n            }),\n            request.on('success', data => {\n                callback(data);\n                this.currentRequest = null;\n            }),\n            request.on('error', e => {\n                this.fireEvent('error', e);\n                this.currentRequest = null;\n            })\n        );\n\n        return request;\n    }\n\n    /**\n     * Called while the audio file is loading\n     *\n     * @private\n     * @param {Event} e Progress event\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 optionally opens in a new window\n     * as valid JSON Blob instance.\n     *\n     * @param {number} length=1024 The scale in which to export the peaks\n     * @param {number} accuracy=10000\n     * @param {?boolean} noWindow Set to true to disable opening a new\n     * window with the JSON\n     * @param {number} start Start index\n     * @param {number} end End index\n     * @return {Promise} Promise that resolves with array of peaks\n     */\n    exportPCM(length, accuracy, noWindow, start, end) {\n        length = length || 1024;\n        start = start || 0;\n        accuracy = accuracy || 10000;\n        noWindow = noWindow || false;\n        const peaks = this.backend.getPeaks(length, start, end);\n        const arr = [].map.call(\n            peaks,\n            val => Math.round(val * accuracy) / accuracy\n        );\n\n        return new Promise((resolve, reject) => {\n            if (!noWindow){\n                const blobJSON = new Blob(\n                    [JSON.stringify(arr)],\n                    {type: 'application/json;charset=utf-8'}\n                );\n                const objURL = URL.createObjectURL(blobJSON);\n                window.open(objURL);\n                URL.revokeObjectURL(objURL);\n            }\n            resolve(arr);\n        });\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' A string indicating the image format.\n     * The default format type is `image/png`.\n     * @param {number} quality=1 A number between 0 and 1 indicating the image\n     * quality to use for image formats that use lossy compression such as\n     * `image/jpeg` and `image/webp`.\n     * @param {string} type Image data type to return. Either `dataURL` (default)\n     * or `blob`.\n     * @return {string|string[]|Promise} When using `dataURL` type this returns\n     * a single data URL or an array of data URLs, one for each canvas. When using\n     * `blob` type this returns a `Promise` resolving with an array of `Blob`\n     * instances, one for each canvas.\n     */\n    exportImage(format, quality, type) {\n        if (!format) {\n            format = 'image/png';\n        }\n        if (!quality) {\n            quality = 1;\n        }\n        if (!type) {\n            type = 'dataURL';\n        }\n\n        return this.drawer.getImage(format, quality, type);\n    }\n\n    /**\n     * Cancel any fetch request currently in progress\n     */\n    cancelAjax() {\n        if (this.currentRequest && this.currentRequest.controller) {\n            // If the current request has a ProgressHandler, then its ReadableStream might need to be cancelled too\n            // See: Wavesurfer issue #2042\n            // See Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1583815\n            if (this.currentRequest._reader) {\n                // Ignoring exceptions thrown by call to cancel()\n                this.currentRequest._reader.cancel().catch(err => {});\n            }\n\n            this.currentRequest.controller.abort();\n            this.currentRequest = 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\n        // empty drawer\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        if (this.backend) {\n            this.backend.destroy();\n            // clears memory usage\n            this.backend = null;\n        }\n        if (this.drawer) {\n            this.drawer.destroy();\n        }\n        this.isDestroyed = true;\n        this.isReady = false;\n        this.arraybuffer = null;\n    }\n}\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    /** scriptBufferSize: size of the processing buffer */\n    static scriptBufferSize = 256;\n    /** audioContext: allows to process audio with WebAudio API */\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} Whether or not this browser supports this backend\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} Existing audio context, or creates a new one\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 The sample rate to use\n     * @return {OfflineAudioContext} Existing offline audio context, or creates\n     * a new one\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 Wavesurfer parameters\n     */\n    constructor(params) {\n        super();\n        /** @private */\n        this.params = params;\n        /** ac: Audio Context instance */\n        this.ac =\n            params.audioContext ||\n            (this.supportsWebAudio() ? 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.buffer = null;\n        /** @private */\n        this.filters = [];\n        /** gainNode: allows to control audio volume */\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        /** analyser: provides audio analysis information */\n        this.analyser = null;\n        /** scriptNode: allows processing audio */\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 = params.duration;\n        /** @private */\n        this.sinkStreamDestination = null;\n        /** @private */\n        this.sinkAudioElement = null;\n        /**\n         * Boolean indicating if the backend was destroyed.\n         */\n        this.destroyed = false;\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    /**\n     * @private\n     *\n     * @param {string} state The new state\n     */\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 One or more filters to set\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    /** Create ScriptProcessorNode to process audio */\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    /** Create analyser node to perform audio analysis */\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     */\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     * @returns {Promise} A Promise that resolves to `undefined` when there\n     * are no errors.\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            if (!this.sinkAudioElement) {\n                this.sinkAudioElement = new window.Audio();\n                // autoplay is necessary since we're not invoking .play()\n                this.sinkAudioElement.autoplay = true;\n            }\n            if (!this.sinkAudioElement.setSinkId) {\n                return Promise.reject(\n                    new Error('setSinkId is not supported in your browser')\n                );\n            }\n            if (!this.sinkStreamDestination) {\n                this.sinkStreamDestination = this.ac.createMediaStreamDestination();\n            }\n            this.gainNode.disconnect();\n            this.gainNode.connect(this.sinkStreamDestination);\n            this.sinkAudioElement.srcObject = this.sinkStreamDestination.stream;\n\n            return this.sinkAudioElement.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    /**\n     * Decode an array buffer and pass data to a callback\n     *\n     * @private\n     * @param {ArrayBuffer} arraybuffer The array buffer to decode\n     * @param {function} callback The function to call on complete.\n     * @param {function} errback The function to call on error.\n     */\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        if ('webkitAudioContext' in window) {\n            // Safari: no support for Promise-based decodeAudioData enabled\n            // Enable it in Safari using the Experimental Features > Modern WebAudio API option\n            this.offlineAc.decodeAudioData(\n                arraybuffer,\n                data => callback(data),\n                errback\n            );\n        } else {\n            this.offlineAc.decodeAudioData(arraybuffer).then(\n                (data) => callback(data)\n            ).catch(\n                (err) => errback(err)\n            );\n        }\n    }\n\n    /**\n     * Set pre-decoded peaks\n     *\n     * @param {number[]|Number.<Array[]>} peaks Peaks data\n     * @param {?number} duration Explicit duration\n     */\n    setPeaks(peaks, duration) {\n        if (duration != null) {\n            this.explicitDuration = duration;\n        }\n        this.peaks = peaks;\n    }\n\n    /**\n     * Set the rendered length (different from the length of the audio)\n     *\n     * @param {number} length The rendered 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 <length> 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[]>} Array of 2*<length> 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        if (!this.buffer) {\n            return [];\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                /**\n                 * Initialize the max and min to the first sample of this\n                 * subrange, so that even if the samples are entirely\n                 * on one side of zero, we still return the true max and\n                 * min values in the subrange.\n                 */\n                let min = chan[start];\n                let max = min;\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} Position\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     * Destroy all references with WebAudio, disconnecting audio nodes and closing Audio Context\n     */\n    destroyWebAudio() {\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        // disconnect resources used by setSinkId\n        if (this.sinkStreamDestination) {\n            this.sinkAudioElement.pause();\n            this.sinkAudioElement.srcObject = null;\n            this.sinkStreamDestination.disconnect();\n            this.sinkStreamDestination = null;\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.destroyed = true;\n\n        this.destroyWebAudio();\n    }\n\n    /**\n     * Loaded a decoded audio buffer\n     *\n     * @param {Object} buffer Decoded audio buffer to load\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.setPlaybackRate(this.playbackRate);\n        this.source.buffer = this.buffer;\n        this.source.connect(this.analyser);\n    }\n\n    /**\n     * @private\n     *\n     * some browsers require an explicit call to #resume before they will play back audio\n     */\n    resumeAudioContext() {\n        if (this.ac.state == 'suspended') {\n            this.ac.resume && this.ac.resume();\n        }\n    }\n\n    /**\n     * Used by `wavesurfer.isPlaying()` and `wavesurfer.playPause()`\n     *\n     * @return {boolean} Whether or not this backend is currently paused\n     */\n    isPaused() {\n        return this.state !== this.states[PLAYING];\n    }\n\n    /**\n     * Used by `wavesurfer.getDuration()`\n     *\n     * @return {number} Duration of loaded buffer\n     */\n    getDuration() {\n        if (this.explicitDuration) {\n            return this.explicitDuration;\n        }\n        if (!this.buffer) {\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}} Object containing start and end\n     * positions\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} The playback position in seconds\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);\n\n        this.resumeAudioContext();\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        try {\n            this.source && this.source.stop(0);\n        } catch (err) {\n            // Calling stop can throw the following 2 errors:\n            // - RangeError (The value specified for when is negative.)\n            // - InvalidStateNode (The node has not been started by calling start().)\n            // We can safely ignore both errors, because:\n            // - The range is surely correct\n            // - The node might not have been started yet, in which case we just want to carry on without causing any trouble.\n        }\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} The current time in seconds\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} The current playback rate\n     */\n    getPlaybackRate() {\n        return this.playbackRate;\n    }\n\n    /**\n     * Set the audio source playback rate.\n     *\n     * @param {number} value The playback rate to use\n     */\n    setPlaybackRate(value) {\n        this.playbackRate = value || 1;\n        this.source && this.source.playbackRate.setValueAtTime(\n            this.playbackRate,\n            this.ac.currentTime\n        );\n    }\n\n    /**\n     * Set a point in seconds for playback to stop at.\n     *\n     * @param {number} end Position to end at\n     * @version 3.3.0\n     */\n    setPlayEnd(end) {\n        this.scheduledPause = end;\n    }\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","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// startup\n// Load entry module and return exports\n// This entry module is referenced by other modules so it can't be inlined\nvar __webpack_exports__ = __webpack_require__(631);\n"],"names":["root","factory","exports","module","define","amd","self","CanvasEntry","this","wave","waveCtx","progress","progressCtx","start","end","id","getId","constructor","name","toLowerCase","canvasContextAttributes","element","getContext","elementWidth","totalWidth","width","height","offsetLeft","elementSize","style","hasProgressCanvas","clearRect","canvas","waveColor","progressColor","fillStyle","getFillStyle","ctx","color","CanvasGradient","waveGradient","createLinearGradient","forEach","value","index","addColorStop","length","vertical","setTransform","x","y","radius","fillRectToContext","drawRoundedRect","fillRect","beginPath","moveTo","lineTo","quadraticCurveTo","closePath","fill","peaks","absmax","halfH","offsetY","drawLineToContext","i","peak","h","first","Math","round","canvasStart","canvasEnd","scale","halfOffset","absmaxHalf","halfPixel","j","format","quality","type","Promise","resolve","toBlob","toDataURL","Drawer","container","params","util","withOrientation","pixelRatio","lastPos","wrapper","el","styles","appendChild","document","createElement","display","position","userSelect","webkitUserSelect","fillParent","scrollParent","cursor","hideCursor","overflowX","hideScrollbar","overflowY","setupWrapperEvents","e","noPrevent","preventDefault","clientX","targetTouches","bbox","getBoundingClientRect","nominalWidth","parentWidth","getWidth","progressPixels","getProgressPixels","scrollLeft","scrollWidth","clamp","wrapperBbox","rtl","right","left","addEventListener","orientedEvent","scrollbarHeight","offsetHeight","clientHeight","clientY","bottom","interact","fireEvent","handleEvent","setWidth","clearWave","barWidth","drawBars","drawWave","percent","recenterOnPosition","immediate","half","clientWidth","maxScroll","target","offset","rate","autoCenterRate","max","min","newWidth","updateSize","minPxDelta","pos","autoCenter","newPos","autoCenterImmediately","updateProgress","unAll","parentNode","domElement","removeChild","channelIndex","Observer","MultiCanvas","maxCanvasWidth","maxCanvasElementWidth","canvases","progressWave","EntryClass","drawingContextAttributes","overlap","ceil","barRadius","createWrapper","createElements","zIndex","top","overflow","boxSizing","borderRightStyle","pointerEvents","addCanvas","updateCursor","borderRightWidth","cursorWidth","borderRightColor","cursorColor","requiredCanvases","removeCanvas","canvasWidth","lastCanvas","entry","updateDimensions","leftOffset","initWave","initProgress","push","lastEntry","parentElement","destroy","pop","frame","prepareDraw","hasMinVals","ch","undefined","peakIndexScale","bar","step","barGap","last","peakIndex","peakIndexRange","floor","peakIndexEnd","newPeak","abs","barMinHeight","reflectedPeaks","len","drawLine","splitChannelsOptions","channelColors","setFillStyles","applyCanvasTransforms","drawLines","startCanvas","endCanvas","intersection","x1","y1","x2","y2","fillRects","splitChannels","filterChannels","includes","fn","drawIndex","normalizedMax","Array","channels","overallAbsMax","filteredChannels","filter","c","hideChannel","overlay","setHeight","relativeNormalization","map","channelPeaks","absMax","indexOf","barHeight","normalize","some","call","val","all","getImage","images","MediaElementWebAudio","sourceMediaElement","setPlaybackRate","audioRate","createTimer","createVolumeNode","createScriptNode","createAnalyserNode","media","preload","createMediaElementSource","mediaElement","ac","connect","analyser","resumeAudioContext","destroyWebAudio","MediaElement","currentTime","duration","paused","playbackRate","play","pause","volume","mediaType","elementPosition","isMuted","buffer","onPlayEnd","mediaListeners","error","canplay","ended","seeked","event","volumechange","muted","Object","keys","removeEventListener","on","onAudioProcess","isPaused","getCurrentTime","url","controls","mediaControls","autoplay","src","prevMedia","querySelector","_load","elt","HTMLMediaElement","Error","load","_setupMediaListeners","setVolume","explicitDuration","Infinity","seekable","getDuration","isNaN","clearPlayEnd","seekTo","promise","setPlayEnd","_onPlayEnd","time","un","deviceId","setSinkId","reject","destroyed","removeMediaElementOnDestroy","WebAudio","PeakCache","clearPeakCache","peakCacheRanges","peakCacheLength","uncachedRanges","item","arr","concat","sort","a","b","uncachedRangePairs","peakCacheRangePairs","values","utilMax","utilmin","options","instance","fetchHeaders","Headers","fetchRequest","Request","controller","AbortController","requestHeaders","header","append","key","responseType","fetchOptions","method","headers","mode","credentials","cache","redirect","referrer","signal","fetch","then","response","progressAvailable","body","contentLength","get","onProgress","Response","ReadableStream","ProgressHandler","errMsg","ok","arrayBuffer","json","blob","text","status","catch","_reader","getReader","total","parseInt","loaded","read","done","lengthComputable","close","byteLength","enqueue","func","args","reqAnimationFrame","prefix","random","toString","substring","largest","smallest","Number","_disabledEventEmissions","handlers","callback","splice","handler","apply","setTimeout","eventNames","_isDisabledEventEmission","isProxy","Proxy","obj","prop","receiver","mapProp","bind","set","verticalPropMap","offsetTop","offsetWidth","prototype","hasOwnProperty","Symbol","preventClickHandler","stopPropagation","window","requestAnimationFrame","webkitRequestAnimationFrame","mozRequestAnimationFrame","oRequestAnimationFrame","msRequestAnimationFrame","tmp","innerHTML","audioSilentMode","children","disableRemotePlayback","remove","WaveSurfer","audioContext","audioScriptProcessor","backend","backgroundColor","dragSelection","desynchronized","forceDecode","ignoreSilenceMode","loopSelection","mediaContainer","minPxPerSec","partialRender","devicePixelRatio","screen","deviceXDPI","logicalXDPI","plugins","renderer","responsive","skipLength","splitDragSelection","xhr","assign","defaultParams","transform","setBackgroundColor","savedVolume","tmpEvents","currentRequest","arraybuffer","drawer","peakCache","supportsWebAudio","Backend","backends","initialisedPluginList","isDestroyed","isReady","prevWidth","_onResize","debounce","registerPlugins","createDrawer","createBackend","createPeakCache","plugin","addPlugin","deferInit","initPlugin","staticProps","pluginStaticProp","Instance","getOwnPropertyNames","destroyPlugin","init","drawBuffer","getPlayedPercents","newVolume","getVolume","seconds","skip","seekAndCenter","recenter","isFinite","isWebAudioBackend","oldScrollParent","getPlaybackRate","setMute","mute","filters","channelIdx","background","channelIndices","newRanges","addRangeToPeakCache","getPeaks","drawPeaks","pxPerSec","decodeArrayBuffer","data","loadDecodedBuffer","reader","FileReader","loadArrayBuffer","result","readAsArrayBuffer","empty","preloadIgnoreReasons","activeReasons","reason","console","warn","join","loadBuffer","loadMediaElement","action","once","getArrayBuffer","setPeaks","urlOrElt","loadElt","err","request","fetchFile","percentComplete","accuracy","noWindow","blobJSON","Blob","JSON","stringify","objURL","URL","createObjectURL","open","revokeObjectURL","cancel","abort","stop","disconnectSource","cancelAjax","clearTmpEvents","destroyAllPlugins","__VERSION__","PLAYING","PAUSED","FINISHED","addOnAudioProcess","startPosition","getPlayedTime","removeOnAudioProcess","getAudioContext","lastPlay","scheduledPause","states","create","stateBehaviors","gainNode","mergedPeaks","offlineAc","scriptNode","source","splitPeaks","state","sinkStreamDestination","sinkAudioElement","AudioContext","webkitAudioContext","WaveSurferAudioContext","sampleRate","WaveSurferOfflineAudioContext","OfflineAudioContext","webkitOfflineAudioContext","setState","setLength","disconnect","setFilters","disconnectFilters","reduce","prev","curr","createScriptProcessor","scriptBufferSize","createJavaScriptNode","destination","onaudioprocess","createAnalyser","createGain","createGainNode","Audio","createMediaStreamDestination","srcObject","stream","gain","setValueAtTime","errback","getOfflineAudioContext","decodeAudioData","numberOfChannels","newBuffer","createBuffer","sampleSize","sampleStep","chan","getChannelData","closeAudioContext","createSource","createBufferSource","noteGrainOn","noteOff","resume","adjustedTime","wait","timeout","context","timestamp","later","Date","now","debounced","arguments","callNow","clear","clearTimeout","flush","__webpack_module_cache__","__webpack_exports__","__webpack_require__","moduleId","cachedModule","__webpack_modules__"],"sourceRoot":""}