vendor: 4,174 bytes, lines 1-103
1/*! 2 * wavesurfer.js 3.3.3 (2020-04-16) 3 * https://github.com/katspaugh/wavesurfer.js 4 * @license BSD-3-Clause 5 */ 6(function webpackUniversalModuleDefinition(root, factory) { 7 if(typeof exports === 'object' && typeof module === 'object') 8 module.exports = factory(); 9 else if(typeof define === 'function' && define.amd) 10 define("WaveSurfer", [], factory); 11 else if(typeof exports === 'object') 12 exports["WaveSurfer"] = factory(); 13 else 14 root["WaveSurfer"] = factory(); 15})(window, function() { 16return /******/ (function(modules) { // webpackBootstrap 17/******/ // The module cache 18/******/ var installedModules = {}; 19/******/ 20/******/ // The require function 21/******/ function __webpack_require__(moduleId) { 22/******/ 23/******/ // Check if module is in cache 24/******/ if(installedModules[moduleId]) { 25/******/ return installedModules[moduleId].exports; 26/******/ } 27/******/ // Create a new module (and put it into the cache) 28/******/ var module = installedModules[moduleId] = { 29/******/ i: moduleId, 30/******/ l: false, 31/******/ exports: {} 32/******/ }; 33/******/ 34/******/ // Execute the module function 35/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 36/******/ 37/******/ // Flag the module as loaded 38/******/ module.l = true; 39/******/ 40/******/ // Return the exports of the module 41/******/ return module.exports; 42/******/ } 43/******/ 44/******/ 45/******/ // expose the modules object (__webpack_modules__) 46/******/ __webpack_require__.m = modules; 47/******/ 48/******/ // expose the module cache 49/******/ __webpack_require__.c = installedModules; 50/******/ 51/******/ // define getter function for harmony exports 52/******/ __webpack_require__.d = function(exports, name, getter) { 53/******/ if(!__webpack_require__.o(exports, name)) { 54/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); 55/******/ } 56/******/ }; 57/******/ 58/******/ // define __esModule on exports 59/******/ __webpack_require__.r = function(exports) { 60/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { 61/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); 62/******/ } 63/******/ Object.defineProperty(exports, '__esModule', { value: true }); 64/******/ }; 65/******/ 66/******/ // create a fake namespace object 67/******/ // mode & 1: value is a module id, require it 68/******/ // mode & 2: merge all properties of value into the ns 69/******/ // mode & 4: return value when already ns object 70/******/ // mode & 8|1: behave like require 71/******/ __webpack_require__.t = function(value, mode) { 72/******/ if(mode & 1) value = __webpack_require__(value); 73/******/ if(mode & 8) return value; 74/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; 75/******/ var ns = Object.create(null); 76/******/ __webpack_require__.r(ns); 77/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); 78/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); 79/******/ return ns; 80/******/ }; 81/******/ 82/******/ // getDefaultExport function for compatibility with non-harmony modules 83/******/ __webpack_require__.n = function(module) { 84/******/ var getter = module && module.__esModule ? 85/******/ function getDefault() { return module['default']; } : 86/******/ function getModuleExports() { return module; }; 87/******/ __webpack_require__.d(getter, 'a', getter); 88/******/ return getter; 89/******/ }; 90/******/ 91/******/ // Object.prototype.hasOwnProperty.call 92/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 93/******/ 94/******/ // __webpack_public_path__ 95/******/ __webpack_require__.p = ""; 96/******/ 97/******/ 98/******/ // Load entry module and return exports 99/******/ return __webpack_require__(__webpack_require__.s = "./src/wavesurfer.js"); 100/******/ }) 101/************************************************************************/ 102/******/ ({ 103
vendor: 2,102 bytes, lines 104-184
104/***/ "./node_modules/debounce/index.js": 105/*!****************************************!*\ 106 !*** ./node_modules/debounce/index.js ***! 107 \****************************************/ 108/*! no static exports found */ 109/***/ (function(module, exports) { 110 111/** 112 * Returns a function, that, as long as it continues to be invoked, will not 113 * be triggered. The function will be called after it stops being called for 114 * N milliseconds. If `immediate` is passed, trigger the function on the 115 * leading edge, instead of the trailing. The function also has a property 'clear' 116 * that is a function which will clear the timer to prevent previously scheduled executions. 117 * 118 * @source underscore.js 119 * @see http://unscriptable.com/2009/03/20/debouncing-javascript-methods/ 120 * @param {Function} function to wrap 121 * @param {Number} timeout in ms (`100`) 122 * @param {Boolean} whether to execute at the beginning (`false`) 123 * @api public 124 */ 125function debounce(func, wait, immediate){ 126 var timeout, args, context, timestamp, result; 127 if (null == wait) wait = 100; 128 129 function later() { 130 var last = Date.now() - timestamp; 131 132 if (last < wait && last >= 0) { 133 timeout = setTimeout(later, wait - last); 134 } else { 135 timeout = null; 136 if (!immediate) { 137 result = func.apply(context, args); 138 context = args = null; 139 } 140 } 141 }; 142 143 var debounced = function(){ 144 context = this; 145 args = arguments; 146 timestamp = Date.now(); 147 var callNow = immediate && !timeout; 148 if (!timeout) timeout = setTimeout(later, wait); 149 if (callNow) { 150 result = func.apply(context, args); 151 context = args = null; 152 } 153 154 return result; 155 }; 156 157 debounced.clear = function() { 158 if (timeout) { 159 clearTimeout(timeout); 160 timeout = null; 161 } 162 }; 163 164 debounced.flush = function() { 165 if (timeout) { 166 result = func.apply(context, args); 167 context = args = null; 168 169 clearTimeout(timeout); 170 timeout = null; 171 } 172 }; 173 174 return debounced; 175}; 176 177// Adds compatibility for ES modules 178debounce.debounce = debounce; 179 180module.exports = debounce; 181 182 183/***/ }), 184
185/***/ "./src/drawer.canvasentry.js": 186/*!***********************************!*\ 187 !*** ./src/drawer.canvasentry.js ***! 188 \***********************************/ 189/*! no static exports found */ 190/***/ (function(module, exports, __webpack_require__) { 191 192"use strict"; 193 194 195Object.defineProperty(exports, "__esModule", { 196 value: true 197}); 198exports.default = void 0; 199 200var _style = _interopRequireDefault(__webpack_require__(/*! ./util/style */ "./src/util/style.js")); 201 202var _getId = _interopRequireDefault(__webpack_require__(/*! ./util/get-id */ "./src/util/get-id.js")); 203 204function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 205 206function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 207 208function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } 209 210function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } 211 212/** 213 * The `CanvasEntry` class represents an element consisting of a wave `canvas` 214 * and an (optional) progress wave `canvas`. 215 * 216 * The `MultiCanvas` renderer uses one or more `CanvasEntry` instances to 217 * render a waveform, depending on the zoom level. 218 */ 219var CanvasEntry = 220/*#__PURE__*/ 221function () { 222 function CanvasEntry() { 223 _classCallCheck(this, CanvasEntry); 224 225 /** 226 * The wave node 227 * 228 * @type {HTMLCanvasElement} 229 */ 230 this.wave = null; 231 /** 232 * The wave canvas rendering context 233 * 234 * @type {CanvasRenderingContext2D} 235 */ 236 237 this.waveCtx = null; 238 /** 239 * The (optional) progress wave node 240 * 241 * @type {HTMLCanvasElement} 242 */ 243 244 this.progress = null; 245 /** 246 * The (optional) progress wave canvas rendering context 247 * 248 * @type {CanvasRenderingContext2D} 249 */ 250 251 this.progressCtx = null; 252 /** 253 * Start of the area the canvas should render, between 0 and 1 254 * 255 * @type {number} 256 * @private 257 */ 258 259 this.start = 0; 260 /** 261 * End of the area the canvas should render, between 0 and 1 262 * 263 * @type {number} 264 * @private 265 */ 266 267 this.end = 1; 268 /** 269 * Unique identifier for this entry 270 * 271 * @type {string} 272 */ 273 274 this.id = (0, _getId.default)(typeof this.constructor.name !== 'undefined' ? this.constructor.name.toLowerCase() + '_' : 'canvasentry_'); 275 /** 276 * Canvas 2d context attributes 277 * 278 * @type {object} 279 */ 280 281 this.canvasContextAttributes = {}; 282 } 283 /** 284 * Store the wave canvas element and create the 2D rendering context 285 * 286 * @param {HTMLCanvasElement} element The wave `canvas` element. 287 */ 288 289 290 _createClass(CanvasEntry, [{ 291 key: "initWave", 292 value: function initWave(element) { 293 this.wave = element; 294 this.waveCtx = this.wave.getContext('2d', this.canvasContextAttributes); 295 } 296 /** 297 * Store the progress wave canvas element and create the 2D rendering 298 * context 299 * 300 * @param {HTMLCanvasElement} element The progress wave `canvas` element. 301 */ 302 303 }, { 304 key: "initProgress", 305 value: function initProgress(element) { 306 this.progress = element; 307 this.progressCtx = this.progress.getContext('2d', this.canvasContextAttributes); 308 } 309 /** 310 * Update the dimensions 311 * 312 * @param {number} elementWidth Width of the entry 313 * @param {number} totalWidth Total width of the multi canvas renderer 314 * @param {number} width The new width of the element 315 * @param {number} height The new height of the element 316 */ 317 318 }, { 319 key: "updateDimensions", 320 value: function updateDimensions(elementWidth, totalWidth, width, height) { 321 // where the canvas starts and ends in the waveform, represented as a 322 // decimal between 0 and 1 323 this.start = this.wave.offsetLeft / totalWidth || 0; 324 this.end = this.start + elementWidth / totalWidth; // set wave canvas dimensions 325 326 this.wave.width = width; 327 this.wave.height = height; 328 var elementSize = { 329 width: elementWidth + 'px' 330 }; 331 (0, _style.default)(this.wave, elementSize); 332 333 if (this.hasProgressCanvas) { 334 // set progress canvas dimensions 335 this.progress.width = width; 336 this.progress.height = height; 337 (0, _style.default)(this.progress, elementSize); 338 } 339 } 340 /** 341 * Clear the wave and progress rendering contexts 342 */ 343 344 }, { 345 key: "clearWave", 346 value: function clearWave() { 347 // wave 348 this.waveCtx.clearRect(0, 0, this.waveCtx.canvas.width, this.waveCtx.canvas.height); // progress 349 350 if (this.hasProgressCanvas) { 351 this.progressCtx.clearRect(0, 0, this.progressCtx.canvas.width, this.progressCtx.canvas.height); 352 } 353 } 354 /** 355 * Set the fill styles for wave and progress 356 * 357 * @param {string} waveColor Fill color for the wave canvas 358 * @param {?string} progressColor Fill color for the progress canvas 359 */ 360 361 }, { 362 key: "setFillStyles", 363 value: function setFillStyles(waveColor, progressColor) { 364 this.waveCtx.fillStyle = waveColor; 365 366 if (this.hasProgressCanvas) { 367 this.progressCtx.fillStyle = progressColor; 368 } 369 } 370 /** 371 * Draw a rectangle for wave and progress 372 * 373 * @param {number} x X start position 374 * @param {number} y Y start position 375 * @param {number} width Width of the rectangle 376 * @param {number} height Height of the rectangle 377 * @param {number} radius Radius of the rectangle 378 */ 379 380 }, { 381 key: "fillRects", 382 value: function fillRects(x, y, width, height, radius) { 383 this.fillRectToContext(this.waveCtx, x, y, width, height, radius); 384 385 if (this.hasProgressCanvas) { 386 this.fillRectToContext(this.progressCtx, x, y, width, height, radius); 387 } 388 } 389 /** 390 * Draw the actual rectangle on a `canvas` element 391 * 392 * @private 393 * @param {CanvasRenderingContext2D} ctx Rendering context of target canvas 394 * @param {number} x X start position 395 * @param {number} y Y start position 396 * @param {number} width Width of the rectangle 397 * @param {number} height Height of the rectangle 398 * @param {number} radius Radius of the rectangle 399 */ 400 401 }, { 402 key: "fillRectToContext", 403 value: function fillRectToContext(ctx, x, y, width, height, radius) { 404 if (!ctx) { 405 return; 406 } 407 408 if (radius) { 409 this.drawRoundedRect(ctx, x, y, width, height, radius); 410 } else { 411 ctx.fillRect(x, y, width, height); 412 } 413 } 414 /** 415 * Draw a rounded rectangle on Canvas 416 * 417 * @private 418 * @param {CanvasRenderingContext2D} ctx Canvas context 419 * @param {number} x X-position of the rectangle 420 * @param {number} y Y-position of the rectangle 421 * @param {number} width Width of the rectangle 422 * @param {number} height Height of the rectangle 423 * @param {number} radius Radius of the rectangle 424 * 425 * @return {void} 426 * @example drawRoundedRect(ctx, 50, 50, 5, 10, 3) 427 */ 428 429 }, { 430 key: "drawRoundedRect", 431 value: function drawRoundedRect(ctx, x, y, width, height, radius) { 432 if (height === 0) { 433 return; 434 } // peaks are float values from -1 to 1. Use absolute height values in 435 // order to correctly calculate rounded rectangle coordinates 436 437 438 if (height < 0) { 439 height *= -1; 440 y -= height; 441 } 442 443 ctx.beginPath(); 444 ctx.moveTo(x + radius, y);
445 ctx.lineTo(x + width - radius, y); 446 ctx.quadraticCurveTo(x + width, y, x + width, y + radius); 447 ctx.lineTo(x + width, y + height - radius); 448 ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height); 449 ctx.lineTo(x + radius, y + height); 450 ctx.quadraticCurveTo(x, y + height, x, y + height - radius); 451 ctx.lineTo(x, y + radius); 452 ctx.quadraticCurveTo(x, y, x + radius, y); 453 ctx.closePath(); 454 ctx.fill(); 455 } 456 /** 457 * Render the actual wave and progress lines 458 * 459 * @param {number[]} peaks Array with peaks data 460 * @param {number} absmax Maximum peak value (absolute) 461 * @param {number} halfH Half the height of the waveform 462 * @param {number} offsetY Offset to the top 463 * @param {number} start The x-offset of the beginning of the area that 464 * should be rendered 465 * @param {number} end The x-offset of the end of the area that 466 * should be rendered 467 */ 468 469 }, { 470 key: "drawLines", 471 value: function drawLines(peaks, absmax, halfH, offsetY, start, end) { 472 this.drawLineToContext(this.waveCtx, peaks, absmax, halfH, offsetY, start, end); 473 474 if (this.hasProgressCanvas) { 475 this.drawLineToContext(this.progressCtx, peaks, absmax, halfH, offsetY, start, end); 476 } 477 } 478 /** 479 * Render the actual waveform line on a `canvas` element 480 * 481 * @private 482 * @param {CanvasRenderingContext2D} ctx Rendering context of target canvas 483 * @param {number[]} peaks Array with peaks data 484 * @param {number} absmax Maximum peak value (absolute) 485 * @param {number} halfH Half the height of the waveform 486 * @param {number} offsetY Offset to the top 487 * @param {number} start The x-offset of the beginning of the area that 488 * should be rendered 489 * @param {number} end The x-offset of the end of the area that 490 * should be rendered 491 */ 492 493 }, { 494 key: "drawLineToContext", 495 value: function drawLineToContext(ctx, peaks, absmax, halfH, offsetY, start, end) { 496 if (!ctx) { 497 return; 498 } 499 500 var length = peaks.length / 2; 501 var first = Math.round(length * this.start); // use one more peak value to make sure we join peaks at ends -- unless, 502 // of course, this is the last canvas 503 504 var last = Math.round(length * this.end) + 1; 505 var canvasStart = first; 506 var canvasEnd = last; 507 var scale = this.wave.width / (canvasEnd - canvasStart - 1); // optimization 508 509 var halfOffset = halfH + offsetY; 510 var absmaxHalf = absmax / halfH; 511 ctx.beginPath(); 512 ctx.moveTo((canvasStart - first) * scale, halfOffset); 513 ctx.lineTo((canvasStart - first) * scale, halfOffset - Math.round((peaks[2 * canvasStart] || 0) / absmaxHalf)); 514 var i, peak, h; 515 516 for (i = canvasStart; i < canvasEnd; i++) { 517 peak = peaks[2 * i] || 0; 518 h = Math.round(peak / absmaxHalf); 519 ctx.lineTo((i - first) * scale + this.halfPixel, halfOffset - h); 520 } // draw the bottom edge going backwards, to make a single 521 // closed hull to fill 522 523 524 var j = canvasEnd - 1; 525 526 for (j; j >= canvasStart; j--) { 527 peak = peaks[2 * j + 1] || 0; 528 h = Math.round(peak / absmaxHalf); 529 ctx.lineTo((j - first) * scale + this.halfPixel, halfOffset - h); 530 } 531 532 ctx.lineTo((canvasStart - first) * scale, halfOffset - Math.round((peaks[2 * canvasStart + 1] || 0) / absmaxHalf)); 533 ctx.closePath(); 534 ctx.fill(); 535 } 536 /** 537 * Destroys this entry 538 */ 539 540 }, { 541 key: "destroy", 542 value: function destroy() { 543 this.waveCtx = null; 544 this.wave = null; 545 this.progressCtx = null; 546 this.progress = null; 547 } 548 /** 549 * Return image data of the wave `canvas` element 550 * 551 * When using a `type` of `'blob'`, this will return a `Promise` that 552 * resolves with a `Blob` instance. 553 * 554 * @param {string} format='image/png' An optional value of a format type. 555 * @param {number} quality=0.92 An optional value between 0 and 1. 556 * @param {string} type='dataURL' Either 'dataURL' or 'blob'. 557 * @return {string|Promise} When using the default `'dataURL'` `type` this 558 * returns a data URL. When using the `'blob'` `type` this returns a 559 * `Promise` that resolves with a `Blob` instance. 560 */ 561 562 }, { 563 key: "getImage", 564 value: function getImage(format, quality, type) { 565 var _this = this; 566 567 if (type === 'blob') { 568 return new Promise(function (resolve) { 569 _this.wave.toBlob(resolve, format, quality); 570 }); 571 } else if (type === 'dataURL') { 572 return this.wave.toDataURL(format, quality); 573 } 574 } 575 }]); 576 577 return CanvasEntry; 578}(); 579 580exports.default = CanvasEntry; 581module.exports = exports.default; 582 583/***/ }), 584
vendor: 4,411 bytes, lines 585-666
585/***/ "./src/drawer.js": 586/*!***********************!*\ 587 !*** ./src/drawer.js ***! 588 \***********************/ 589/*! no static exports found */ 590/***/ (function(module, exports, __webpack_require__) { 591 592"use strict"; 593 594 595Object.defineProperty(exports, "__esModule", { 596 value: true 597}); 598exports.default = void 0; 599 600var util = _interopRequireWildcard(__webpack_require__(/*! ./util */ "./src/util/index.js")); 601 602function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; } 603 604function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } 605 606function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } 607 608function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 609 610function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } 611 612function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } 613 614function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } 615 616function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } 617 618function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } 619 620function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } 621 622function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } 623 624/** 625 * Parent class for renderers 626 * 627 * @extends {Observer} 628 */ 629var Drawer = 630/*#__PURE__*/ 631function (_util$Observer) { 632 _inherits(Drawer, _util$Observer); 633 634 /** 635 * @param {HTMLElement} container The container node of the wavesurfer instance 636 * @param {WavesurferParams} params The wavesurfer initialisation options 637 */ 638 function Drawer(container, params) { 639 var _this; 640 641 _classCallCheck(this, Drawer); 642 643 _this = _possibleConstructorReturn(this, _getPrototypeOf(Drawer).call(this)); 644 /** @private */ 645 646 _this.container = container; 647 /** 648 * @type {WavesurferParams} 649 * @private 650 */ 651 652 _this.params = params; 653 /** 654 * The width of the renderer 655 * @type {number} 656 */ 657 658 _this.width = 0; 659 /** 660 * The height of the renderer 661 * @type {number} 662 */ 663 664 _this.height = params.height * _this.params.pixelRatio; 665 /** @private */ 666
667 _this.lastPos = 0; 668 /** 669 * The `<wave>` element which is added to the container 670 * @type {HTMLElement} 671 */ 672 673 _this.wrapper = null; 674 return _this; 675 } 676 /** 677 * Alias of `util.style` 678 * 679 * @param {HTMLElement} el The element that the styles will be applied to 680 * @param {Object} styles The map of propName: attribute, both are used as-is 681 * @return {HTMLElement} el 682 */ 683 684 685 _createClass(Drawer, [{ 686 key: "style", 687 value: function style(el, styles) { 688 return util.style(el, styles); 689 } 690 /** 691 * Create the wrapper `<wave>` element, style it and set up the events for 692 * interaction 693 */ 694 695 }, { 696 key: "createWrapper", 697 value: function createWrapper() { 698 this.wrapper = this.container.appendChild(document.createElement('wave')); 699 this.style(this.wrapper, { 700 display: 'block', 701 position: 'relative', 702 userSelect: 'none', 703 webkitUserSelect: 'none', 704 height: this.params.height + 'px' 705 }); 706 707 if (this.params.fillParent || this.params.scrollParent) { 708 this.style(this.wrapper, { 709 width: '100%', 710 overflowX: this.params.hideScrollbar ? 'hidden' : 'auto', 711 overflowY: 'hidden' 712 }); 713 } 714 715 this.setupWrapperEvents(); 716 } 717 /** 718 * Handle click event 719 * 720 * @param {Event} e Click event 721 * @param {?boolean} noPrevent Set to true to not call `e.preventDefault()` 722 * @return {number} Playback position from 0 to 1 723 */ 724 725 }, { 726 key: "handleEvent", 727 value: function handleEvent(e, noPrevent) { 728 !noPrevent && e.preventDefault(); 729 var clientX = e.targetTouches ? e.targetTouches[0].clientX : e.clientX; 730 var bbox = this.wrapper.getBoundingClientRect(); 731 var nominalWidth = this.width; 732 var parentWidth = this.getWidth(); 733 var progress; 734 735 if (!this.params.fillParent && nominalWidth < parentWidth) { 736 progress = (this.params.rtl ? bbox.right - clientX : clientX - bbox.left) * (this.params.pixelRatio / nominalWidth) || 0; 737 738 if (progress > 1) { 739 progress = 1; 740 } 741 } else { 742 progress = ((this.params.rtl ? bbox.right - clientX : clientX - bbox.left) + this.wrapper.scrollLeft) / this.wrapper.scrollWidth || 0; 743 } 744 745 return progress; 746 } 747 /** 748 * @private 749 */ 750 751 }, { 752 key: "setupWrapperEvents", 753 value: function setupWrapperEvents() { 754 var _this2 = this; 755 756 this.wrapper.addEventListener('click', function (e) { 757 var scrollbarHeight = _this2.wrapper.offsetHeight - _this2.wrapper.clientHeight; 758 759 if (scrollbarHeight !== 0) { 760 // scrollbar is visible. Check if click was on it 761 var bbox = _this2.wrapper.getBoundingClientRect(); 762 763 if (e.clientY >= bbox.bottom - scrollbarHeight) { 764 // ignore mousedown as it was on the scrollbar 765 return; 766 } 767 } 768 769 if (_this2.params.interact) { 770 _this2.fireEvent('click', e, _this2.handleEvent(e)); 771 } 772 }); 773 this.wrapper.addEventListener('dblclick', function (e) { 774 if (_this2.params.interact) { 775 _this2.fireEvent('dblclick', e, _this2.handleEvent(e)); 776 } 777 }); 778 this.wrapper.addEventListener('scroll', function (e) { 779 return _this2.fireEvent('scroll', e); 780 }); 781 } 782 /** 783 * Draw peaks on the canvas 784 * 785 * @param {number[]|Number.<Array[]>} peaks Can also be an array of arrays 786 * for split channel rendering 787 * @param {number} length The width of the area that should be drawn 788 * @param {number} start The x-offset of the beginning of the area that 789 * should be rendered 790 * @param {number} end The x-offset of the end of the area that should be 791 * rendered 792 */ 793 794 }, { 795 key: "drawPeaks", 796 value: function drawPeaks(peaks, length, start, end) { 797 if (!this.setWidth(length)) { 798 this.clearWave(); 799 } 800 801 this.params.barWidth ? this.drawBars(peaks, 0, start, end) : this.drawWave(peaks, 0, start, end); 802 } 803 /** 804 * Scroll to the beginning 805 */ 806 807 }, { 808 key: "resetScroll", 809 value: function resetScroll() { 810 if (this.wrapper !== null) { 811 this.wrapper.scrollLeft = 0; 812 } 813 } 814 /** 815 * Recenter the view-port at a certain percent of the waveform 816 * 817 * @param {number} percent Value from 0 to 1 on the waveform 818 */ 819 820 }, {
821 key: "recenter", 822 value: function recenter(percent) { 823 var position = this.wrapper.scrollWidth * percent; 824 this.recenterOnPosition(position, true); 825 } 826 /** 827 * Recenter the view-port on a position, either scroll there immediately or 828 * in steps of 5 pixels 829 * 830 * @param {number} position X-offset in pixels 831 * @param {boolean} immediate Set to true to immediately scroll somewhere 832 */ 833 834 }, { 835 key: "recenterOnPosition", 836 value: function recenterOnPosition(position, immediate) { 837 var scrollLeft = this.wrapper.scrollLeft; 838 var half = ~~(this.wrapper.clientWidth / 2); 839 var maxScroll = this.wrapper.scrollWidth - this.wrapper.clientWidth; 840 var target = position - half; 841 var offset = target - scrollLeft; 842 843 if (maxScroll == 0) { 844 // no need to continue if scrollbar is not there 845 return; 846 } // if the cursor is currently visible... 847 848 849 if (!immediate && -half <= offset && offset < half) { 850 // set rate at which waveform is centered 851 var rate = this.params.autoCenterRate; // make rate depend on width of view and length of waveform 852 853 rate /= half; 854 rate *= maxScroll; 855 offset = Math.max(-rate, Math.min(rate, offset)); 856 target = scrollLeft + offset; 857 } // limit target to valid range (0 to maxScroll) 858 859 860 target = Math.max(0, Math.min(maxScroll, target)); // no use attempting to scroll if we're not moving 861 862 if (target != scrollLeft) { 863 this.wrapper.scrollLeft = target; 864 } 865 } 866 /** 867 * Get the current scroll position in pixels 868 * 869 * @return {number} Horizontal scroll position in pixels 870 */ 871 872 }, { 873 key: "getScrollX", 874 value: function getScrollX() { 875 var x = 0; 876 877 if (this.wrapper) { 878 var pixelRatio = this.params.pixelRatio; 879 x = Math.round(this.wrapper.scrollLeft * pixelRatio); // In cases of elastic scroll (safari with mouse wheel) you can 880 // scroll beyond the limits of the container 881 // Calculate and floor the scrollable extent to make sure an out 882 // of bounds value is not returned 883 // Ticket #1312 884 885 if (this.params.scrollParent) { 886 var maxScroll = ~~(this.wrapper.scrollWidth * pixelRatio - this.getWidth()); 887 x = Math.min(maxScroll, Math.max(0, x)); 888 } 889 } 890 891 return x; 892 } 893 /** 894 * Get the width of the container 895 * 896 * @return {number} The width of the container 897 */ 898 899 }, { 900 key: "getWidth", 901 value: function getWidth() { 902 return Math.round(this.container.clientWidth * this.params.pixelRatio); 903 } 904 /** 905 * Set the width of the container 906 * 907 * @param {number} width The new width of the container 908 * @return {boolean} Whether the width of the container was updated or not 909 */ 910 911 }, { 912 key: "setWidth", 913 value: function setWidth(width) { 914 if (this.width == width) { 915 return false; 916 } 917 918 this.width = width; 919 920 if (this.params.fillParent || this.params.scrollParent) { 921 this.style(this.wrapper, { 922 width: '' 923 }); 924 } else { 925 this.style(this.wrapper, { 926 width: ~~(this.width / this.params.pixelRatio) + 'px' 927 }); 928 } 929 930 this.updateSize(); 931 return true; 932 } 933 /** 934 * Set the height of the container 935 * 936 * @param {number} height The new height of the container. 937 * @return {boolean} Whether the height of the container was updated or not 938 */ 939 940 }, { 941 key: "setHeight", 942 value: function setHeight(height) { 943 if (height == this.height) { 944 return false; 945 } 946 947 this.height = height; 948 this.style(this.wrapper, { 949 height: ~~(this.height / this.params.pixelRatio) + 'px' 950 }); 951 this.updateSize(); 952 return true; 953 } 954 /** 955 * Called by wavesurfer when progress should be rendered 956 * 957 * @param {number} progress From 0 to 1 958 */ 959 960 }, { 961 key: "progress", 962 value: function progress(_progress) { 963 var minPxDelta = 1 / this.params.pixelRatio; 964 var pos = Math.round(_progress * this.width) * minPxDelta; 965 966 if (pos < this.lastPos || pos - this.lastPos >= minPxDelta) {
967 this.lastPos = pos; 968 969 if (this.params.scrollParent && this.params.autoCenter) { 970 var newPos = ~~(this.wrapper.scrollWidth * _progress); 971 this.recenterOnPosition(newPos, this.params.autoCenterImmediately); 972 } 973 974 this.updateProgress(pos); 975 } 976 } 977 /** 978 * This is called when wavesurfer is destroyed 979 */ 980 981 }, { 982 key: "destroy", 983 value: function destroy() { 984 this.unAll(); 985 986 if (this.wrapper) { 987 if (this.wrapper.parentNode == this.container) { 988 this.container.removeChild(this.wrapper); 989 } 990 991 this.wrapper = null; 992 } 993 } 994 /* Renderer-specific methods */ 995 996 /** 997 * Called after cursor related params have changed. 998 * 999 * @abstract 1000 */ 1001 1002 }, { 1003 key: "updateCursor", 1004 value: function updateCursor() {} 1005 /** 1006 * Called when the size of the container changes so the renderer can adjust 1007 * 1008 * @abstract 1009 */ 1010 1011 }, { 1012 key: "updateSize", 1013 value: function updateSize() {} 1014 /** 1015 * Draw a waveform with bars 1016 * 1017 * @abstract 1018 * @param {number[]|Number.<Array[]>} peaks Can also be an array of arrays for split channel 1019 * rendering 1020 * @param {number} channelIndex The index of the current channel. Normally 1021 * should be 0 1022 * @param {number} start The x-offset of the beginning of the area that 1023 * should be rendered 1024 * @param {number} end The x-offset of the end of the area that should be 1025 * rendered 1026 */ 1027 1028 }, { 1029 key: "drawBars", 1030 value: function drawBars(peaks, channelIndex, start, end) {} 1031 /** 1032 * Draw a waveform 1033 * 1034 * @abstract 1035 * @param {number[]|Number.<Array[]>} peaks Can also be an array of arrays for split channel 1036 * rendering 1037 * @param {number} channelIndex The index of the current channel. Normally 1038 * should be 0 1039 * @param {number} start The x-offset of the beginning of the area that 1040 * should be rendered 1041 * @param {number} end The x-offset of the end of the area that should be 1042 * rendered 1043 */ 1044 1045 }, { 1046 key: "drawWave", 1047 value: function drawWave(peaks, channelIndex, start, end) {} 1048 /** 1049 * Clear the waveform 1050 * 1051 * @abstract 1052 */ 1053 1054 }, { 1055 key: "clearWave", 1056 value: function clearWave() {} 1057 /** 1058 * Render the new progress 1059 * 1060 * @abstract 1061 * @param {number} position X-Offset of progress position in pixels 1062 */ 1063 1064 }, { 1065 key: "updateProgress", 1066 value: function updateProgress(position) {} 1067 }]); 1068 1069 return Drawer; 1070}(util.Observer); 1071 1072exports.default = Drawer; 1073module.exports = exports.default; 1074 1075/***/ }), 1076
1077/***/ "./src/drawer.multicanvas.js": 1078/*!***********************************!*\ 1079 !*** ./src/drawer.multicanvas.js ***! 1080 \***********************************/ 1081/*! no static exports found */ 1082/***/ (function(module, exports, __webpack_require__) { 1083 1084"use strict"; 1085 1086 1087Object.defineProperty(exports, "__esModule", { 1088 value: true 1089}); 1090exports.default = void 0; 1091 1092var _drawer = _interopRequireDefault(__webpack_require__(/*! ./drawer */ "./src/drawer.js")); 1093 1094var util = _interopRequireWildcard(__webpack_require__(/*! ./util */ "./src/util/index.js")); 1095 1096var _drawer2 = _interopRequireDefault(__webpack_require__(/*! ./drawer.canvasentry */ "./src/drawer.canvasentry.js")); 1097 1098function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; } 1099 1100function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } 1101 1102function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 1103 1104function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } 1105 1106function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 1107 1108function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } 1109 1110function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } 1111 1112function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } 1113 1114function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } 1115 1116function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } 1117 1118function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } 1119 1120function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } 1121 1122/** 1123 * MultiCanvas renderer for wavesurfer. Is currently the default and sole 1124 * builtin renderer. 1125 * 1126 * A `MultiCanvas` consists of one or more `CanvasEntry` instances, depending 1127 * on the zoom level. 1128 */ 1129var MultiCanvas = 1130/*#__PURE__*/ 1131function (_Drawer) { 1132 _inherits(MultiCanvas, _Drawer); 1133 1134 /** 1135 * @param {HTMLElement} container The container node of the wavesurfer instance 1136 * @param {WavesurferParams} params The wavesurfer initialisation options 1137 */ 1138 function MultiCanvas(container, params) { 1139 var _this; 1140 1141 _classCallCheck(this, MultiCanvas); 1142 1143 _this = _possibleConstructorReturn(this, _getPrototypeOf(MultiCanvas).call(this, container, params)); 1144 /** 1145 * @type {number} 1146 * @private 1147 */ 1148 1149 _this.maxCanvasWidth = params.maxCanvasWidth; 1150 /** 1151 * @private 1152 * @type {number} 1153 */ 1154 1155 _this.maxCanvasElementWidth = Math.round(params.maxCanvasWidth / params.pixelRatio); 1156 /** 1157 * Whether or not the progress wave is rendered. If the `waveColor` 1158 * and `progressColor` are the same color it is not. 1159 * 1160 * @type {boolean} 1161 */ 1162 1163 _this.hasProgressCanvas = params.waveColor != params.progressColor; 1164 /** 1165 * @private 1166 * @type {number} 1167 */ 1168 1169 _this.halfPixel = 0.5 / params.pixelRatio; 1170 /** 1171 * List of `CanvasEntry` instances. 1172 * 1173 * @private 1174 * @type {Array} 1175 */ 1176
1177 _this.canvases = []; 1178 /** 1179 * @private 1180 * @type {HTMLElement} 1181 */ 1182 1183 _this.progressWave = null; 1184 /** 1185 * Class used to generate entries. 1186 * 1187 * @private 1188 * @type {function} 1189 */ 1190 1191 _this.EntryClass = _drawer2.default; 1192 /** 1193 * Canvas 2d context attributes. 1194 * 1195 * @private 1196 * @type {object} 1197 */ 1198 1199 _this.canvasContextAttributes = params.drawingContextAttributes; 1200 /** 1201 * Overlap added between entries to prevent vertical white stripes 1202 * between `canvas` elements. 1203 * 1204 * @type {number} 1205 */ 1206 1207 _this.overlap = 2 * Math.ceil(params.pixelRatio / 2); 1208 /** 1209 * The radius of the wave bars. Makes bars rounded 1210 * 1211 * @private 1212 * @type {number} 1213 */ 1214 1215 _this.barRadius = params.barRadius || 0; 1216 return _this; 1217 } 1218 /** 1219 * Initialize the drawer 1220 */ 1221 1222 1223 _createClass(MultiCanvas, [{ 1224 key: "init", 1225 value: function init() { 1226 this.createWrapper(); 1227 this.createElements(); 1228 } 1229 /** 1230 * Create the canvas elements and style them 1231 * 1232 * @private 1233 */ 1234 1235 }, { 1236 key: "createElements", 1237 value: function createElements() { 1238 this.progressWave = this.wrapper.appendChild(this.style(document.createElement('wave'), { 1239 position: 'absolute', 1240 zIndex: 3, 1241 left: 0, 1242 top: 0, 1243 bottom: 0, 1244 overflow: 'hidden', 1245 width: '0', 1246 display: 'none', 1247 boxSizing: 'border-box', 1248 borderRightStyle: 'solid', 1249 pointerEvents: 'none' 1250 })); 1251 this.addCanvas(); 1252 this.updateCursor(); 1253 } 1254 /** 1255 * Update cursor style 1256 */ 1257 1258 }, { 1259 key: "updateCursor", 1260 value: function updateCursor() { 1261 this.style(this.progressWave, { 1262 borderRightWidth: this.params.cursorWidth + 'px', 1263 borderRightColor: this.params.cursorColor 1264 }); 1265 } 1266 /** 1267 * Adjust to the updated size by adding or removing canvases 1268 */ 1269 1270 }, { 1271 key: "updateSize", 1272 value: function updateSize() { 1273 var _this2 = this; 1274 1275 var totalWidth = Math.round(this.width / this.params.pixelRatio); 1276 var requiredCanvases = Math.ceil(totalWidth / (this.maxCanvasElementWidth + this.overlap)); // add required canvases 1277 1278 while (this.canvases.length < requiredCanvases) { 1279 this.addCanvas(); 1280 } // remove older existing canvases, if any 1281 1282 1283 while (this.canvases.length > requiredCanvases) { 1284 this.removeCanvas(); 1285 } 1286 1287 var canvasWidth = this.maxCanvasWidth + this.overlap; 1288 var lastCanvas = this.canvases.length - 1; 1289 this.canvases.forEach(function (entry, i) { 1290 if (i == lastCanvas) { 1291 canvasWidth = _this2.width - _this2.maxCanvasWidth * lastCanvas; 1292 } 1293 1294 _this2.updateDimensions(entry, canvasWidth, _this2.height); 1295 1296 entry.clearWave(); 1297 }); 1298 } 1299 /** 1300 * Add a canvas to the canvas list 1301 * 1302 * @private 1303 */ 1304 1305 }, { 1306 key: "addCanvas", 1307 value: function addCanvas() { 1308 var entry = new this.EntryClass(); 1309 entry.canvasContextAttributes = this.canvasContextAttributes; 1310 entry.hasProgressCanvas = this.hasProgressCanvas; 1311 entry.halfPixel = this.halfPixel; 1312 var leftOffset = this.maxCanvasElementWidth * this.canvases.length; // wave 1313 1314 entry.initWave(this.wrapper.appendChild(this.style(document.createElement('canvas'), { 1315 position: 'absolute', 1316 zIndex: 2, 1317 left: leftOffset + 'px', 1318 top: 0, 1319 bottom: 0, 1320 height: '100%', 1321 pointerEvents: 'none' 1322 }))); // progress 1323 1324 if (this.hasProgressCanvas) { 1325 entry.initProgress(this.progressWave.appendChild(this.style(document.createElement('canvas'), { 1326 position: 'absolute', 1327 left: leftOffset + 'px', 1328 top: 0, 1329 bottom: 0, 1330 height: '100%' 1331 }))); 1332 } 1333 1334 this.canvases.push(entry); 1335 } 1336 /** 1337 * Pop single canvas from the list 1338 * 1339 * @private 1340 */ 1341 1342 }, { 1343 key: "removeCanvas", 1344 value: function removeCanvas() {
1345 var lastEntry = this.canvases[this.canvases.length - 1]; // wave 1346 1347 lastEntry.wave.parentElement.removeChild(lastEntry.wave); // progress 1348 1349 if (this.hasProgressCanvas) { 1350 lastEntry.progress.parentElement.removeChild(lastEntry.progress); 1351 } // cleanup 1352 1353 1354 if (lastEntry) { 1355 lastEntry.destroy(); 1356 lastEntry = null; 1357 } 1358 1359 this.canvases.pop(); 1360 } 1361 /** 1362 * Update the dimensions of a canvas element 1363 * 1364 * @private 1365 * @param {CanvasEntry} entry Target entry 1366 * @param {number} width The new width of the element 1367 * @param {number} height The new height of the element 1368 */ 1369 1370 }, { 1371 key: "updateDimensions", 1372 value: function updateDimensions(entry, width, height) { 1373 var elementWidth = Math.round(width / this.params.pixelRatio); 1374 var totalWidth = Math.round(this.width / this.params.pixelRatio); // update canvas dimensions 1375 1376 entry.updateDimensions(elementWidth, totalWidth, width, height); // style element 1377 1378 this.style(this.progressWave, { 1379 display: 'block' 1380 }); 1381 } 1382 /** 1383 * Clear the whole multi-canvas 1384 */ 1385 1386 }, { 1387 key: "clearWave", 1388 value: function clearWave() { 1389 var _this3 = this; 1390 1391 util.frame(function () { 1392 _this3.canvases.forEach(function (entry) { 1393 return entry.clearWave(); 1394 }); 1395 })(); 1396 } 1397 /** 1398 * Draw a waveform with bars 1399 * 1400 * @param {number[]|Number.<Array[]>} peaks Can also be an array of arrays 1401 * for split channel rendering 1402 * @param {number} channelIndex The index of the current channel. Normally 1403 * should be 0. Must be an integer. 1404 * @param {number} start The x-offset of the beginning of the area that 1405 * should be rendered 1406 * @param {number} end The x-offset of the end of the area that should be 1407 * rendered 1408 * @returns {void} 1409 */ 1410 1411 }, { 1412 key: "drawBars", 1413 value: function drawBars(peaks, channelIndex, start, end) { 1414 var _this4 = this; 1415 1416 return this.prepareDraw(peaks, channelIndex, start, end, function (_ref) { 1417 var absmax = _ref.absmax, 1418 hasMinVals = _ref.hasMinVals, 1419 height = _ref.height, 1420 offsetY = _ref.offsetY, 1421 halfH = _ref.halfH, 1422 peaks = _ref.peaks; 1423 1424 // if drawBars was called within ws.empty we don't pass a start and 1425 // don't want anything to happen 1426 if (start === undefined) { 1427 return; 1428 } // Skip every other value if there are negatives. 1429 1430 1431 var peakIndexScale = hasMinVals ? 2 : 1; 1432 var length = peaks.length / peakIndexScale; 1433 var bar = _this4.params.barWidth * _this4.params.pixelRatio; 1434 var gap = _this4.params.barGap === null ? Math.max(_this4.params.pixelRatio, ~~(bar / 2)) : Math.max(_this4.params.pixelRatio, _this4.params.barGap * _this4.params.pixelRatio); 1435 var step = bar + gap; 1436 var scale = length / _this4.width; 1437 var first = start; 1438 var last = end; 1439 var i = first; 1440 1441 for (i; i < last; i += step) { 1442 var peak = peaks[Math.floor(i * scale * peakIndexScale)] || 0; 1443 var h = Math.round(peak / absmax * halfH); 1444 /* in case of silences, allow the user to specify that we 1445 * always draw *something* (normally a 1px high bar) */ 1446 1447 if (h == 0 && _this4.params.barMinHeight) h = _this4.params.barMinHeight; 1448 1449 _this4.fillRect(i + _this4.halfPixel, halfH - h + offsetY, bar + _this4.halfPixel, h * 2, _this4.barRadius); 1450 } 1451 }); 1452 } 1453 /** 1454 * Draw a waveform 1455 * 1456 * @param {number[]|Number.<Array[]>} peaks Can also be an array of arrays 1457 * for split channel rendering 1458 * @param {number} channelIndex The index of the current channel. Normally 1459 * should be 0 1460 * @param {number?} start The x-offset of the beginning of the area that 1461 * should be rendered (If this isn't set only a flat line is rendered) 1462 * @param {number?} end The x-offset of the end of the area that should be 1463 * rendered 1464 * @returns {void} 1465 */ 1466 1467 }, { 1468 key: "drawWave", 1469 value: function drawWave(peaks, channelIndex, start, end) { 1470 var _this5 = this; 1471 1472 return this.prepareDraw(peaks, channelIndex, start, end, function (_ref2) { 1473 var absmax = _ref2.absmax, 1474 hasMinVals = _ref2.hasMinVals, 1475 height = _ref2.height, 1476 offsetY = _ref2.offsetY, 1477 halfH = _ref2.halfH, 1478 peaks = _ref2.peaks; 1479 1480 if (!hasMinVals) { 1481 var reflectedPeaks = []; 1482 var len = peaks.length; 1483 var i = 0; 1484 1485 for (i; i < len; i++) { 1486 reflectedPeaks[2 * i] = peaks[i];
1487 reflectedPeaks[2 * i + 1] = -peaks[i]; 1488 } 1489 1490 peaks = reflectedPeaks; 1491 } // if drawWave was called within ws.empty we don't pass a start and 1492 // end and simply want a flat line 1493 1494 1495 if (start !== undefined) { 1496 _this5.drawLine(peaks, absmax, halfH, offsetY, start, end); 1497 } // always draw a median line 1498 1499 1500 _this5.fillRect(0, halfH + offsetY - _this5.halfPixel, _this5.width, _this5.halfPixel, _this5.barRadius); 1501 }); 1502 } 1503 /** 1504 * Tell the canvas entries to render their portion of the waveform 1505 * 1506 * @private 1507 * @param {number[]} peaks Peaks data 1508 * @param {number} absmax Maximum peak value (absolute) 1509 * @param {number} halfH Half the height of the waveform 1510 * @param {number} offsetY Offset to the top 1511 * @param {number} start The x-offset of the beginning of the area that 1512 * should be rendered 1513 * @param {number} end The x-offset of the end of the area that 1514 * should be rendered 1515 */ 1516 1517 }, { 1518 key: "drawLine", 1519 value: function drawLine(peaks, absmax, halfH, offsetY, start, end) { 1520 var _this6 = this; 1521 1522 this.canvases.forEach(function (entry) { 1523 _this6.setFillStyles(entry); 1524 1525 entry.drawLines(peaks, absmax, halfH, offsetY, start, end); 1526 }); 1527 } 1528 /** 1529 * Draw a rectangle on the multi-canvas 1530 * 1531 * @param {number} x X-position of the rectangle 1532 * @param {number} y Y-position of the rectangle 1533 * @param {number} width Width of the rectangle 1534 * @param {number} height Height of the rectangle 1535 * @param {number} radius Radius of the rectangle 1536 */ 1537 1538 }, { 1539 key: "fillRect", 1540 value: function fillRect(x, y, width, height, radius) { 1541 var startCanvas = Math.floor(x / this.maxCanvasWidth); 1542 var endCanvas = Math.min(Math.ceil((x + width) / this.maxCanvasWidth) + 1, this.canvases.length); 1543 var i = startCanvas; 1544 1545 for (i; i < endCanvas; i++) { 1546 var entry = this.canvases[i]; 1547 var leftOffset = i * this.maxCanvasWidth; 1548 var intersection = { 1549 x1: Math.max(x, i * this.maxCanvasWidth), 1550 y1: y, 1551 x2: Math.min(x + width, i * this.maxCanvasWidth + entry.wave.width), 1552 y2: y + height 1553 }; 1554 1555 if (intersection.x1 < intersection.x2) { 1556 this.setFillStyles(entry); 1557 entry.fillRects(intersection.x1 - leftOffset, intersection.y1, intersection.x2 - intersection.x1, intersection.y2 - intersection.y1, radius); 1558 } 1559 } 1560 } 1561 /** 1562 * Performs preparation tasks and calculations which are shared by `drawBars` 1563 * and `drawWave` 1564 * 1565 * @private 1566 * @param {number[]|Number.<Array[]>} peaks Can also be an array of arrays for 1567 * split channel rendering 1568 * @param {number} channelIndex The index of the current channel. Normally 1569 * should be 0 1570 * @param {number?} start The x-offset of the beginning of the area that 1571 * should be rendered. If this isn't set only a flat line is rendered 1572 * @param {number?} end The x-offset of the end of the area that should be 1573 * rendered 1574 * @param {function} fn The render function to call, e.g. `drawWave` 1575 * @returns {void} 1576 */ 1577 1578 }, { 1579 key: "prepareDraw", 1580 value: function prepareDraw(peaks, channelIndex, start, end, fn) { 1581 var _this7 = this; 1582 1583 return util.frame(function () { 1584 // Split channels and call this function with the channelIndex set 1585 if (peaks[0] instanceof Array) { 1586 var channels = peaks; 1587 1588 if (_this7.params.splitChannels) { 1589 _this7.setHeight(channels.length * _this7.params.height * _this7.params.pixelRatio); 1590 1591 return channels.forEach(function (channelPeaks, i) { 1592 return _this7.prepareDraw(channelPeaks, i, start, end, fn); 1593 }); 1594 } 1595 1596 peaks = channels[0]; 1597 } // calculate maximum modulation value, either from the barHeight 1598 // parameter or if normalize=true from the largest value in the peak 1599 // set 1600 1601 1602 var absmax = 1 / _this7.params.barHeight; 1603 1604 if (_this7.params.normalize) { 1605 var max = util.max(peaks); 1606 var min = util.min(peaks); 1607 absmax = -min > max ? -min : max; 1608 } // Bar wave draws the bottom only as a reflection of the top, 1609 // so we don't need negative values 1610 1611 1612 var hasMinVals = [].some.call(peaks, function (val) { 1613 return val < 0; 1614 }); 1615 var height = _this7.params.height * _this7.params.pixelRatio; 1616 var offsetY = height * channelIndex || 0; 1617 var halfH = height / 2; 1618 return fn({ 1619 absmax: absmax, 1620 hasMinVals: hasMinVals, 1621 height: height, 1622 offsetY: offsetY, 1623 halfH: halfH, 1624 peaks: peaks 1625 }); 1626 })(); 1627 } 1628 /** 1629 * Set the fill styles for a certain entry (wave and progress) 1630 * 1631 * @private 1632 * @param {CanvasEntry} entry Target entry 1633 */ 1634 1635 }, { 1636 key: "setFillStyles", 1637 value: function setFillStyles(entry) { 1638 entry.setFillStyles(this.params.waveColor, this.params.progressColor); 1639 } 1640 /** 1641 * Return image data of the multi-canvas 1642 * 1643 * When using a `type` of `'blob'`, this will return a `Promise`. 1644 * 1645 * @param {string} format='image/png' An optional value of a format type. 1646 * @param {number} quality=0.92 An optional value between 0 and 1. 1647 * @param {string} type='dataURL' Either 'dataURL' or 'blob'. 1648 * @return {string|string[]|Promise} When using the default `'dataURL'` 1649 * `type` this returns a single data URL or an array of data URLs, 1650 * one for each canvas. When using the `'blob'` `type` this returns a 1651 * `Promise` that resolves with an array of `Blob` instances, one for each 1652 * canvas. 1653 */ 1654 1655 }, { 1656 key: "getImage", 1657 value: function getImage(format, quality, type) { 1658 if (type === 'blob') {
1659 return Promise.all(this.canvases.map(function (entry) { 1660 return entry.getImage(format, quality, type); 1661 })); 1662 } else if (type === 'dataURL') { 1663 var images = this.canvases.map(function (entry) { 1664 return entry.getImage(format, quality, type); 1665 }); 1666 return images.length > 1 ? images : images[0]; 1667 } 1668 } 1669 /** 1670 * Render the new progress 1671 * 1672 * @param {number} position X-offset of progress position in pixels 1673 */ 1674 1675 }, { 1676 key: "updateProgress", 1677 value: function updateProgress(position) { 1678 this.style(this.progressWave, { 1679 width: position + 'px' 1680 }); 1681 } 1682 }]); 1683 1684 return MultiCanvas; 1685}(_drawer.default); 1686 1687exports.default = MultiCanvas; 1688module.exports = exports.default; 1689 1690/***/ }), 1691
vendor: 4,817 bytes, lines 1692-1773
1692/***/ "./src/mediaelement-webaudio.js": 1693/*!**************************************!*\ 1694 !*** ./src/mediaelement-webaudio.js ***! 1695 \**************************************/ 1696/*! no static exports found */ 1697/***/ (function(module, exports, __webpack_require__) { 1698 1699"use strict"; 1700 1701 1702Object.defineProperty(exports, "__esModule", { 1703 value: true 1704}); 1705exports.default = void 0; 1706 1707var _mediaelement = _interopRequireDefault(__webpack_require__(/*! ./mediaelement */ "./src/mediaelement.js")); 1708 1709function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 1710 1711function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } 1712 1713function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 1714 1715function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } 1716 1717function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } 1718 1719function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } 1720 1721function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } 1722 1723function _get(target, property, receiver) { if (typeof Reflect !== "undefined" && Reflect.get) { _get = Reflect.get; } else { _get = function _get(target, property, receiver) { var base = _superPropBase(target, property); if (!base) return; var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(receiver); } return desc.value; }; } return _get(target, property, receiver || target); } 1724 1725function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; } 1726 1727function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } 1728 1729function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } 1730 1731function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } 1732 1733/** 1734 * MediaElementWebAudio backend: allows to load audio as HTML5 audio tag and use it with WebAudio API. 1735 * Setting the MediaElementWebAudio backend, there is the possibility to load audio of big dimensions, using the WebAudio API features. 1736 * The audio to load is an HTML5 audio tag, so you have to use the same methods of MediaElement backend for loading and playback. 1737 * In this way, the audio resource is not loaded entirely from server, but in ranges, since you load an HTML5 audio tag. 1738 * In this way, filters and other functionalities can be performed like with WebAudio backend, but without decoding 1739 * internally audio data, that caused crashing of the browser. You have to give also peaks, so the audio data are not decoded. 1740 * 1741 * @since 3.2.0 1742 */ 1743var MediaElementWebAudio = 1744/*#__PURE__*/ 1745function (_MediaElement) { 1746 _inherits(MediaElementWebAudio, _MediaElement); 1747 1748 /** 1749 * Construct the backend 1750 * 1751 * @param {WavesurferParams} params Wavesurfer parameters 1752 */ 1753 function MediaElementWebAudio(params) { 1754 var _this; 1755 1756 _classCallCheck(this, MediaElementWebAudio); 1757 1758 _this = _possibleConstructorReturn(this, _getPrototypeOf(MediaElementWebAudio).call(this, params)); 1759 /** @private */ 1760 1761 _this.params = params; 1762 /** @private */ 1763 1764 _this.sourceMediaElement = null; 1765 return _this; 1766 } 1767 /** 1768 * Initialise the backend, called in `wavesurfer.createBackend()` 1769 */ 1770 1771 1772 _createClass(MediaElementWebAudio, [{ 1773 key: "init",
1774 value: function init() { 1775 this.setPlaybackRate(this.params.audioRate); 1776 this.createTimer(); 1777 this.createVolumeNode(); 1778 this.createScriptNode(); 1779 this.createAnalyserNode(); 1780 } 1781 /** 1782 * Private method called by both `load` (from url) 1783 * and `loadElt` (existing media element) methods. 1784 * 1785 * @param {HTMLMediaElement} media HTML5 Audio or Video element 1786 * @param {number[]|Number.<Array[]>} peaks Array of peak data 1787 * @private 1788 */ 1789 1790 }, { 1791 key: "_load", 1792 value: function _load(media, peaks) { 1793 _get(_getPrototypeOf(MediaElementWebAudio.prototype), "_load", this).call(this, media, peaks); 1794 1795 this.createMediaElementSource(media); 1796 } 1797 /** 1798 * Create MediaElementSource node 1799 * 1800 * @since 3.2.0 1801 * @param {HTMLMediaElement} mediaElement HTML5 Audio to load 1802 */ 1803 1804 }, { 1805 key: "createMediaElementSource", 1806 value: function createMediaElementSource(mediaElement) { 1807 this.sourceMediaElement = this.ac.createMediaElementSource(mediaElement); 1808 this.sourceMediaElement.connect(this.analyser); 1809 } 1810 }]); 1811 1812 return MediaElementWebAudio; 1813}(_mediaelement.default); 1814 1815exports.default = MediaElementWebAudio; 1816module.exports = exports.default; 1817 1818/***/ }), 1819
1820/***/ "./src/mediaelement.js": 1821/*!*****************************!*\ 1822 !*** ./src/mediaelement.js ***! 1823 \*****************************/ 1824/*! no static exports found */ 1825/***/ (function(module, exports, __webpack_require__) { 1826 1827"use strict"; 1828 1829 1830Object.defineProperty(exports, "__esModule", { 1831 value: true 1832}); 1833exports.default = void 0; 1834 1835var _webaudio = _interopRequireDefault(__webpack_require__(/*! ./webaudio */ "./src/webaudio.js")); 1836 1837var util = _interopRequireWildcard(__webpack_require__(/*! ./util */ "./src/util/index.js")); 1838 1839function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; } 1840 1841function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } 1842 1843function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 1844 1845function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } 1846 1847function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 1848 1849function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } 1850 1851function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } 1852 1853function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } 1854 1855function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } 1856 1857function _get(target, property, receiver) { if (typeof Reflect !== "undefined" && Reflect.get) { _get = Reflect.get; } else { _get = function _get(target, property, receiver) { var base = _superPropBase(target, property); if (!base) return; var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(receiver); } return desc.value; }; } return _get(target, property, receiver || target); } 1858 1859function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; } 1860 1861function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } 1862 1863function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } 1864 1865function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } 1866 1867/** 1868 * MediaElement backend 1869 */ 1870var MediaElement = 1871/*#__PURE__*/ 1872function (_WebAudio) { 1873 _inherits(MediaElement, _WebAudio); 1874 1875 /** 1876 * Construct the backend 1877 * 1878 * @param {WavesurferParams} params Wavesurfer parameters 1879 */ 1880 function MediaElement(params) { 1881 var _this; 1882 1883 _classCallCheck(this, MediaElement); 1884 1885 _this = _possibleConstructorReturn(this, _getPrototypeOf(MediaElement).call(this, params)); 1886 /** @private */ 1887 1888 _this.params = params; 1889 /** 1890 * Initially a dummy media element to catch errors. Once `_load` is 1891 * called, this will contain the actual `HTMLMediaElement`. 1892 * @private 1893 */ 1894 1895 _this.media = { 1896 currentTime: 0, 1897 duration: 0, 1898 paused: true, 1899 playbackRate: 1, 1900 play: function play() {}, 1901 pause: function pause() {}, 1902 volume: 0 1903 }; 1904 /** @private */ 1905 1906 _this.mediaType = params.mediaType.toLowerCase(); 1907 /** @private */ 1908 1909 _this.elementPosition = params.elementPosition; 1910 /** @private */ 1911 1912 _this.peaks = null; 1913 /** @private */ 1914 1915 _this.playbackRate = 1; 1916 /** @private */ 1917 1918 _this.volume = 1; 1919 /** @private */ 1920 1921 _this.isMuted = false;
1922 /** @private */ 1923 1924 _this.buffer = null; 1925 /** @private */ 1926 1927 _this.onPlayEnd = null; 1928 /** @private */ 1929 1930 _this.mediaListeners = {}; 1931 return _this; 1932 } 1933 /** 1934 * Initialise the backend, called in `wavesurfer.createBackend()` 1935 */ 1936 1937 1938 _createClass(MediaElement, [{ 1939 key: "init", 1940 value: function init() { 1941 this.setPlaybackRate(this.params.audioRate); 1942 this.createTimer(); 1943 } 1944 /** 1945 * Attach event listeners to media element. 1946 */ 1947 1948 }, { 1949 key: "_setupMediaListeners", 1950 value: function _setupMediaListeners() { 1951 var _this2 = this; 1952 1953 this.mediaListeners.error = function () { 1954 _this2.fireEvent('error', 'Error loading media element'); 1955 }; 1956 1957 this.mediaListeners.canplay = function () { 1958 _this2.fireEvent('canplay'); 1959 }; 1960 1961 this.mediaListeners.ended = function () { 1962 _this2.fireEvent('finish'); 1963 }; // listen to and relay play, pause and seeked events to enable 1964 // playback control from the external media element 1965 1966 1967 this.mediaListeners.play = function () { 1968 _this2.fireEvent('play'); 1969 }; 1970 1971 this.mediaListeners.pause = function () { 1972 _this2.fireEvent('pause'); 1973 }; 1974 1975 this.mediaListeners.seeked = function (event) { 1976 _this2.fireEvent('seek'); 1977 }; 1978 1979 this.mediaListeners.volumechange = function (event) { 1980 _this2.isMuted = _this2.media.muted; 1981 1982 if (_this2.isMuted) { 1983 _this2.volume = 0; 1984 } else { 1985 _this2.volume = _this2.media.volume; 1986 } 1987 1988 _this2.fireEvent('volume'); 1989 }; // reset event listeners 1990 1991 1992 Object.keys(this.mediaListeners).forEach(function (id) { 1993 _this2.media.removeEventListener(id, _this2.mediaListeners[id]); 1994 1995 _this2.media.addEventListener(id, _this2.mediaListeners[id]); 1996 }); 1997 } 1998 /** 1999 * Create a timer to provide a more precise `audioprocess` event. 2000 */ 2001 2002 }, { 2003 key: "createTimer", 2004 value: function createTimer() { 2005 var _this3 = this; 2006 2007 var onAudioProcess = function onAudioProcess() { 2008 if (_this3.isPaused()) { 2009 return; 2010 } 2011 2012 _this3.fireEvent('audioprocess', _this3.getCurrentTime()); // Call again in the next frame 2013 2014 2015 util.frame(onAudioProcess)(); 2016 }; 2017 2018 this.on('play', onAudioProcess); // Update the progress one more time to prevent it from being stuck in 2019 // case of lower framerates 2020 2021 this.on('pause', function () { 2022 _this3.fireEvent('audioprocess', _this3.getCurrentTime()); 2023 }); 2024 } 2025 /** 2026 * Create media element with url as its source, 2027 * and append to container element. 2028 * 2029 * @param {string} url Path to media file 2030 * @param {HTMLElement} container HTML element 2031 * @param {number[]|Number.<Array[]>} peaks Array of peak data 2032 * @param {string} preload HTML 5 preload attribute value 2033 * @throws Will throw an error if the `url` argument is not a valid media 2034 * element. 2035 */ 2036 2037 }, { 2038 key: "load", 2039 value: function load(url, container, peaks, preload) { 2040 var media = document.createElement(this.mediaType); 2041 media.controls = this.params.mediaControls; 2042 media.autoplay = this.params.autoplay || false; 2043 media.preload = preload == null ? 'auto' : preload; 2044 media.src = url; 2045 media.style.width = '100%'; 2046 var prevMedia = container.querySelector(this.mediaType); 2047 2048 if (prevMedia) { 2049 container.removeChild(prevMedia); 2050 } 2051 2052 container.appendChild(media); 2053 2054 this._load(media, peaks); 2055 } 2056 /** 2057 * Load existing media element. 2058 * 2059 * @param {HTMLMediaElement} elt HTML5 Audio or Video element 2060 * @param {number[]|Number.<Array[]>} peaks Array of peak data 2061 */ 2062 2063 }, { 2064 key: "loadElt", 2065 value: function loadElt(elt, peaks) { 2066 elt.controls = this.params.mediaControls; 2067 elt.autoplay = this.params.autoplay || false; 2068 2069 this._load(elt, peaks); 2070 } 2071 /** 2072 * Method called by both `load` (from url) 2073 * and `loadElt` (existing media element) methods. 2074 * 2075 * @param {HTMLMediaElement} media HTML5 Audio or Video element 2076 * @param {number[]|Number.<Array[]>} peaks Array of peak data 2077 * @throws Will throw an error if the `media` argument is not a valid media 2078 * element. 2079 * @private 2080 */ 2081 2082 }, { 2083 key: "_load", 2084 value: function _load(media, peaks) { 2085 // verify media element is valid 2086 if (!(media instanceof HTMLMediaElement) || typeof media.addEventListener === 'undefined') { 2087 throw new Error('media parameter is not a valid media element'); 2088 } // load must be called manually on iOS, otherwise peaks won't draw 2089 // until a user interaction triggers load --> 'ready' event 2090 2091 2092 if (typeof media.load == 'function') { 2093 // Resets the media element and restarts the media resource. Any 2094 // pending events are discarded. How much media data is fetched is 2095 // still affected by the preload attribute. 2096 media.load(); 2097 } 2098 2099 this.media = media; 2100 2101 this._setupMediaListeners(); 2102 2103 this.peaks = peaks; 2104 this.onPlayEnd = null; 2105 this.buffer = null; 2106 this.isMuted = media.muted; 2107 this.setPlaybackRate(this.playbackRate); 2108 this.setVolume(this.volume); 2109 } 2110 /** 2111 * Used by `wavesurfer.isPlaying()` and `wavesurfer.playPause()` 2112 * 2113 * @return {boolean} Media paused or not 2114 */ 2115 2116 }, { 2117 key: "isPaused",
2118 value: function isPaused() { 2119 return !this.media || this.media.paused; 2120 } 2121 /** 2122 * Used by `wavesurfer.getDuration()` 2123 * 2124 * @return {number} Duration 2125 */ 2126 2127 }, { 2128 key: "getDuration", 2129 value: function getDuration() { 2130 if (this.explicitDuration) { 2131 return this.explicitDuration; 2132 } 2133 2134 var duration = (this.buffer || this.media).duration; 2135 2136 if (duration >= Infinity) { 2137 // streaming audio 2138 duration = this.media.seekable.end(0); 2139 } 2140 2141 return duration; 2142 } 2143 /** 2144 * Returns the current time in seconds relative to the audio-clip's 2145 * duration. 2146 * 2147 * @return {number} Current time 2148 */ 2149 2150 }, { 2151 key: "getCurrentTime", 2152 value: function getCurrentTime() { 2153 return this.media && this.media.currentTime; 2154 } 2155 /** 2156 * Get the position from 0 to 1 2157 * 2158 * @return {number} Current position 2159 */ 2160 2161 }, { 2162 key: "getPlayedPercents", 2163 value: function getPlayedPercents() { 2164 return this.getCurrentTime() / this.getDuration() || 0; 2165 } 2166 /** 2167 * Get the audio source playback rate. 2168 * 2169 * @return {number} Playback rate 2170 */ 2171 2172 }, { 2173 key: "getPlaybackRate", 2174 value: function getPlaybackRate() { 2175 return this.playbackRate || this.media.playbackRate; 2176 } 2177 /** 2178 * Set the audio source playback rate. 2179 * 2180 * @param {number} value Playback rate 2181 */ 2182 2183 }, { 2184 key: "setPlaybackRate", 2185 value: function setPlaybackRate(value) { 2186 this.playbackRate = value || 1; 2187 this.media.playbackRate = this.playbackRate; 2188 } 2189 /** 2190 * Used by `wavesurfer.seekTo()` 2191 * 2192 * @param {number} start Position to start at in seconds 2193 */ 2194 2195 }, { 2196 key: "seekTo", 2197 value: function seekTo(start) { 2198 if (start != null) { 2199 this.media.currentTime = start; 2200 } 2201 2202 this.clearPlayEnd(); 2203 } 2204 /** 2205 * Plays the loaded audio region. 2206 * 2207 * @param {number} start Start offset in seconds, relative to the beginning 2208 * of a clip. 2209 * @param {number} end When to stop, relative to the beginning of a clip. 2210 * @emits MediaElement#play 2211 * @return {Promise} Result 2212 */ 2213 2214 }, { 2215 key: "play", 2216 value: function play(start, end) { 2217 this.seekTo(start); 2218 var promise = this.media.play(); 2219 end && this.setPlayEnd(end); 2220 return promise; 2221 } 2222 /** 2223 * Pauses the loaded audio. 2224 * 2225 * @emits MediaElement#pause 2226 * @return {Promise} Result 2227 */ 2228 2229 }, { 2230 key: "pause", 2231 value: function pause() { 2232 var promise; 2233 2234 if (this.media) { 2235 promise = this.media.pause(); 2236 } 2237 2238 this.clearPlayEnd(); 2239 return promise; 2240 } 2241 /** 2242 * Set the play end 2243 * 2244 * @param {number} end Where to end 2245 */ 2246 2247 }, { 2248 key: "setPlayEnd", 2249 value: function setPlayEnd(end) { 2250 var _this4 = this; 2251 2252 this.clearPlayEnd(); 2253 2254 this._onPlayEnd = function (time) { 2255 if (time >= end) { 2256 _this4.pause(); 2257 2258 _this4.seekTo(end); 2259 } 2260 }; 2261 2262 this.on('audioprocess', this._onPlayEnd); 2263 } 2264 /** @private */ 2265 2266 }, { 2267 key: "clearPlayEnd", 2268 value: function clearPlayEnd() { 2269 if (this._onPlayEnd) { 2270 this.un('audioprocess', this._onPlayEnd); 2271 this._onPlayEnd = null; 2272 } 2273 } 2274 /** 2275 * Compute the max and min value of the waveform when broken into 2276 * <length> subranges. 2277 * 2278 * @param {number} length How many subranges to break the waveform into. 2279 * @param {number} first First sample in the required range. 2280 * @param {number} last Last sample in the required range. 2281 * @return {number[]|Number.<Array[]>} Array of 2*<length> peaks or array of 2282 * arrays of peaks consisting of (max, min) values for each subrange. 2283 */ 2284 2285 }, { 2286 key: "getPeaks", 2287 value: function getPeaks(length, first, last) { 2288 if (this.buffer) { 2289 return _get(_getPrototypeOf(MediaElement.prototype), "getPeaks", this).call(this, length, first, last); 2290 } 2291 2292 return this.peaks || []; 2293 } 2294 /** 2295 * Set the sink id for the media player 2296 * 2297 * @param {string} deviceId String value representing audio device id. 2298 * @returns {Promise} A Promise that resolves to `undefined` when there 2299 * are no errors. 2300 */ 2301 2302 }, { 2303 key: "setSinkId", 2304 value: function setSinkId(deviceId) { 2305 if (deviceId) { 2306 if (!this.media.setSinkId) { 2307 return Promise.reject(new Error('setSinkId is not supported in your browser')); 2308 } 2309 2310 return this.media.setSinkId(deviceId); 2311 } 2312 2313 return Promise.reject(new Error('Invalid deviceId: ' + deviceId)); 2314 } 2315 /** 2316 * Get the current volume 2317 * 2318 * @return {number} value A floating point value between 0 and 1. 2319 */ 2320 2321 }, { 2322 key: "getVolume", 2323 value: function getVolume() { 2324 return this.volume; 2325 } 2326 /** 2327 * Set the audio volume 2328 * 2329 * @param {number} value A floating point value between 0 and 1. 2330 */ 2331 2332 }, { 2333 key: "setVolume", 2334 value: function setVolume(value) { 2335 this.volume = value; // no need to change when it's already at that volume 2336 2337 if (this.media.volume !== this.volume) { 2338 this.media.volume = this.volume; 2339 } 2340 } 2341 /** 2342 * This is called when wavesurfer is destroyed 2343 * 2344 */ 2345 2346 }, {
2347 key: "destroy", 2348 value: function destroy() { 2349 var _this5 = this; 2350 2351 this.pause(); 2352 this.unAll(); 2353 this.destroyed = true; // cleanup media event listeners 2354 2355 Object.keys(this.mediaListeners).forEach(function (id) { 2356 if (_this5.media) { 2357 _this5.media.removeEventListener(id, _this5.mediaListeners[id]); 2358 } 2359 }); 2360 2361 if (this.params.removeMediaElementOnDestroy && this.media && this.media.parentNode) { 2362 this.media.parentNode.removeChild(this.media); 2363 } 2364 2365 this.media = null; 2366 } 2367 }]); 2368 2369 return MediaElement; 2370}(_webaudio.default); 2371 2372exports.default = MediaElement; 2373module.exports = exports.default; 2374 2375/***/ }), 2376
2377/***/ "./src/peakcache.js": 2378/*!**************************!*\ 2379 !*** ./src/peakcache.js ***! 2380 \**************************/ 2381/*! no static exports found */ 2382/***/ (function(module, exports, __webpack_require__) { 2383 2384"use strict"; 2385 2386 2387Object.defineProperty(exports, "__esModule", { 2388 value: true 2389}); 2390exports.default = void 0; 2391 2392function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 2393 2394function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } 2395 2396function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } 2397 2398/** 2399 * Caches the decoded peaks data to improve rendering speed for large audio 2400 * 2401 * Is used if the option parameter `partialRender` is set to `true` 2402 */ 2403var PeakCache = 2404/*#__PURE__*/ 2405function () { 2406 /** 2407 * Instantiate cache 2408 */ 2409 function PeakCache() { 2410 _classCallCheck(this, PeakCache); 2411 2412 this.clearPeakCache(); 2413 } 2414 /** 2415 * Empty the cache 2416 */ 2417 2418 2419 _createClass(PeakCache, [{ 2420 key: "clearPeakCache", 2421 value: function clearPeakCache() { 2422 /** 2423 * Flat array with entries that are always in pairs to mark the 2424 * beginning and end of each subrange. This is a convenience so we can 2425 * iterate over the pairs for easy set difference operations. 2426 * @private 2427 */ 2428 this.peakCacheRanges = []; 2429 /** 2430 * Length of the entire cachable region, used for resetting the cache 2431 * when this changes (zoom events, for instance). 2432 * @private 2433 */ 2434 2435 this.peakCacheLength = -1; 2436 } 2437 /** 2438 * Add a range of peaks to the cache 2439 * 2440 * @param {number} length The length of the range 2441 * @param {number} start The x offset of the start of the range 2442 * @param {number} end The x offset of the end of the range 2443 * @return {Number.<Array[]>} Array with arrays of numbers 2444 */ 2445 2446 }, { 2447 key: "addRangeToPeakCache", 2448 value: function addRangeToPeakCache(length, start, end) { 2449 if (length != this.peakCacheLength) { 2450 this.clearPeakCache(); 2451 this.peakCacheLength = length; 2452 } // Return ranges that weren't in the cache before the call. 2453 2454 2455 var uncachedRanges = []; 2456 var i = 0; // Skip ranges before the current start. 2457 2458 while (i < this.peakCacheRanges.length && this.peakCacheRanges[i] < start) { 2459 i++; 2460 } // If |i| is even, |start| falls after an existing range. Otherwise, 2461 // |start| falls between an existing range, and the uncached region 2462 // starts when we encounter the next node in |peakCacheRanges| or 2463 // |end|, whichever comes first. 2464 2465 2466 if (i % 2 == 0) { 2467 uncachedRanges.push(start); 2468 } 2469 2470 while (i < this.peakCacheRanges.length && this.peakCacheRanges[i] <= end) { 2471 uncachedRanges.push(this.peakCacheRanges[i]); 2472 i++; 2473 } // If |i| is even, |end| is after all existing ranges. 2474 2475 2476 if (i % 2 == 0) { 2477 uncachedRanges.push(end); 2478 } // Filter out the 0-length ranges. 2479 2480 2481 uncachedRanges = uncachedRanges.filter(function (item, pos, arr) { 2482 if (pos == 0) { 2483 return item != arr[pos + 1]; 2484 } else if (pos == arr.length - 1) { 2485 return item != arr[pos - 1]; 2486 } 2487 2488 return item != arr[pos - 1] && item != arr[pos + 1]; 2489 }); // Merge the two ranges together, uncachedRanges will either contain 2490 // wholly new points, or duplicates of points in peakCacheRanges. If 2491 // duplicates are detected, remove both and extend the range. 2492 2493 this.peakCacheRanges = this.peakCacheRanges.concat(uncachedRanges); 2494 this.peakCacheRanges = this.peakCacheRanges.sort(function (a, b) { 2495 return a - b; 2496 }).filter(function (item, pos, arr) { 2497 if (pos == 0) { 2498 return item != arr[pos + 1]; 2499 } else if (pos == arr.length - 1) { 2500 return item != arr[pos - 1]; 2501 } 2502 2503 return item != arr[pos - 1] && item != arr[pos + 1]; 2504 }); // Push the uncached ranges into an array of arrays for ease of 2505 // iteration in the functions that call this. 2506 2507 var uncachedRangePairs = []; 2508 2509 for (i = 0; i < uncachedRanges.length; i += 2) { 2510 uncachedRangePairs.push([uncachedRanges[i], uncachedRanges[i + 1]]); 2511 } 2512 2513 return uncachedRangePairs; 2514 } 2515 /** 2516 * For testing 2517 * 2518 * @return {Number.<Array[]>} Array with arrays of numbers 2519 */ 2520 2521 }, { 2522 key: "getCacheRanges", 2523 value: function getCacheRanges() { 2524 var peakCacheRangePairs = []; 2525 var i; 2526 2527 for (i = 0; i < this.peakCacheRanges.length; i += 2) { 2528 peakCacheRangePairs.push([this.peakCacheRanges[i], this.peakCacheRanges[i + 1]]); 2529 } 2530 2531 return peakCacheRangePairs; 2532 } 2533 }]); 2534 2535 return PeakCache; 2536}(); 2537 2538exports.default = PeakCache; 2539module.exports = exports.default; 2540 2541/***/ }), 2542
2543/***/ "./src/util/ajax.js": 2544/*!**************************!*\ 2545 !*** ./src/util/ajax.js ***! 2546 \**************************/ 2547/*! no static exports found */ 2548/***/ (function(module, exports, __webpack_require__) { 2549 2550"use strict"; 2551 2552 2553Object.defineProperty(exports, "__esModule", { 2554 value: true 2555}); 2556exports.default = ajax; 2557 2558var _observer = _interopRequireDefault(__webpack_require__(/*! ./observer */ "./src/util/observer.js")); 2559 2560function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 2561 2562/** 2563 * Perform an ajax request using `XMLHttpRequest`. 2564 * 2565 * @deprecated Use `util.fetchFile` instead. 2566 * 2567 * @param {Object} options AJAX options to use. See example below for options. 2568 * @returns {Observer} Observer instance 2569 * @example 2570 * // default options 2571 * let options = { 2572 * method: 'GET', 2573 * url: undefined, 2574 * responseType: 'json', 2575 * xhr: {} 2576 * }; 2577 * 2578 * // override default options 2579 * options.url = '../media/demo.wav'; 2580 * options.responseType = 'arraybuffer'; 2581 * options.xhr = { 2582 * requestHeaders: [ 2583 * { 2584 * key: 'Authorization', 2585 * value: 'my-token' 2586 * } 2587 * ], 2588 * withCredentials: true 2589 * }; 2590 * 2591 * // make ajax call 2592 * let ajaxCall = util.ajax(options); 2593 * ajaxCall.on('progress', e => { 2594 * console.log('progress', e); 2595 * }); 2596 * ajaxCall.on('success', (data, e) => { 2597 * console.log('success!', data); 2598 * }); 2599 * ajaxCall.on('error', e => { 2600 * console.warn('ajax error: ' + e.target.statusText); 2601 * }); 2602 */ 2603function ajax(options) { 2604 var instance = new _observer.default(); 2605 var xhr = new XMLHttpRequest(); 2606 var fired100 = false; 2607 xhr.open(options.method || 'GET', options.url, true); 2608 xhr.responseType = options.responseType || 'json'; 2609 2610 if (options.xhr) { 2611 if (options.xhr.requestHeaders) { 2612 // add custom request headers 2613 options.xhr.requestHeaders.forEach(function (header) { 2614 xhr.setRequestHeader(header.key, header.value); 2615 }); 2616 } 2617 2618 if (options.xhr.withCredentials) { 2619 // use credentials 2620 xhr.withCredentials = true; 2621 } 2622 } 2623 2624 xhr.addEventListener('progress', function (e) { 2625 instance.fireEvent('progress', e); 2626 2627 if (e.lengthComputable && e.loaded == e.total) { 2628 fired100 = true; 2629 } 2630 }); 2631 xhr.addEventListener('load', function (e) { 2632 if (!fired100) { 2633 instance.fireEvent('progress', e); 2634 } 2635 2636 instance.fireEvent('load', e); 2637 2638 if (200 == xhr.status || 206 == xhr.status) { 2639 instance.fireEvent('success', xhr.response, e); 2640 } else { 2641 instance.fireEvent('error', e); 2642 } 2643 }); 2644 xhr.addEventListener('error', function (e) { 2645 return instance.fireEvent('error', e); 2646 }); 2647 xhr.send(); 2648 instance.xhr = xhr; 2649 return instance; 2650} 2651 2652module.exports = exports.default; 2653 2654/***/ }), 2655
2656/***/ "./src/util/extend.js": 2657/*!****************************!*\ 2658 !*** ./src/util/extend.js ***! 2659 \****************************/ 2660/*! no static exports found */ 2661/***/ (function(module, exports, __webpack_require__) { 2662 2663"use strict"; 2664 2665 2666Object.defineProperty(exports, "__esModule", { 2667 value: true 2668}); 2669exports.default = extend; 2670 2671/* eslint no-console: ["error", { allow: ["warn"] }] */ 2672 2673/** 2674 * Extend an object shallowly with others 2675 * 2676 * @param {Object} dest The target object 2677 * @param {Object[]} sources The objects to use for extending 2678 * 2679 * @return {Object} Merged object 2680 * @deprecated since version 3.3.0 2681 */ 2682function extend(dest) { 2683 console.warn('util.extend is deprecated; use Object.assign instead'); 2684 2685 for (var _len = arguments.length, sources = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 2686 sources[_key - 1] = arguments[_key]; 2687 } 2688 2689 sources.forEach(function (source) { 2690 Object.keys(source).forEach(function (key) { 2691 dest[key] = source[key]; 2692 }); 2693 }); 2694 return dest; 2695} 2696 2697module.exports = exports.default; 2698 2699/***/ }), 2700
2701/***/ "./src/util/fetch.js": 2702/*!***************************!*\ 2703 !*** ./src/util/fetch.js ***! 2704 \***************************/ 2705/*! no static exports found */ 2706/***/ (function(module, exports, __webpack_require__) { 2707 2708"use strict"; 2709 2710 2711Object.defineProperty(exports, "__esModule", { 2712 value: true 2713}); 2714exports.default = fetchFile; 2715 2716var _observer = _interopRequireDefault(__webpack_require__(/*! ./observer */ "./src/util/observer.js")); 2717 2718function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 2719 2720function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 2721 2722function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } 2723 2724function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } 2725 2726var ProgressHandler = 2727/*#__PURE__*/ 2728function () { 2729 /** 2730 * Instantiate ProgressHandler 2731 * 2732 * @param {Observer} instance The `fetchFile` observer instance. 2733 * @param {Number} contentLength Content length. 2734 * @param {Response} response Response object. 2735 */ 2736 function ProgressHandler(instance, contentLength, response) { 2737 _classCallCheck(this, ProgressHandler); 2738 2739 this.instance = instance; 2740 this.instance._reader = response.body.getReader(); 2741 this.total = parseInt(contentLength, 10); 2742 this.loaded = 0; 2743 } 2744 /** 2745 * A method that is called once, immediately after the `ReadableStream`` 2746 * is constructed. 2747 * 2748 * @param {ReadableStreamDefaultController} controller Controller instance 2749 * used to control the stream. 2750 */ 2751 2752 2753 _createClass(ProgressHandler, [{ 2754 key: "start", 2755 value: function start(controller) { 2756 var _this = this; 2757 2758 var read = function read() { 2759 // instance._reader.read() returns a promise that resolves 2760 // when a value has been received 2761 _this.instance._reader.read().then(function (_ref) { 2762 var done = _ref.done, 2763 value = _ref.value; 2764 2765 // result objects contain two properties: 2766 // done - true if the stream has already given you all its data. 2767 // value - some data. Always undefined when done is true. 2768 if (done) { 2769 // ensure onProgress called when content-length=0 2770 if (_this.total === 0) { 2771 _this.instance.onProgress.call(_this.instance, { 2772 loaded: _this.loaded, 2773 total: _this.total, 2774 lengthComputable: false 2775 }); 2776 } // no more data needs to be consumed, close the stream 2777 2778 2779 controller.close(); 2780 return; 2781 } 2782 2783 _this.loaded += value.byteLength; 2784 2785 _this.instance.onProgress.call(_this.instance, { 2786 loaded: _this.loaded, 2787 total: _this.total, 2788 lengthComputable: !(_this.total === 0) 2789 }); // enqueue the next data chunk into our target stream 2790 2791 2792 controller.enqueue(value); 2793 read(); 2794 }).catch(function (error) { 2795 controller.error(error); 2796 }); 2797 }; 2798 2799 read(); 2800 } 2801 }]); 2802 2803 return ProgressHandler; 2804}(); 2805/** 2806 * Load a file using `fetch`. 2807 * 2808 * @param {object} options Request options to use. See example below. 2809 * @returns {Observer} Observer instance 2810 * @example 2811 * // default options 2812 * let options = { 2813 * url: undefined, 2814 * method: 'GET', 2815 * mode: 'cors', 2816 * credentials: 'same-origin', 2817 * cache: 'default', 2818 * responseType: 'json', 2819 * requestHeaders: [], 2820 * redirect: 'follow', 2821 * referrer: 'client' 2822 * }; 2823 * 2824 * // override some options 2825 * options.url = '../media/demo.wav'; 2826 2827 * // available types: 'arraybuffer', 'blob', 'json' or 'text' 2828 * options.responseType = 'arraybuffer'; 2829 * 2830 * // make fetch call 2831 * let request = util.fetchFile(options); 2832 * 2833 * // listen for events 2834 * request.on('progress', e => { 2835 * console.log('progress', e); 2836 * }); 2837 * 2838 * request.on('success', data => { 2839 * console.log('success!', data); 2840 * }); 2841 * 2842 * request.on('error', e => { 2843 * console.warn('fetchFile error: ', e); 2844 * }); 2845 */ 2846 2847 2848function fetchFile(options) { 2849 if (!options) { 2850 throw new Error('fetch options missing'); 2851 } else if (!options.url) { 2852 throw new Error('fetch url missing'); 2853 } 2854 2855 var instance = new _observer.default(); 2856 var fetchHeaders = new Headers();
2857 var fetchRequest = new Request(options.url); // add ability to abort 2858 2859 instance.controller = new AbortController(); // check if headers have to be added 2860 2861 if (options && options.requestHeaders) { 2862 // add custom request headers 2863 options.requestHeaders.forEach(function (header) { 2864 fetchHeaders.append(header.key, header.value); 2865 }); 2866 } // parse fetch options 2867 2868 2869 var responseType = options.responseType || 'json'; 2870 var fetchOptions = { 2871 method: options.method || 'GET', 2872 headers: fetchHeaders, 2873 mode: options.mode || 'cors', 2874 credentials: options.credentials || 'same-origin', 2875 cache: options.cache || 'default', 2876 redirect: options.redirect || 'follow', 2877 referrer: options.referrer || 'client', 2878 signal: instance.controller.signal 2879 }; 2880 fetch(fetchRequest, fetchOptions).then(function (response) { 2881 // store response reference 2882 instance.response = response; 2883 var progressAvailable = true; 2884 2885 if (!response.body) { 2886 // ReadableStream is not yet supported in this browser 2887 // see https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream 2888 progressAvailable = false; 2889 } // Server must send CORS header "Access-Control-Expose-Headers: content-length" 2890 2891 2892 var contentLength = response.headers.get('content-length'); 2893 2894 if (contentLength === null) { 2895 // Content-Length server response header missing. 2896 // Don't evaluate download progress if we can't compare against a total size 2897 // see https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Access-Control-Expose-Headers 2898 progressAvailable = false; 2899 } 2900 2901 if (!progressAvailable) { 2902 // not able to check download progress so skip it 2903 return response; 2904 } // fire progress event when during load 2905 2906 2907 instance.onProgress = function (e) { 2908 instance.fireEvent('progress', e); 2909 }; 2910 2911 return new Response(new ReadableStream(new ProgressHandler(instance, contentLength, response)), fetchOptions); 2912 }).then(function (response) { 2913 var errMsg; 2914 2915 if (response.ok) { 2916 switch (responseType) { 2917 case 'arraybuffer': 2918 return response.arrayBuffer(); 2919 2920 case 'json': 2921 return response.json(); 2922 2923 case 'blob': 2924 return response.blob(); 2925 2926 case 'text': 2927 return response.text(); 2928 2929 default: 2930 errMsg = 'Unknown responseType: ' + responseType; 2931 break; 2932 } 2933 } 2934 2935 if (!errMsg) { 2936 errMsg = 'HTTP error status: ' + response.status; 2937 } 2938 2939 throw new Error(errMsg); 2940 }).then(function (response) { 2941 instance.fireEvent('success', response); 2942 }).catch(function (error) { 2943 instance.fireEvent('error', error); 2944 }); // return the fetch request 2945 2946 instance.fetchRequest = fetchRequest; 2947 return instance; 2948} 2949 2950module.exports = exports.default; 2951 2952/***/ }), 2953
2954/***/ "./src/util/frame.js": 2955/*!***************************!*\ 2956 !*** ./src/util/frame.js ***! 2957 \***************************/ 2958/*! no static exports found */ 2959/***/ (function(module, exports, __webpack_require__) { 2960 2961"use strict"; 2962 2963 2964Object.defineProperty(exports, "__esModule", { 2965 value: true 2966}); 2967exports.default = frame; 2968 2969var _requestAnimationFrame = _interopRequireDefault(__webpack_require__(/*! ./request-animation-frame */ "./src/util/request-animation-frame.js")); 2970 2971function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 2972 2973/** 2974 * Create a function which will be called at the next requestAnimationFrame 2975 * cycle 2976 * 2977 * @param {function} func The function to call 2978 * 2979 * @return {func} The function wrapped within a requestAnimationFrame 2980 */ 2981function frame(func) { 2982 return function () { 2983 for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { 2984 args[_key] = arguments[_key]; 2985 } 2986 2987 return (0, _requestAnimationFrame.default)(function () { 2988 return func.apply(void 0, args); 2989 }); 2990 }; 2991} 2992 2993module.exports = exports.default; 2994 2995/***/ }), 2996
2997/***/ "./src/util/get-id.js": 2998/*!****************************!*\ 2999 !*** ./src/util/get-id.js ***! 3000 \****************************/ 3001/*! no static exports found */ 3002/***/ (function(module, exports, __webpack_require__) { 3003 3004"use strict"; 3005 3006 3007Object.defineProperty(exports, "__esModule", { 3008 value: true 3009}); 3010exports.default = getId; 3011 3012/** 3013 * Get a random prefixed ID 3014 * 3015 * @param {String} prefix Prefix to use. Default is `'wavesurfer_'`. 3016 * @returns {String} Random prefixed ID 3017 * @example 3018 * console.log(getId()); // logs 'wavesurfer_b5pors4ru6g' 3019 * 3020 * let prefix = 'foo-'; 3021 * console.log(getId(prefix)); // logs 'foo-b5pors4ru6g' 3022 */ 3023function getId(prefix) { 3024 if (prefix === undefined) { 3025 prefix = 'wavesurfer_'; 3026 } 3027 3028 return prefix + Math.random().toString(32).substring(2); 3029} 3030 3031module.exports = exports.default; 3032 3033/***/ }), 3034
3035/***/ "./src/util/index.js": 3036/*!***************************!*\ 3037 !*** ./src/util/index.js ***! 3038 \***************************/ 3039/*! no static exports found */ 3040/***/ (function(module, exports, __webpack_require__) { 3041 3042"use strict"; 3043 3044 3045Object.defineProperty(exports, "__esModule", { 3046 value: true 3047}); 3048Object.defineProperty(exports, "ajax", { 3049 enumerable: true, 3050 get: function get() { 3051 return _ajax.default; 3052 } 3053}); 3054Object.defineProperty(exports, "getId", { 3055 enumerable: true, 3056 get: function get() { 3057 return _getId.default; 3058 } 3059}); 3060Object.defineProperty(exports, "max", { 3061 enumerable: true, 3062 get: function get() { 3063 return _max.default; 3064 } 3065}); 3066Object.defineProperty(exports, "min", { 3067 enumerable: true, 3068 get: function get() { 3069 return _min.default; 3070 } 3071}); 3072Object.defineProperty(exports, "Observer", { 3073 enumerable: true, 3074 get: function get() { 3075 return _observer.default; 3076 } 3077}); 3078Object.defineProperty(exports, "extend", { 3079 enumerable: true, 3080 get: function get() { 3081 return _extend.default; 3082 } 3083}); 3084Object.defineProperty(exports, "style", { 3085 enumerable: true, 3086 get: function get() { 3087 return _style.default; 3088 } 3089}); 3090Object.defineProperty(exports, "requestAnimationFrame", { 3091 enumerable: true, 3092 get: function get() { 3093 return _requestAnimationFrame.default; 3094 } 3095}); 3096Object.defineProperty(exports, "frame", { 3097 enumerable: true, 3098 get: function get() { 3099 return _frame.default; 3100 } 3101}); 3102Object.defineProperty(exports, "debounce", { 3103 enumerable: true, 3104 get: function get() { 3105 return _debounce.default; 3106 } 3107}); 3108Object.defineProperty(exports, "preventClick", { 3109 enumerable: true, 3110 get: function get() { 3111 return _preventClick.default; 3112 } 3113}); 3114Object.defineProperty(exports, "fetchFile", { 3115 enumerable: true, 3116 get: function get() { 3117 return _fetch.default; 3118 } 3119}); 3120 3121var _ajax = _interopRequireDefault(__webpack_require__(/*! ./ajax */ "./src/util/ajax.js")); 3122 3123var _getId = _interopRequireDefault(__webpack_require__(/*! ./get-id */ "./src/util/get-id.js")); 3124 3125var _max = _interopRequireDefault(__webpack_require__(/*! ./max */ "./src/util/max.js")); 3126 3127var _min = _interopRequireDefault(__webpack_require__(/*! ./min */ "./src/util/min.js")); 3128 3129var _observer = _interopRequireDefault(__webpack_require__(/*! ./observer */ "./src/util/observer.js")); 3130 3131var _extend = _interopRequireDefault(__webpack_require__(/*! ./extend */ "./src/util/extend.js")); 3132 3133var _style = _interopRequireDefault(__webpack_require__(/*! ./style */ "./src/util/style.js")); 3134 3135var _requestAnimationFrame = _interopRequireDefault(__webpack_require__(/*! ./request-animation-frame */ "./src/util/request-animation-frame.js")); 3136 3137var _frame = _interopRequireDefault(__webpack_require__(/*! ./frame */ "./src/util/frame.js")); 3138 3139var _debounce = _interopRequireDefault(__webpack_require__(/*! debounce */ "./node_modules/debounce/index.js")); 3140 3141var _preventClick = _interopRequireDefault(__webpack_require__(/*! ./prevent-click */ "./src/util/prevent-click.js")); 3142 3143var _fetch = _interopRequireDefault(__webpack_require__(/*! ./fetch */ "./src/util/fetch.js")); 3144 3145function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 3146 3147/***/ }), 3148
3149/***/ "./src/util/max.js": 3150/*!*************************!*\ 3151 !*** ./src/util/max.js ***! 3152 \*************************/ 3153/*! no static exports found */ 3154/***/ (function(module, exports, __webpack_require__) { 3155 3156"use strict"; 3157 3158 3159Object.defineProperty(exports, "__esModule", { 3160 value: true 3161}); 3162exports.default = max; 3163 3164/** 3165 * Get the largest value 3166 * 3167 * @param {Array} values Array of numbers 3168 * @returns {Number} Largest number found 3169 * @example console.log(max([1, 2, 3])); // logs 3 3170 */ 3171function max(values) { 3172 var largest = -Infinity; 3173 Object.keys(values).forEach(function (i) { 3174 if (values[i] > largest) { 3175 largest = values[i]; 3176 } 3177 }); 3178 return largest; 3179} 3180 3181module.exports = exports.default; 3182 3183/***/ }), 3184
3185/***/ "./src/util/min.js": 3186/*!*************************!*\ 3187 !*** ./src/util/min.js ***! 3188 \*************************/ 3189/*! no static exports found */ 3190/***/ (function(module, exports, __webpack_require__) { 3191 3192"use strict"; 3193 3194 3195Object.defineProperty(exports, "__esModule", { 3196 value: true 3197}); 3198exports.default = min; 3199 3200/** 3201 * Get the smallest value 3202 * 3203 * @param {Array} values Array of numbers 3204 * @returns {Number} Smallest number found 3205 * @example console.log(min([1, 2, 3])); // logs 1 3206 */ 3207function min(values) { 3208 var smallest = Number(Infinity); 3209 Object.keys(values).forEach(function (i) { 3210 if (values[i] < smallest) { 3211 smallest = values[i]; 3212 } 3213 }); 3214 return smallest; 3215} 3216 3217module.exports = exports.default; 3218 3219/***/ }), 3220
3221/***/ "./src/util/observer.js": 3222/*!******************************!*\ 3223 !*** ./src/util/observer.js ***! 3224 \******************************/ 3225/*! no static exports found */ 3226/***/ (function(module, exports, __webpack_require__) { 3227 3228"use strict"; 3229 3230 3231Object.defineProperty(exports, "__esModule", { 3232 value: true 3233}); 3234exports.default = void 0; 3235 3236function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 3237 3238function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } 3239 3240function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } 3241 3242/** 3243 * @typedef {Object} ListenerDescriptor 3244 * @property {string} name The name of the event 3245 * @property {function} callback The callback 3246 * @property {function} un The function to call to remove the listener 3247 */ 3248 3249/** 3250 * Observer class 3251 */ 3252var Observer = 3253/*#__PURE__*/ 3254function () { 3255 /** 3256 * Instantiate Observer 3257 */ 3258 function Observer() { 3259 _classCallCheck(this, Observer); 3260 3261 /** 3262 * @private 3263 * @todo Initialise the handlers here already and remove the conditional 3264 * assignment in `on()` 3265 */ 3266 this.handlers = null; 3267 } 3268 /** 3269 * Attach a handler function for an event. 3270 * 3271 * @param {string} event Name of the event to listen to 3272 * @param {function} fn The callback to trigger when the event is fired 3273 * @return {ListenerDescriptor} The event descriptor 3274 */ 3275 3276 3277 _createClass(Observer, [{ 3278 key: "on", 3279 value: function on(event, fn) { 3280 var _this = this; 3281 3282 if (!this.handlers) { 3283 this.handlers = {}; 3284 } 3285 3286 var handlers = this.handlers[event]; 3287 3288 if (!handlers) { 3289 handlers = this.handlers[event] = []; 3290 } 3291 3292 handlers.push(fn); // Return an event descriptor 3293 3294 return { 3295 name: event, 3296 callback: fn, 3297 un: function un(e, fn) { 3298 return _this.un(e, fn); 3299 } 3300 }; 3301 } 3302 /** 3303 * Remove an event handler. 3304 * 3305 * @param {string} event Name of the event the listener that should be 3306 * removed listens to 3307 * @param {function} fn The callback that should be removed 3308 */ 3309 3310 }, { 3311 key: "un", 3312 value: function un(event, fn) { 3313 if (!this.handlers) { 3314 return; 3315 } 3316 3317 var handlers = this.handlers[event]; 3318 var i; 3319 3320 if (handlers) { 3321 if (fn) { 3322 for (i = handlers.length - 1; i >= 0; i--) { 3323 if (handlers[i] == fn) { 3324 handlers.splice(i, 1); 3325 } 3326 } 3327 } else { 3328 handlers.length = 0; 3329 } 3330 } 3331 } 3332 /** 3333 * Remove all event handlers. 3334 */ 3335 3336 }, { 3337 key: "unAll", 3338 value: function unAll() { 3339 this.handlers = null; 3340 } 3341 /** 3342 * Attach a handler to an event. The handler is executed at most once per 3343 * event type. 3344 * 3345 * @param {string} event The event to listen to 3346 * @param {function} handler The callback that is only to be called once 3347 * @return {ListenerDescriptor} The event descriptor 3348 */ 3349 3350 }, { 3351 key: "once", 3352 value: function once(event, handler) { 3353 var _this2 = this; 3354 3355 var fn = function fn() { 3356 for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { 3357 args[_key] = arguments[_key]; 3358 } 3359 3360 /* eslint-disable no-invalid-this */ 3361 handler.apply(_this2, args); 3362 /* eslint-enable no-invalid-this */ 3363 3364 setTimeout(function () { 3365 _this2.un(event, fn); 3366 }, 0); 3367 }; 3368 3369 return this.on(event, fn); 3370 } 3371 /** 3372 * Manually fire an event 3373 * 3374 * @param {string} event The event to fire manually 3375 * @param {...any} args The arguments with which to call the listeners 3376 */ 3377 3378 }, { 3379 key: "fireEvent", 3380 value: function fireEvent(event) { 3381 for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { 3382 args[_key2 - 1] = arguments[_key2]; 3383 } 3384 3385 if (!this.handlers) { 3386 return; 3387 } 3388 3389 var handlers = this.handlers[event];
3390 handlers && handlers.forEach(function (fn) { 3391 fn.apply(void 0, args); 3392 }); 3393 } 3394 }]); 3395 3396 return Observer; 3397}(); 3398 3399exports.default = Observer; 3400module.exports = exports.default; 3401 3402/***/ }), 3403
3404/***/ "./src/util/prevent-click.js": 3405/*!***********************************!*\ 3406 !*** ./src/util/prevent-click.js ***! 3407 \***********************************/ 3408/*! no static exports found */ 3409/***/ (function(module, exports, __webpack_require__) { 3410 3411"use strict"; 3412 3413 3414Object.defineProperty(exports, "__esModule", { 3415 value: true 3416}); 3417exports.default = preventClick; 3418 3419/** 3420 * Stops propagation of click event and removes event listener 3421 * 3422 * @private 3423 * @param {object} event The click event 3424 */ 3425function preventClickHandler(event) { 3426 event.stopPropagation(); 3427 document.body.removeEventListener('click', preventClickHandler, true); 3428} 3429/** 3430 * Starts listening for click event and prevent propagation 3431 * 3432 * @param {object} values Values 3433 */ 3434 3435 3436function preventClick(values) { 3437 document.body.addEventListener('click', preventClickHandler, true); 3438} 3439 3440module.exports = exports.default; 3441 3442/***/ }), 3443
3444/***/ "./src/util/request-animation-frame.js": 3445/*!*********************************************!*\ 3446 !*** ./src/util/request-animation-frame.js ***! 3447 \*********************************************/ 3448/*! no static exports found */ 3449/***/ (function(module, exports, __webpack_require__) { 3450 3451"use strict"; 3452 3453 3454Object.defineProperty(exports, "__esModule", { 3455 value: true 3456}); 3457exports.default = void 0; 3458 3459/* eslint-disable valid-jsdoc */ 3460 3461/** 3462 * Returns the `requestAnimationFrame` function for the browser, or a shim with 3463 * `setTimeout` if the function is not found 3464 * 3465 * @return {function} Available `requestAnimationFrame` function for the browser 3466 */ 3467var _default = (window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback, element) { 3468 return setTimeout(callback, 1000 / 60); 3469}).bind(window); 3470 3471exports.default = _default; 3472module.exports = exports.default; 3473 3474/***/ }), 3475
3476/***/ "./src/util/style.js": 3477/*!***************************!*\ 3478 !*** ./src/util/style.js ***! 3479 \***************************/ 3480/*! no static exports found */ 3481/***/ (function(module, exports, __webpack_require__) { 3482 3483"use strict"; 3484 3485 3486Object.defineProperty(exports, "__esModule", { 3487 value: true 3488}); 3489exports.default = style; 3490 3491/** 3492 * Apply a map of styles to an element 3493 * 3494 * @param {HTMLElement} el The element that the styles will be applied to 3495 * @param {Object} styles The map of propName: attribute, both are used as-is 3496 * 3497 * @return {HTMLElement} el 3498 */ 3499function style(el, styles) { 3500 Object.keys(styles).forEach(function (prop) { 3501 if (el.style[prop] !== styles[prop]) { 3502 el.style[prop] = styles[prop]; 3503 } 3504 }); 3505 return el; 3506} 3507 3508module.exports = exports.default; 3509 3510/***/ }), 3511
vendor: 4,746 bytes, lines 3512-3576
3512/***/ "./src/wavesurfer.js": 3513/*!***************************!*\ 3514 !*** ./src/wavesurfer.js ***! 3515 \***************************/ 3516/*! no static exports found */ 3517/***/ (function(module, exports, __webpack_require__) { 3518 3519"use strict"; 3520 3521 3522Object.defineProperty(exports, "__esModule", { 3523 value: true 3524}); 3525exports.default = void 0; 3526 3527var util = _interopRequireWildcard(__webpack_require__(/*! ./util */ "./src/util/index.js")); 3528 3529var _drawer = _interopRequireDefault(__webpack_require__(/*! ./drawer.multicanvas */ "./src/drawer.multicanvas.js")); 3530 3531var _webaudio = _interopRequireDefault(__webpack_require__(/*! ./webaudio */ "./src/webaudio.js")); 3532 3533var _mediaelement = _interopRequireDefault(__webpack_require__(/*! ./mediaelement */ "./src/mediaelement.js")); 3534 3535var _peakcache = _interopRequireDefault(__webpack_require__(/*! ./peakcache */ "./src/peakcache.js")); 3536 3537var _mediaelementWebaudio = _interopRequireDefault(__webpack_require__(/*! ./mediaelement-webaudio */ "./src/mediaelement-webaudio.js")); 3538 3539function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 3540 3541function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; } 3542 3543function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } 3544 3545function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } 3546 3547function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } 3548 3549function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } 3550 3551function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } 3552 3553function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } 3554 3555function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } 3556 3557function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 3558 3559function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } 3560 3561function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } 3562 3563/* 3564 * This work is licensed under a BSD-3-Clause License. 3565 */ 3566 3567/** @external {HTMLElement} https://developer.mozilla.org/en/docs/Web/API/HTMLElement */ 3568 3569/** @external {OfflineAudioContext} https://developer.mozilla.org/en-US/docs/Web/API/OfflineAudioContext */ 3570 3571/** @external {File} https://developer.mozilla.org/en-US/docs/Web/API/File */ 3572 3573/** @external {Blob} https://developer.mozilla.org/en-US/docs/Web/API/Blob */ 3574 3575/** @external {CanvasRenderingContext2D} https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D */ 3576
3577/** @external {MediaStreamConstraints} https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamConstraints */ 3578 3579/** @external {AudioNode} https://developer.mozilla.org/de/docs/Web/API/AudioNode */ 3580 3581/** 3582 * @typedef {Object} WavesurferParams 3583 * @property {AudioContext} audioContext=null Use your own previously 3584 * initialized AudioContext or leave blank. 3585 * @property {number} audioRate=1 Speed at which to play audio. Lower number is 3586 * slower. 3587 * @property {ScriptProcessorNode} audioScriptProcessor=null Use your own previously 3588 * initialized ScriptProcessorNode or leave blank. 3589 * @property {boolean} autoCenter=true If a scrollbar is present, center the 3590 * waveform on current progress 3591 * @property {number} autoCenterRate=5 If autoCenter is active, rate at which the 3592 * waveform is centered 3593 * @property {boolean} autoCenterImmediately=false If autoCenter is active, immediately 3594 * center waveform on current progress 3595 * @property {string} backend='WebAudio' `'WebAudio'|'MediaElement'|'MediaElementWebAudio'` In most cases 3596 * you don't have to set this manually. MediaElement is a fallback for unsupported browsers. 3597 * MediaElementWebAudio allows to use WebAudio API also with big audio files, loading audio like with 3598 * MediaElement backend (HTML5 audio tag). You have to use the same methods of MediaElement backend for loading and 3599 * playback, giving also peaks, so the audio data are not decoded. In this way you can use WebAudio features, like filters, 3600 * also with audio with big duration. For example: 3601 * ` wavesurfer.load(url | HTMLMediaElement, peaks, preload, duration); 3602 * wavesurfer.play(); 3603 * wavesurfer.setFilter(customFilter); 3604 * ` 3605 * @property {string} backgroundColor=null Change background color of the 3606 * waveform container. 3607 * @property {number} barHeight=1 The height of the wave bars. 3608 * @property {number} barRadius=0 The radius of the wave bars. Makes bars rounded 3609 * @property {number} barGap=null The optional spacing between bars of the wave, 3610 * if not provided will be calculated in legacy format. 3611 * @property {number} barWidth=null Draw the waveform using bars. 3612 * @property {number} barMinHeight=null If specified, draw at least a bar of this height, 3613 * eliminating waveform gaps 3614 * @property {boolean} closeAudioContext=false Close and nullify all audio 3615 * contexts when the destroy method is called. 3616 * @property {!string|HTMLElement} container CSS selector or HTML element where 3617 * the waveform should be drawn. This is the only required parameter. 3618 * @property {string} cursorColor='#333' The fill color of the cursor indicating 3619 * the playhead position. 3620 * @property {number} cursorWidth=1 Measured in pixels. 3621 * @property {object} drawingContextAttributes={desynchronized: false} Drawing context 3622 * attributes. 3623 * @property {number} duration=null Optional audio length so pre-rendered peaks 3624 * can be display immediately for example. 3625 * @property {boolean} fillParent=true Whether to fill the entire container or 3626 * draw only according to `minPxPerSec`. 3627 * @property {boolean} forceDecode=false Force decoding of audio using web audio 3628 * when zooming to get a more detailed waveform. 3629 * @property {number} height=128 The height of the waveform. Measured in 3630 * pixels. 3631 * @property {boolean} hideScrollbar=false Whether to hide the horizontal 3632 * scrollbar when one would normally be shown. 3633 * @property {boolean} interact=true Whether the mouse interaction will be 3634 * enabled at initialization. You can switch this parameter at any time later 3635 * on. 3636 * @property {boolean} loopSelection=true (Use with regions plugin) Enable 3637 * looping of selected regions 3638 * @property {number} maxCanvasWidth=4000 Maximum width of a single canvas in 3639 * pixels, excluding a small overlap (2 * `pixelRatio`, rounded up to the next 3640 * even integer). If the waveform is longer than this value, additional canvases 3641 * will be used to render the waveform, which is useful for very large waveforms 3642 * that may be too wide for browsers to draw on a single canvas. 3643 * @property {boolean} mediaControls=false (Use with backend `MediaElement` or `MediaElementWebAudio`) 3644 * this enables the native controls for the media element 3645 * @property {string} mediaType='audio' (Use with backend `MediaElement` or `MediaElementWebAudio`) 3646 * `'audio'|'video'` ('video' only for `MediaElement`) 3647 * @property {number} minPxPerSec=20 Minimum number of pixels per second of 3648 * audio. 3649 * @property {boolean} normalize=false If true, normalize by the maximum peak 3650 * instead of 1.0. 3651 * @property {boolean} partialRender=false Use the PeakCache to improve 3652 * rendering speed of large waveforms 3653 * @property {number} pixelRatio=window.devicePixelRatio The pixel ratio used to 3654 * calculate display 3655 * @property {PluginDefinition[]} plugins=[] An array of plugin definitions to 3656 * register during instantiation, they will be directly initialised unless they 3657 * are added with the `deferInit` property set to true. 3658 * @property {string} progressColor='#555' The fill color of the part of the 3659 * waveform behind the cursor. When `progressColor` and `waveColor` are the same 3660 * the progress wave is not rendered at all. 3661 * @property {boolean} removeMediaElementOnDestroy=true Set to false to keep the 3662 * media element in the DOM when the player is destroyed. This is useful when 3663 * reusing an existing media element via the `loadMediaElement` method. 3664 * @property {Object} renderer=MultiCanvas Can be used to inject a custom 3665 * renderer. 3666 * @property {boolean|number} responsive=false If set to `true` resize the 3667 * waveform, when the window is resized. This is debounced with a `100ms` 3668 * timeout by default. If this parameter is a number it represents that timeout. 3669 * @property {boolean} rtl=false If set to `true`, renders waveform from 3670 * right-to-left. 3671 * @property {boolean} scrollParent=false Whether to scroll the container with a 3672 * lengthy waveform. Otherwise the waveform is shrunk to the container width 3673 * (see fillParent). 3674 * @property {number} skipLength=2 Number of seconds to skip with the 3675 * skipForward() and skipBackward() methods. 3676 * @property {boolean} splitChannels=false Render with separate waveforms for 3677 * the channels of the audio 3678 * @property {string} waveColor='#999' The fill color of the waveform after the 3679 * cursor. 3680 * @property {object} xhr={} XHR options. For example: 3681 * `let xhr = { 3682 * cache: 'default', 3683 * mode: 'cors', 3684 * method: 'GET', 3685 * credentials: 'same-origin', 3686 * redirect: 'follow', 3687 * referrer: 'client', 3688 * headers: [ 3689 * { 3690 * key: 'Authorization', 3691 * value: 'my-token' 3692 * } 3693 * ] 3694 * };` 3695 */ 3696 3697/** 3698 * @typedef {Object} PluginDefinition 3699 * @desc The Object used to describe a plugin 3700 * @example wavesurfer.addPlugin(pluginDefinition); 3701 * @property {string} name The name of the plugin, the plugin instance will be 3702 * added as a property to the wavesurfer instance under this name
3703 * @property {?Object} staticProps The properties that should be added to the 3704 * wavesurfer instance as static properties 3705 * @property {?boolean} deferInit Don't initialise plugin 3706 * automatically 3707 * @property {Object} params={} The plugin parameters, they are the first parameter 3708 * passed to the plugin class constructor function 3709 * @property {PluginClass} instance The plugin instance factory, is called with 3710 * the dependency specified in extends. Returns the plugin class. 3711 */ 3712 3713/** 3714 * @interface PluginClass 3715 * 3716 * @desc This is the interface which is implemented by all plugin classes. Note 3717 * that this only turns into an observer after being passed through 3718 * `wavesurfer.addPlugin`. 3719 * 3720 * @extends {Observer} 3721 */ 3722var PluginClass = 3723/*#__PURE__*/ 3724function () { 3725 _createClass(PluginClass, [{ 3726 key: "create", 3727 3728 /** 3729 * Plugin definition factory 3730 * 3731 * This function must be used to create a plugin definition which can be 3732 * used by wavesurfer to correctly instantiate the plugin. 3733 * 3734 * It returns a `PluginDefinition` object representing the plugin. 3735 * 3736 * @param {Object} params={} The plugin params (specific to the plugin) 3737 */ 3738 value: function create(params) {} 3739 /** 3740 * Construct the plugin 3741 * 3742 * @param {Object} params={} The plugin params (specific to the plugin) 3743 * @param {Object} ws The wavesurfer instance 3744 */ 3745 3746 }]); 3747 3748 function PluginClass(params, ws) { 3749 _classCallCheck(this, PluginClass); 3750 } 3751 /** 3752 * Initialise the plugin 3753 * 3754 * Start doing something. This is called by 3755 * `wavesurfer.initPlugin(pluginName)` 3756 */ 3757 3758 3759 _createClass(PluginClass, [{ 3760 key: "init", 3761 value: function init() {} 3762 /** 3763 * Destroy the plugin instance 3764 * 3765 * Stop doing something. This is called by 3766 * `wavesurfer.destroyPlugin(pluginName)` 3767 */ 3768 3769 }, { 3770 key: "destroy", 3771 value: function destroy() {} 3772 }]); 3773 3774 return PluginClass; 3775}(); 3776/** 3777 * WaveSurfer core library class 3778 * 3779 * @extends {Observer} 3780 * @example 3781 * const params = { 3782 * container: '#waveform', 3783 * waveColor: 'violet', 3784 * progressColor: 'purple' 3785 * }; 3786 * 3787 * // initialise like this 3788 * const wavesurfer = WaveSurfer.create(params); 3789 * 3790 * // or like this ... 3791 * const wavesurfer = new WaveSurfer(params); 3792 * wavesurfer.init(); 3793 * 3794 * // load audio file 3795 * wavesurfer.load('example/media/demo.wav'); 3796 */ 3797 3798 3799var WaveSurfer = 3800/*#__PURE__*/ 3801function (_util$Observer) { 3802 _inherits(WaveSurfer, _util$Observer); 3803 3804 _createClass(WaveSurfer, null, [{ 3805 key: "create", 3806 3807 /** @private */ 3808 3809 /** @private */ 3810 3811 /** 3812 * Instantiate this class, call its `init` function and returns it 3813 * 3814 * @param {WavesurferParams} params The wavesurfer parameters 3815 * @return {Object} WaveSurfer instance 3816 * @example const wavesurfer = WaveSurfer.create(params); 3817 */ 3818 value: function create(params) { 3819 var wavesurfer = new WaveSurfer(params); 3820 return wavesurfer.init(); 3821 } 3822 /** 3823 * The library version number is available as a static property of the 3824 * WaveSurfer class 3825 * 3826 * @type {String} 3827 * @example 3828 * console.log('Using wavesurfer.js ' + WaveSurfer.VERSION); 3829 */ 3830 3831 }]); 3832 3833 /** 3834 * Initialise wavesurfer instance 3835 * 3836 * @param {WavesurferParams} params Instantiation options for wavesurfer 3837 * @example 3838 * const wavesurfer = new WaveSurfer(params); 3839 * @returns {this} Wavesurfer instance 3840 */ 3841 function WaveSurfer(params) { 3842 var _this; 3843 3844 _classCallCheck(this, WaveSurfer); 3845 3846 _this = _possibleConstructorReturn(this, _getPrototypeOf(WaveSurfer).call(this)); 3847 /** 3848 * Extract relevant parameters (or defaults) 3849 * @private 3850 */ 3851 3852 _this.defaultParams = { 3853 audioContext: null, 3854 audioScriptProcessor: null, 3855 audioRate: 1, 3856 autoCenter: true, 3857 autoCenterRate: 5, 3858 autoCenterImmediately: false, 3859 backend: 'WebAudio', 3860 backgroundColor: null, 3861 barHeight: 1, 3862 barRadius: 0, 3863 barGap: null, 3864 barMinHeight: null, 3865 container: null, 3866 cursorColor: '#333', 3867 cursorWidth: 1, 3868 dragSelection: true, 3869 drawingContextAttributes: { 3870 // Boolean that hints the user agent to reduce the latency 3871 // by desynchronizing the canvas paint cycle from the event 3872 // loop 3873 desynchronized: false 3874 }, 3875 duration: null, 3876 fillParent: true, 3877 forceDecode: false, 3878 height: 128, 3879 hideScrollbar: false, 3880 interact: true, 3881 loopSelection: true, 3882 maxCanvasWidth: 4000, 3883 mediaContainer: null,
3884 mediaControls: false, 3885 mediaType: 'audio', 3886 minPxPerSec: 20, 3887 normalize: false, 3888 partialRender: false, 3889 pixelRatio: window.devicePixelRatio || screen.deviceXDPI / screen.logicalXDPI, 3890 plugins: [], 3891 progressColor: '#555', 3892 removeMediaElementOnDestroy: true, 3893 renderer: _drawer.default, 3894 responsive: false, 3895 rtl: false, 3896 scrollParent: false, 3897 skipLength: 2, 3898 splitChannels: false, 3899 waveColor: '#999', 3900 xhr: {} 3901 }; 3902 _this.backends = { 3903 MediaElement: _mediaelement.default, 3904 WebAudio: _webaudio.default, 3905 MediaElementWebAudio: _mediaelementWebaudio.default 3906 }; 3907 _this.util = util; 3908 _this.params = Object.assign({}, _this.defaultParams, params); 3909 /** @private */ 3910 3911 _this.container = 'string' == typeof params.container ? document.querySelector(_this.params.container) : _this.params.container; 3912 3913 if (!_this.container) { 3914 throw new Error('Container element not found'); 3915 } 3916 3917 if (_this.params.mediaContainer == null) { 3918 /** @private */ 3919 _this.mediaContainer = _this.container; 3920 } else if (typeof _this.params.mediaContainer == 'string') { 3921 /** @private */ 3922 _this.mediaContainer = document.querySelector(_this.params.mediaContainer); 3923 } else { 3924 /** @private */ 3925 _this.mediaContainer = _this.params.mediaContainer; 3926 } 3927 3928 if (!_this.mediaContainer) { 3929 throw new Error('Media Container element not found'); 3930 } 3931 3932 if (_this.params.maxCanvasWidth <= 1) { 3933 throw new Error('maxCanvasWidth must be greater than 1'); 3934 } else if (_this.params.maxCanvasWidth % 2 == 1) { 3935 throw new Error('maxCanvasWidth must be an even number'); 3936 } 3937 3938 if (_this.params.rtl === true) { 3939 util.style(_this.container, { 3940 transform: 'rotateY(180deg)' 3941 }); 3942 } 3943 3944 if (_this.params.backgroundColor) { 3945 _this.setBackgroundColor(_this.params.backgroundColor); 3946 } 3947 /** 3948 * @private Used to save the current volume when muting so we can 3949 * restore once unmuted 3950 * @type {number} 3951 */ 3952 3953 3954 _this.savedVolume = 0; 3955 /** 3956 * @private The current muted state 3957 * @type {boolean} 3958 */ 3959 3960 _this.isMuted = false; 3961 /** 3962 * @private Will hold a list of event descriptors that need to be 3963 * canceled on subsequent loads of audio 3964 * @type {Object[]} 3965 */ 3966 3967 _this.tmpEvents = []; 3968 /** 3969 * @private Holds any running audio downloads 3970 * @type {Observer} 3971 */ 3972 3973 _this.currentRequest = null; 3974 /** @private */ 3975 3976 _this.arraybuffer = null; 3977 /** @private */ 3978 3979 _this.drawer = null; 3980 /** @private */ 3981 3982 _this.backend = null; 3983 /** @private */ 3984 3985 _this.peakCache = null;
3985 // cache constructor objects 3986 3987 if (typeof _this.params.renderer !== 'function') { 3988 throw new Error('Renderer parameter is invalid'); 3989 } 3990 /** 3991 * @private The uninitialised Drawer class 3992 */ 3993 3994 3995 _this.Drawer = _this.params.renderer; 3996 /** 3997 * @private The uninitialised Backend class 3998 */ 3999 // Back compat 4000 4001 if (_this.params.backend == 'AudioElement') { 4002 _this.params.backend = 'MediaElement'; 4003 } 4004 4005 if ((_this.params.backend == 'WebAudio' || _this.params.backend === 'MediaElementWebAudio') && !_webaudio.default.prototype.supportsWebAudio.call(null)) { 4006 _this.params.backend = 'MediaElement'; 4007 } 4008 4009 _this.Backend = _this.backends[_this.params.backend]; 4010 /** 4011 * @private map of plugin names that are currently initialised 4012 */ 4013 4014 _this.initialisedPluginList = {}; 4015 /** @private */ 4016 4017 _this.isDestroyed = false; 4018 /** 4019 * Get the current ready status. 4020 * 4021 * @example const isReady = wavesurfer.isReady; 4022 * @return {boolean} 4023 */ 4024 4025 _this.isReady = false; // responsive debounced event listener. If this.params.responsive is not 4026 // set, this is never called. Use 100ms or this.params.responsive as 4027 // timeout for the debounce function. 4028 4029 var prevWidth = 0; 4030 _this._onResize = util.debounce(function () { 4031 if (prevWidth != _this.drawer.wrapper.clientWidth && !_this.params.scrollParent) { 4032 prevWidth = _this.drawer.wrapper.clientWidth; 4033 4034 _this.drawer.fireEvent('redraw'); 4035 } 4036 }, typeof _this.params.responsive === 'number' ? _this.params.responsive : 100); 4037 return _possibleConstructorReturn(_this, _assertThisInitialized(_this)); 4038 } 4039 /** 4040 * Initialise the wave 4041 * 4042 * @example 4043 * var wavesurfer = new WaveSurfer(params); 4044 * wavesurfer.init(); 4045 * @return {this} The wavesurfer instance 4046 */ 4047 4048 4049 _createClass(WaveSurfer, [{ 4050 key: "init", 4051 value: function init() { 4052 this.registerPlugins(this.params.plugins); 4053 this.createDrawer(); 4054 this.createBackend(); 4055 this.createPeakCache(); 4056 return this; 4057 } 4058 /** 4059 * Add and initialise array of plugins (if `plugin.deferInit` is falsey), 4060 * this function is called in the init function of wavesurfer 4061 * 4062 * @param {PluginDefinition[]} plugins An array of plugin definitions 4063 * @emits {WaveSurfer#plugins-registered} Called with the array of plugin definitions 4064 * @return {this} The wavesurfer instance 4065 */ 4066 4067 }, { 4068 key: "registerPlugins", 4069 value: function registerPlugins(plugins) { 4070 var _this2 = this; 4071 4072 // first instantiate all the plugins 4073 plugins.forEach(function (plugin) { 4074 return _this2.addPlugin(plugin); 4075 }); // now run the init functions 4076 4077 plugins.forEach(function (plugin) { 4078 // call init function of the plugin if deferInit is falsey 4079 // in that case you would manually use initPlugins() 4080 if (!plugin.deferInit) { 4081 _this2.initPlugin(plugin.name); 4082 } 4083 }); 4084 this.fireEvent('plugins-registered', plugins); 4085 return this; 4086 } 4087 /** 4088 * Get a map of plugin names that are currently initialised 4089 * 4090 * @example wavesurfer.getPlugins(); 4091 * @return {Object} Object with plugin names 4092 */ 4093 4094 }, { 4095 key: "getActivePlugins", 4096 value: function getActivePlugins() { 4097 return this.initialisedPluginList; 4098 } 4099 /** 4100 * Add a plugin object to wavesurfer 4101 * 4102 * @param {PluginDefinition} plugin A plugin definition 4103 * @emits {WaveSurfer#plugin-added} Called with the name of the plugin that was added 4104 * @example wavesurfer.addPlugin(WaveSurfer.minimap()); 4105 * @return {this} The wavesurfer instance 4106 */ 4107 4108 }, { 4109 key: "addPlugin", 4110 value: function addPlugin(plugin) { 4111 var _this3 = this; 4112 4113 if (!plugin.name) { 4114 throw new Error('Plugin does not have a name!'); 4115 } 4116 4117 if (!plugin.instance) { 4118 throw new Error("Plugin ".concat(plugin.name, " does not have an instance property!")); 4119 } // staticProps properties are applied to wavesurfer instance 4120 4121 4122 if (plugin.staticProps) {
4123 Object.keys(plugin.staticProps).forEach(function (pluginStaticProp) { 4124 /** 4125 * Properties defined in a plugin definition's `staticProps` property are added as 4126 * staticProps properties of the WaveSurfer instance 4127 */ 4128 _this3[pluginStaticProp] = plugin.staticProps[pluginStaticProp]; 4129 }); 4130 } 4131 4132 var Instance = plugin.instance; // turn the plugin instance into an observer 4133 4134 var observerPrototypeKeys = Object.getOwnPropertyNames(util.Observer.prototype); 4135 observerPrototypeKeys.forEach(function (key) { 4136 Instance.prototype[key] = util.Observer.prototype[key]; 4137 }); 4138 /** 4139 * Instantiated plugin classes are added as a property of the wavesurfer 4140 * instance 4141 * @type {Object} 4142 */ 4143 4144 this[plugin.name] = new Instance(plugin.params || {}, this); 4145 this.fireEvent('plugin-added', plugin.name); 4146 return this; 4147 } 4148 /** 4149 * Initialise a plugin 4150 * 4151 * @param {string} name A plugin name 4152 * @emits WaveSurfer#plugin-initialised 4153 * @example wavesurfer.initPlugin('minimap'); 4154 * @return {this} The wavesurfer instance 4155 */ 4156 4157 }, { 4158 key: "initPlugin", 4159 value: function initPlugin(name) { 4160 if (!this[name]) { 4161 throw new Error("Plugin ".concat(name, " has not been added yet!")); 4162 } 4163 4164 if (this.initialisedPluginList[name]) { 4165 // destroy any already initialised plugins 4166 this.destroyPlugin(name); 4167 } 4168 4169 this[name].init(); 4170 this.initialisedPluginList[name] = true; 4171 this.fireEvent('plugin-initialised', name); 4172 return this; 4173 } 4174 /** 4175 * Destroy a plugin 4176 * 4177 * @param {string} name A plugin name 4178 * @emits WaveSurfer#plugin-destroyed 4179 * @example wavesurfer.destroyPlugin('minimap'); 4180 * @returns {this} The wavesurfer instance 4181 */ 4182 4183 }, { 4184 key: "destroyPlugin", 4185 value: function destroyPlugin(name) { 4186 if (!this[name]) { 4187 throw new Error("Plugin ".concat(name, " has not been added yet and cannot be destroyed!")); 4188 } 4189 4190 if (!this.initialisedPluginList[name]) { 4191 throw new Error("Plugin ".concat(name, " is not active and cannot be destroyed!")); 4192 } 4193 4194 if (typeof this[name].destroy !== 'function') { 4195 throw new Error("Plugin ".concat(name, " does not have a destroy function!")); 4196 } 4197 4198 this[name].destroy(); 4199 delete this.initialisedPluginList[name]; 4200 this.fireEvent('plugin-destroyed', name); 4201 return this; 4202 } 4203 /** 4204 * Destroy all initialised plugins. Convenience function to use when 4205 * wavesurfer is removed 4206 * 4207 * @private 4208 */ 4209 4210 }, { 4211 key: "destroyAllPlugins", 4212 value: function destroyAllPlugins() { 4213 var _this4 = this; 4214 4215 Object.keys(this.initialisedPluginList).forEach(function (name) { 4216 return _this4.destroyPlugin(name); 4217 }); 4218 } 4219 /** 4220 * Create the drawer and draw the waveform 4221 * 4222 * @private 4223 * @emits WaveSurfer#drawer-created 4224 */ 4225 4226 }, { 4227 key: "createDrawer", 4228 value: function createDrawer() { 4229 var _this5 = this; 4230 4231 this.drawer = new this.Drawer(this.container, this.params); 4232 this.drawer.init(); 4233 this.fireEvent('drawer-created', this.drawer); 4234 4235 if (this.params.responsive !== false) { 4236 window.addEventListener('resize', this._onResize, true); 4237 window.addEventListener('orientationchange', this._onResize, true); 4238 } 4239 4240 this.drawer.on('redraw', function () { 4241 _this5.drawBuffer(); 4242 4243 _this5.drawer.progress(_this5.backend.getPlayedPercents()); 4244 }); // Click-to-seek 4245 4246 this.drawer.on('click', function (e, progress) { 4247 setTimeout(function () { 4248 return _this5.seekTo(progress); 4249 }, 0); 4250 }); // Relay the scroll event from the drawer 4251 4252 this.drawer.on('scroll', function (e) { 4253 if (_this5.params.partialRender) { 4254 _this5.drawBuffer(); 4255 } 4256 4257 _this5.fireEvent('scroll', e); 4258 }); 4259 } 4260 /** 4261 * Create the backend 4262 * 4263 * @private 4264 * @emits WaveSurfer#backend-created 4265 */ 4266 4267 }, { 4268 key: "createBackend", 4269 value: function createBackend() { 4270 var _this6 = this; 4271 4272 if (this.backend) { 4273 this.backend.destroy(); 4274 } 4275 4276 this.backend = new this.Backend(this.params); 4277 this.backend.init(); 4278 this.fireEvent('backend-created', this.backend); 4279 this.backend.on('finish', function () { 4280 _this6.drawer.progress(_this6.backend.getPlayedPercents()); 4281 4282 _this6.fireEvent('finish'); 4283 }); 4284 this.backend.on('play', function () { 4285 return _this6.fireEvent('play'); 4286 }); 4287 this.backend.on('pause', function () { 4288 return _this6.fireEvent('pause'); 4289 }); 4290 this.backend.on('audioprocess', function (time) { 4291 _this6.drawer.progress(_this6.backend.getPlayedPercents()); 4292 4293 _this6.fireEvent('audioprocess', time); 4294 }); // only needed for MediaElement and MediaElementWebAudio backend 4295 4296 if (this.params.backend === 'MediaElement' || this.params.backend === 'MediaElementWebAudio') { 4297 this.backend.on('seek', function () { 4298 _this6.drawer.progress(_this6.backend.getPlayedPercents()); 4299 }); 4300 this.backend.on('volume', function () { 4301 var newVolume = _this6.getVolume(); 4302 4303 _this6.fireEvent('volume', newVolume); 4304 4305 if (_this6.backend.isMuted !== _this6.isMuted) { 4306 _this6.isMuted = _this6.backend.isMuted; 4307 4308 _this6.fireEvent('mute', _this6.isMuted); 4309 } 4310 }); 4311 } 4312 } 4313 /** 4314 * Create the peak cache 4315 * 4316 * @private 4317 */ 4318 4319 }, { 4320 key: "createPeakCache", 4321 value: function createPeakCache() { 4322 if (this.params.partialRender) { 4323 this.peakCache = new _peakcache.default(); 4324 } 4325 } 4326 /** 4327 * Get the duration of the audio clip 4328 * 4329 * @example const duration = wavesurfer.getDuration(); 4330 * @return {number} Duration in seconds 4331 */ 4332 4333 }, { 4334 key: "getDuration", 4335 value: function getDuration() { 4336 return this.backend.getDuration(); 4337 } 4338 /** 4339 * Get the current playback position 4340 * 4341 * @example const currentTime = wavesurfer.getCurrentTime(); 4342 * @return {number} Playback position in seconds 4343 */ 4344 4345 }, { 4346 key: "getCurrentTime", 4347 value: function getCurrentTime() { 4348 return this.backend.getCurrentTime(); 4349 } 4350 /** 4351 * Set the current play time in seconds. 4352 * 4353 * @param {number}
4353 seconds A positive number in seconds. E.g. 10 means 10 4354 * seconds, 60 means 1 minute 4355 */ 4356 4357 }, { 4358 key: "setCurrentTime", 4359 value: function setCurrentTime(seconds) { 4360 if (seconds >= this.getDuration()) { 4361 this.seekTo(1); 4362 } else { 4363 this.seekTo(seconds / this.getDuration()); 4364 } 4365 } 4366 /** 4367 * Starts playback from the current position. Optional start and end 4368 * measured in seconds can be used to set the range of audio to play. 4369 * 4370 * @param {?number} start Position to start at 4371 * @param {?number} end Position to end at 4372 * @emits WaveSurfer#interaction 4373 * @return {Promise} Result of the backend play method 4374 * @example 4375 * // play from second 1 to 5 4376 * wavesurfer.play(1, 5); 4377 */ 4378 4379 }, { 4380 key: "play", 4381 value: function play(start, end) { 4382 var _this7 = this; 4383 4384 this.fireEvent('interaction', function () { 4385 return _this7.play(start, end); 4386 }); 4387 return this.backend.play(start, end); 4388 } 4389 /** 4390 * Set a point in seconds for playback to stop at. 4391 * 4392 * @param {number} position Position (in seconds) to stop at 4393 * @version 3.3.0 4394 */ 4395 4396 }, { 4397 key: "setPlayEnd", 4398 value: function setPlayEnd(position) { 4399 this.backend.setPlayEnd(position); 4400 } 4401 /** 4402 * Stops and pauses playback 4403 * 4404 * @example wavesurfer.pause(); 4405 * @return {Promise} Result of the backend pause method 4406 */ 4407 4408 }, { 4409 key: "pause", 4410 value: function pause() { 4411 if (!this.backend.isPaused()) { 4412 return this.backend.pause(); 4413 } 4414 } 4415 /** 4416 * Toggle playback 4417 * 4418 * @example wavesurfer.playPause(); 4419 * @return {Promise} Result of the backend play or pause method 4420 */ 4421 4422 }, { 4423 key: "playPause", 4424 value: function playPause() { 4425 return this.backend.isPaused() ? this.play() : this.pause(); 4426 } 4427 /** 4428 * Get the current playback state 4429 * 4430 * @example const isPlaying = wavesurfer.isPlaying(); 4431 * @return {boolean} False if paused, true if playing 4432 */ 4433 4434 }, { 4435 key: "isPlaying", 4436 value: function isPlaying() { 4437 return !this.backend.isPaused(); 4438 } 4439 /** 4440 * Skip backward 4441 * 4442 * @param {?number} seconds Amount to skip back, if not specified `skipLength` 4443 * is used 4444 * @example wavesurfer.skipBackward(); 4445 */ 4446 4447 }, { 4448 key: "skipBackward", 4449 value: function skipBackward(seconds) { 4450 this.skip(-seconds || -this.params.skipLength); 4451 } 4452 /** 4453 * Skip forward 4454 * 4455 * @param {?number} seconds Amount to skip back, if not specified `skipLength` 4456 * is used 4457 * @example wavesurfer.skipForward(); 4458 */ 4459 4460 }, { 4461 key: "skipForward", 4462 value: function skipForward(seconds) { 4463 this.skip(seconds || this.params.skipLength); 4464 } 4465 /** 4466 * Skip a number of seconds from the current position (use a negative value 4467 * to go backwards). 4468 * 4469 * @param {number} offset Amount to skip back or forwards 4470 * @example 4471 * // go back 2 seconds 4472 * wavesurfer.skip(-2); 4473 */ 4474 4475 }, { 4476 key: "skip", 4477 value: function skip(offset) { 4478 var duration = this.getDuration() || 1; 4479 var position = this.getCurrentTime() || 0; 4480 position = Math.max(0, Math.min(duration, position + (offset || 0))); 4481 this.seekAndCenter(position / duration); 4482 } 4483 /** 4484 * Seeks to a position and centers the view 4485 * 4486 * @param {number} progress Between 0 (=beginning) and 1 (=end) 4487 * @example 4488 * // seek and go to the middle of the audio 4489 * wavesurfer.seekTo(0.5); 4490 */ 4491 4492 }, { 4493 key: "seekAndCenter", 4494 value: function seekAndCenter(progress) { 4495 this.seekTo(progress); 4496 this.drawer.recenter(progress); 4497 } 4498 /** 4499 * Seeks to a position 4500 * 4501 * @param {number} progress Between 0 (=beginning) and 1 (=end) 4502 * @emits WaveSurfer#interaction 4503 * @emits WaveSurfer#seek 4504 * @example 4505 * // seek to the middle of the audio 4506 * wavesurfer.seekTo(0.5); 4507 */ 4508 4509 }, { 4510 key: "seekTo", 4511 value: function seekTo(progress) { 4512 var _this8 = this; 4513 4514 // return an error if progress is not a number between 0 and 1 4515 if (typeof progress !== 'number' || !isFinite(progress) || progress < 0 || progress > 1) { 4516 throw new Error('Error calling wavesurfer.seekTo, parameter must be a number between 0 and 1!'); 4517 } 4518 4519 this.fireEvent('interaction', function () { 4520 return _this8.seekTo(progress); 4521 }); 4522 var paused = this.backend.isPaused(); // avoid draw wrong position while playing backward seeking 4523 4524 if (!paused) { 4525 this.backend.pause(); 4526 } // avoid small scrolls while paused seeking 4527 4528 4529 var oldScrollParent = this.params.scrollParent; 4530 this.params.scrollParent = false;
4531 this.backend.seekTo(progress * this.getDuration()); 4532 this.drawer.progress(progress); 4533 4534 if (!paused) { 4535 this.backend.play(); 4536 } 4537 4538 this.params.scrollParent = oldScrollParent; 4539 this.fireEvent('seek', progress); 4540 } 4541 /** 4542 * Stops and goes to the beginning. 4543 * 4544 * @example wavesurfer.stop(); 4545 */ 4546 4547 }, { 4548 key: "stop", 4549 value: function stop() { 4550 this.pause(); 4551 this.seekTo(0); 4552 this.drawer.progress(0); 4553 } 4554 /** 4555 * Sets the ID of the audio device to use for output and returns a Promise. 4556 * 4557 * @param {string} deviceId String value representing underlying output 4558 * device 4559 * @returns {Promise} `Promise` that resolves to `undefined` when there are 4560 * no errors detected. 4561 */ 4562 4563 }, { 4564 key: "setSinkId", 4565 value: function setSinkId(deviceId) { 4566 return this.backend.setSinkId(deviceId); 4567 } 4568 /** 4569 * Set the playback volume. 4570 * 4571 * @param {number} newVolume A value between 0 and 1, 0 being no 4572 * volume and 1 being full volume. 4573 * @emits WaveSurfer#volume 4574 */ 4575 4576 }, { 4577 key: "setVolume", 4578 value: function setVolume(newVolume) { 4579 this.backend.setVolume(newVolume); 4580 this.fireEvent('volume', newVolume); 4581 } 4582 /** 4583 * Get the playback volume. 4584 * 4585 * @return {number} A value between 0 and 1, 0 being no 4586 * volume and 1 being full volume. 4587 */ 4588 4589 }, { 4590 key: "getVolume", 4591 value: function getVolume() { 4592 return this.backend.getVolume(); 4593 } 4594 /** 4595 * Set the playback rate. 4596 * 4597 * @param {number} rate A positive number. E.g. 0.5 means half the normal 4598 * speed, 2 means double speed and so on. 4599 * @example wavesurfer.setPlaybackRate(2); 4600 */ 4601 4602 }, { 4603 key: "setPlaybackRate", 4604 value: function setPlaybackRate(rate) { 4605 this.backend.setPlaybackRate(rate); 4606 } 4607 /** 4608 * Get the playback rate. 4609 * 4610 * @return {number} The current playback rate. 4611 */ 4612 4613 }, { 4614 key: "getPlaybackRate", 4615 value: function getPlaybackRate() { 4616 return this.backend.getPlaybackRate(); 4617 } 4618 /** 4619 * Toggle the volume on and off. If not currently muted it will save the 4620 * current volume value and turn the volume off. If currently muted then it 4621 * will restore the volume to the saved value, and then rest the saved 4622 * value. 4623 * 4624 * @example wavesurfer.toggleMute(); 4625 */ 4626 4627 }, { 4628 key: "toggleMute", 4629 value: function toggleMute() { 4630 this.setMute(!this.isMuted); 4631 } 4632 /** 4633 * Enable or disable muted audio 4634 * 4635 * @param {boolean} mute Specify `true` to mute audio. 4636 * @emits WaveSurfer#volume 4637 * @emits WaveSurfer#mute 4638 * @example 4639 * // unmute 4640 * wavesurfer.setMute(false); 4641 * console.log(wavesurfer.getMute()) // logs false 4642 */ 4643 4644 }, { 4645 key: "setMute", 4646 value: function setMute(mute) { 4647 // ignore all muting requests if the audio is already in that state 4648 if (mute === this.isMuted) { 4649 this.fireEvent('mute', this.isMuted); 4650 return; 4651 } 4652 4653 if (mute) { 4654 // If currently not muted then save current volume, 4655 // turn off the volume and update the mute properties 4656 this.savedVolume = this.backend.getVolume(); 4657 this.backend.setVolume(0); 4658 this.isMuted = true; 4659 this.fireEvent('volume', 0); 4660 } else { 4661 // If currently muted then restore to the saved volume 4662 // and update the mute properties 4663 this.backend.setVolume(this.savedVolume); 4664 this.isMuted = false; 4665 this.fireEvent('volume', this.savedVolume); 4666 } 4667 4668 this.fireEvent('mute', this.isMuted); 4669 } 4670 /** 4671 * Get the current mute status. 4672 * 4673 * @example const isMuted = wavesurfer.getMute(); 4674 * @return {boolean} Current mute status 4675 */ 4676 4677 }, { 4678 key: "getMute", 4679 value: function getMute() { 4680 return this.isMuted; 4681 } 4682 /** 4683 * Get the list of current set filters as an array. 4684 * 4685 * Filters must be set with setFilters method first 4686 * 4687 * @return {array} List of enabled filters 4688 */ 4689 4690 }, { 4691 key: "getFilters", 4692 value: function getFilters() { 4693 return this.backend.filters || []; 4694 } 4695 /** 4696 * Toggles `scrollParent` and redraws 4697 * 4698 * @example wavesurfer.toggleScroll(); 4699 */ 4700 4701 }, { 4702 key: "toggleScroll", 4703 value: function toggleScroll() { 4704 this.params.scrollParent = !this.params.scrollParent; 4705 this.drawBuffer(); 4706 } 4707 /** 4708 * Toggle mouse interaction 4709 * 4710 * @example wavesurfer.toggleInteraction(); 4711 */ 4712 4713 }, { 4714 key: "toggleInteraction", 4715 value: function toggleInteraction() { 4716 this.params.interact = !this.params.interact; 4717 } 4718 /** 4719 * Get the fill color of the waveform after the cursor. 4720 * 4721 * @return {string} A CSS color string. 4722 */ 4723 4724 }, { 4725 key: "getWaveColor", 4726 value: function getWaveColor() { 4727 return this.params.waveColor; 4728 } 4729 /** 4730 * Set the fill color of the waveform after the cursor. 4731 * 4732 * @param {string} color A CSS color string. 4733 * @example wavesurfer.setWaveColor('#ddd'); 4734 */ 4735 4736 }, { 4737 key: "setWaveColor", 4738 value: function setWaveColor(color) { 4739 this.params.waveColor = color; 4740 this.drawBuffer(); 4741 } 4742 /** 4743 * Get the fill color of the waveform behind the cursor. 4744 * 4745 * @return {string} A CSS color string. 4746 */ 4747 4748 }, { 4749 key: "getProgressColor", 4750 value: function getProgressColor() { 4751 return this.params.progressColor; 4752 } 4753 /** 4754 * Set the fill color of the waveform behind the cursor. 4755 * 4756 * @param {string} color A CSS color string. 4757 * @example wavesurfer.setProgressColor('#400'); 4758 */ 4759 4760 }, { 4761 key: "setProgressColor", 4762 value: function setProgressColor(color) { 4763 this.params.progressColor = color; 4764 this.drawBuffer(); 4765 } 4766 /** 4767 * Get the background color of the waveform container. 4768 * 4769 * @return {string} A CSS color string. 4770 */ 4771 4772 }, {
4773 key: "getBackgroundColor", 4774 value: function getBackgroundColor() { 4775 return this.params.backgroundColor; 4776 } 4777 /** 4778 * Set the background color of the waveform container. 4779 * 4780 * @param {string} color A CSS color string. 4781 * @example wavesurfer.setBackgroundColor('#FF00FF'); 4782 */ 4783 4784 }, { 4785 key: "setBackgroundColor", 4786 value: function setBackgroundColor(color) { 4787 this.params.backgroundColor = color; 4788 util.style(this.container, { 4789 background: this.params.backgroundColor 4790 }); 4791 } 4792 /** 4793 * Get the fill color of the cursor indicating the playhead 4794 * position. 4795 * 4796 * @return {string} A CSS color string. 4797 */ 4798 4799 }, { 4800 key: "getCursorColor", 4801 value: function getCursorColor() { 4802 return this.params.cursorColor; 4803 } 4804 /** 4805 * Set the fill color of the cursor indicating the playhead 4806 * position. 4807 * 4808 * @param {string} color A CSS color string. 4809 * @example wavesurfer.setCursorColor('#222'); 4810 */ 4811 4812 }, { 4813 key: "setCursorColor", 4814 value: function setCursorColor(color) { 4815 this.params.cursorColor = color; 4816 this.drawer.updateCursor(); 4817 } 4818 /** 4819 * Get the height of the waveform. 4820 * 4821 * @return {number} Height measured in pixels. 4822 */ 4823 4824 }, { 4825 key: "getHeight", 4826 value: function getHeight() { 4827 return this.params.height; 4828 } 4829 /** 4830 * Set the height of the waveform. 4831 * 4832 * @param {number} height Height measured in pixels. 4833 * @example wavesurfer.setHeight(200); 4834 */ 4835 4836 }, { 4837 key: "setHeight", 4838 value: function setHeight(height) { 4839 this.params.height = height; 4840 this.drawer.setHeight(height * this.params.pixelRatio); 4841 this.drawBuffer(); 4842 } 4843 /** 4844 * Get the correct peaks for current wave view-port and render wave 4845 * 4846 * @private 4847 * @emits WaveSurfer#redraw 4848 */ 4849 4850 }, { 4851 key: "drawBuffer", 4852 value: function drawBuffer() { 4853 var nominalWidth = Math.round(this.getDuration() * this.params.minPxPerSec * this.params.pixelRatio); 4854 var parentWidth = this.drawer.getWidth(); 4855 var width = nominalWidth; // always start at 0 after zooming for scrolling : issue redraw left part 4856 4857 var start = 0; 4858 var end = Math.max(start + parentWidth, width); // Fill container 4859 4860 if (this.params.fillParent && (!this.params.scrollParent || nominalWidth < parentWidth)) { 4861 width = parentWidth; 4862 start = 0; 4863 end = width; 4864 } 4865 4866 var peaks; 4867 4868 if (this.params.partialRender) { 4869 var newRanges = this.peakCache.addRangeToPeakCache(width, start, end); 4870 var i; 4871 4872 for (i = 0; i < newRanges.length; i++) { 4873 peaks = this.backend.getPeaks(width, newRanges[i][0], newRanges[i][1]); 4874 this.drawer.drawPeaks(peaks, width, newRanges[i][0], newRanges[i][1]); 4875 } 4876 } else { 4877 peaks = this.backend.getPeaks(width, start, end); 4878 this.drawer.drawPeaks(peaks, width, start, end); 4879 } 4880 4881 this.fireEvent('redraw', peaks, width); 4882 } 4883 /** 4884 * Horizontally zooms the waveform in and out. It also changes the parameter 4885 * `minPxPerSec` and enables the `scrollParent` option. Calling the function 4886 * with a falsey parameter will reset the zoom state. 4887 * 4888 * @param {?number} pxPerSec Number of horizontal pixels per second of 4889 * audio, if none is set the waveform returns to unzoomed state 4890 * @emits WaveSurfer#zoom 4891 * @example wavesurfer.zoom(20); 4892 */ 4893 4894 }, { 4895 key: "zoom", 4896 value: function zoom(pxPerSec) { 4897 if (!pxPerSec) { 4898 this.params.minPxPerSec = this.defaultParams.minPxPerSec; 4899 this.params.scrollParent = false; 4900 } else { 4901 this.params.minPxPerSec = pxPerSec; 4902 this.params.scrollParent = true; 4903 } 4904 4905 this.drawBuffer(); 4906 this.drawer.progress(this.backend.getPlayedPercents()); 4907 this.drawer.recenter(this.getCurrentTime() / this.getDuration()); 4908 this.fireEvent('zoom', pxPerSec); 4909 } 4910 /** 4911 * Decode buffer and load 4912 * 4913 * @private 4914 * @param {ArrayBuffer} arraybuffer Buffer to process 4915 */ 4916 4917 }, { 4918 key: "loadArrayBuffer", 4919 value: function loadArrayBuffer(arraybuffer) { 4920 var _this9 = this; 4921 4922 this.decodeArrayBuffer(arraybuffer, function (data) { 4923 if (!_this9.isDestroyed) { 4924 _this9.loadDecodedBuffer(data); 4925 } 4926 }); 4927 } 4928 /** 4929 * Directly load an externally decoded AudioBuffer 4930 * 4931 * @private 4932 * @param {AudioBuffer} buffer Buffer to process 4933 * @emits WaveSurfer#ready 4934 */ 4935 4936 }, { 4937 key: "loadDecodedBuffer", 4938 value: function loadDecodedBuffer(buffer) { 4939 this.backend.load(buffer); 4940 this.drawBuffer(); 4941 this.isReady = true; 4942 this.fireEvent('ready'); 4943 } 4944 /** 4945 * Loads audio data from a Blob or File object 4946 * 4947 * @param {Blob|File} blob Audio data 4948 * @example 4949 */ 4950 4951 }, { 4952 key: "loadBlob", 4953 value: function loadBlob(blob) { 4954 var _this10 = this; 4955 4956 // Create file reader 4957 var reader = new FileReader(); 4958 reader.addEventListener('progress', function (e) { 4959 return _this10.onProgress(e); 4960 }); 4961 reader.addEventListener('load', function (e) { 4962 return _this10.loadArrayBuffer(e.target.result); 4963 }); 4964 reader.addEventListener('error', function () { 4965 return _this10.fireEvent('error', 'Error reading file'); 4966 }); 4967 reader.readAsArrayBuffer(blob); 4968 this.empty(); 4969 } 4970 /** 4971 * Loads audio and re-renders the waveform. 4972 * 4973 * @param {string|HTMLMediaElement} url The url of the audio file or the 4974 * audio element with the audio 4975 * @param {number[]|Number.<Array[]>} peaks Wavesurfer does not have to decode 4976 * the audio to render the waveform if this is specified 4977 * @param {?string} preload (Use with backend `MediaElement` and `MediaElementWebAudio`) 4978 * `'none'|'metadata'|'auto'` Preload attribute for the media element 4979 * @param {?number} duration The duration of the audio. This is used to 4980 * render the peaks data in the correct size for the audio duration (as 4981 * befits the current `minPxPerSec` and zoom value) without having to decode 4982 * the audio. 4983 * @returns {void} 4984 * @throws Will throw an error if the `url` argument is empty. 4985 * @example 4986 * // uses fetch or media element to load file (depending on backend) 4987 * wavesurfer.load('http://example.com/demo.wav'); 4988 * 4989 * // setting preload attribute with media element backend and supplying 4990 * // peaks 4991 * wavesurfer.load( 4992 * 'http://example.com/demo.wav', 4993 * [0.0218, 0.0183, 0.0165, 0.0198, 0.2137, 0.2888], 4994 * true 4995 * ); 4996 */ 4997 4998 }, { 4999 key: "load", 5000 value: function load(url, peaks, preload, duration) { 5001 if (!url) { 5002 throw new Error('url parameter cannot be empty'); 5003 } 5004 5005 this.empty(); 5006 5007 if (preload) { 5008 // check whether the preload attribute will be usable and if not log 5009 // a warning listing the reasons why not and nullify the variable 5010 var preloadIgnoreReasons = { 5011 "Preload is not 'auto', 'none' or 'metadata'": ['auto', 'metadata', 'none'].indexOf(preload) === -1, 5012 'Peaks are not provided': !peaks, 5013 "Backend is not of type 'MediaElement' or 'MediaElementWebAudio'": ['MediaElement', 'MediaElementWebAudio'].indexOf(this.params.backend) === -1, 5014 'Url is not of type string': typeof url !== 'string' 5015 }; 5016 var activeReasons = Object.keys(preloadIgnoreReasons).filter(function (reason) { 5017 return preloadIgnoreReasons[reason]; 5018 }); 5019 5020 if (activeReasons.length) { 5021 // eslint-disable-next-line no-console 5022 console.warn('Preload parameter of wavesurfer.load will be ignored because:\n\t- ' + activeReasons.join('\n\t- ')); // stop invalid values from being used 5023 5024 preload = null; 5025 } 5026 } 5027 5028 switch (this.params.backend) { 5029 case 'WebAudio': 5030 return this.loadBuffer(url, peaks, duration); 5031 5032 case 'MediaElement': 5033 case 'MediaElementWebAudio': 5034 return this.loadMediaElement(url, peaks, preload, duration); 5035 } 5036 } 5037 /** 5038 * Loads audio using Web Audio buffer backend. 5039 * 5040 * @private 5041 * @param {string} url URL of audio file 5042 * @param {number[]|Number.<Array[]>} peaks Peaks data 5043 * @param {?number} duration Optional duration of audio file 5044 * @returns {void} 5045 */ 5046 5047 }, { 5048 key: "loadBuffer", 5049 value: function loadBuffer(url, peaks, duration) { 5050 var _this11 = this; 5051 5052 var load = function load(action) { 5053 if (action) { 5054 _this11.tmpEvents.push(_this11.once('ready', action)); 5055 } 5056 5057 return _this11.getArrayBuffer(url, function (data) { 5058 return _this11.loadArrayBuffer(data); 5059 }); 5060 }; 5061 5062 if (peaks) { 5063 this.backend.setPeaks(peaks, duration); 5064 this.drawBuffer(); 5065 this.tmpEvents.push(this.once('interaction', load)); 5066 } else { 5067 return load(); 5068 } 5069 } 5070 /** 5071 * Either create a media element, or load an existing media element. 5072 * 5073 * @private 5074 * @param {string|HTMLMediaElement} urlOrElt Either a path to a media file, or an 5075 * existing HTML5 Audio/Video Element 5076 * @param {number[]|Number.<Array[]>} peaks Array of peaks. Required to bypass web audio 5077 * dependency 5078 * @param {?boolean} preload Set to true if the preload attribute of the 5079 * audio element should be enabled 5080 * @param {?number} duration Optional duration of audio file 5081 */ 5082 5083 }, { 5084 key: "loadMediaElement", 5085 value: function loadMediaElement(urlOrElt, peaks, preload, duration) { 5086 var _this12 = this; 5087 5088 var url = urlOrElt; 5089 5090 if (typeof urlOrElt === 'string') { 5091 this.backend.load(url, this.mediaContainer, peaks, preload); 5092 } else { 5093 var elt = urlOrElt; 5094 this.backend.loadElt(elt, peaks); // If peaks are not provided, 5095 // url = element.src so we can get peaks with web audio 5096 5097 url = elt.src; 5098 } 5099 5100 this.tmpEvents.push(this.backend.once('canplay', function () { 5101 // ignore when backend was already destroyed 5102 if (!_this12.backend.destroyed) { 5103 _this12.drawBuffer(); 5104 5105 _this12.isReady = true; 5106 5107 _this12.fireEvent('ready'); 5108 } 5109 }), this.backend.once('error', function (err) { 5110 return _this12.fireEvent('error', err); 5111 })); // If no pre-decoded peaks provided or pre-decoded peaks are 5112 // provided with forceDecode flag, attempt to download the 5113 // audio file and decode it with Web Audio. 5114 5115 if (peaks) { 5116 this.backend.setPeaks(peaks, duration); 5117 } 5118 5119 if ((!peaks || this.params.forceDecode) && this.backend.supportsWebAudio()) { 5120 this.getArrayBuffer(url, function (arraybuffer) { 5121 _this12.decodeArrayBuffer(arraybuffer, function (buffer) { 5122 _this12.backend.buffer = buffer; 5123 5124 _this12.backend.setPeaks(null); 5125 5126 _this12.drawBuffer(); 5127 5128 _this12.fireEvent('waveform-ready'); 5129 }); 5130 }); 5131 } 5132 } 5133 /** 5134 * Decode an array buffer and pass data to a callback 5135 * 5136 * @private 5137 * @param {Object} arraybuffer The array buffer to decode 5138 * @param {function} callback The function to call on complete 5139 */ 5140 5141 }, { 5142 key: "decodeArrayBuffer", 5143 value: function decodeArrayBuffer(arraybuffer, callback) { 5144 var _this13 = this; 5145 5146 this.arraybuffer = arraybuffer; 5147 this.backend.decodeArrayBuffer(arraybuffer, function (data) { 5148 // Only use the decoded data if we haven't been destroyed or 5149 // another decode started in the meantime
5150 if (!_this13.isDestroyed && _this13.arraybuffer == arraybuffer) { 5151 callback(data); 5152 _this13.arraybuffer = null; 5153 } 5154 }, function () { 5155 return _this13.fireEvent('error', 'Error decoding audiobuffer'); 5156 }); 5157 } 5158 /** 5159 * Load an array buffer using fetch and pass the result to a callback 5160 * 5161 * @param {string} url The URL of the file object 5162 * @param {function} callback The function to call on complete 5163 * @returns {util.fetchFile} fetch call 5164 * @private 5165 */ 5166 5167 }, { 5168 key: "getArrayBuffer", 5169 value: function getArrayBuffer(url, callback) { 5170 var _this14 = this; 5171 5172 var options = Object.assign({ 5173 url: url, 5174 responseType: 'arraybuffer' 5175 }, this.params.xhr); 5176 var request = util.fetchFile(options); 5177 this.currentRequest = request; 5178 this.tmpEvents.push(request.on('progress', function (e) { 5179 _this14.onProgress(e); 5180 }), request.on('success', function (data) { 5181 callback(data); 5182 _this14.currentRequest = null; 5183 }), request.on('error', function (e) { 5184 _this14.fireEvent('error', e); 5185 5186 _this14.currentRequest = null; 5187 })); 5188 return request; 5189 } 5190 /** 5191 * Called while the audio file is loading 5192 * 5193 * @private 5194 * @param {Event} e Progress event 5195 * @emits WaveSurfer#loading 5196 */ 5197 5198 }, { 5199 key: "onProgress", 5200 value: function onProgress(e) { 5201 var percentComplete; 5202 5203 if (e.lengthComputable) { 5204 percentComplete = e.loaded / e.total; 5205 } else { 5206 // Approximate progress with an asymptotic 5207 // function, and assume downloads in the 1-3 MB range. 5208 percentComplete = e.loaded / (e.loaded + 1000000); 5209 } 5210 5211 this.fireEvent('loading', Math.round(percentComplete * 100), e.target); 5212 } 5213 /** 5214 * Exports PCM data into a JSON array and opens in a new window. 5215 * 5216 * @param {number} length=1024 The scale in which to export the peaks 5217 * @param {number} accuracy=10000 5218 * @param {?boolean} noWindow Set to true to disable opening a new 5219 * window with the JSON 5220 * @param {number} start Start index 5221 * @param {number} end End index 5222 * @return {Promise} Promise that resolves with array of peaks 5223 */ 5224 5225 }, { 5226 key: "exportPCM", 5227 value: function exportPCM(length, accuracy, noWindow, start, end) { 5228 length = length || 1024; 5229 start = start || 0; 5230 accuracy = accuracy || 10000; 5231 noWindow = noWindow || false; 5232 var peaks = this.backend.getPeaks(length, start, end); 5233 var arr = [].map.call(peaks, function (val) { 5234 return Math.round(val * accuracy) / accuracy; 5235 }); 5236 return new Promise(function (resolve, reject) { 5237 var json = JSON.stringify(arr); 5238 5239 if (!noWindow) { 5240 window.open('data:application/json;charset=utf-8,' + encodeURIComponent(json)); 5241 } 5242 5243 resolve(json); 5244 }); 5245 } 5246 /** 5247 * Save waveform image as data URI. 5248 * 5249 * The default format is `'image/png'`. Other supported types are 5250 * `'image/jpeg'` and `'image/webp'`. 5251 * 5252 * @param {string} format='image/png' A string indicating the image format. 5253 * The default format type is `'image/png'`. 5254 * @param {number} quality=1 A number between 0 and 1 indicating the image 5255 * quality to use for image formats that use lossy compression such as 5256 * `'image/jpeg'`` and `'image/webp'`. 5257 * @param {string} type Image data type to return. Either 'dataURL' (default) 5258 * or 'blob'. 5259 * @return {string|string[]|Promise} When using `'dataURL'` type this returns 5260 * a single data URL or an array of data URLs, one for each canvas. When using 5261 * `'blob'` type this returns a `Promise` resolving with an array of `Blob` 5262 * instances, one for each canvas. 5263 */ 5264 5265 }, { 5266 key: "exportImage", 5267 value: function exportImage(format, quality, type) { 5268 if (!format) { 5269 format = 'image/png'; 5270 } 5271 5272 if (!quality) { 5273 quality = 1; 5274 } 5275 5276 if (!type) { 5277 type = 'dataURL'; 5278 } 5279 5280 return this.drawer.getImage(format, quality, type); 5281 } 5282 /** 5283 * Cancel any fetch request currently in progress 5284 */ 5285 5286 }, { 5287 key: "cancelAjax", 5288 value: function cancelAjax() { 5289 if (this.currentRequest && this.currentRequest.controller) { 5290 this.currentRequest.controller.abort(); 5291 this.currentRequest = null; 5292 } 5293 } 5294 /** 5295 * @private 5296 */ 5297 5298 }, { 5299 key: "clearTmpEvents", 5300 value: function clearTmpEvents() {
5301 this.tmpEvents.forEach(function (e) { 5302 return e.un(); 5303 }); 5304 } 5305 /** 5306 * Display empty waveform. 5307 */ 5308 5309 }, { 5310 key: "empty", 5311 value: function empty() { 5312 if (!this.backend.isPaused()) { 5313 this.stop(); 5314 this.backend.disconnectSource(); 5315 } 5316 5317 this.isReady = false; 5318 this.cancelAjax(); 5319 this.clearTmpEvents(); // empty drawer 5320 5321 this.drawer.progress(0); 5322 this.drawer.setWidth(0); 5323 this.drawer.drawPeaks({ 5324 length: this.drawer.getWidth() 5325 }, 0); 5326 } 5327 /** 5328 * Remove events, elements and disconnect WebAudio nodes. 5329 * 5330 * @emits WaveSurfer#destroy 5331 */ 5332 5333 }, { 5334 key: "destroy", 5335 value: function destroy() { 5336 this.destroyAllPlugins(); 5337 this.fireEvent('destroy'); 5338 this.cancelAjax(); 5339 this.clearTmpEvents(); 5340 this.unAll(); 5341 5342 if (this.params.responsive !== false) { 5343 window.removeEventListener('resize', this._onResize, true); 5344 window.removeEventListener('orientationchange', this._onResize, true); 5345 } 5346 5347 if (this.backend) { 5348 this.backend.destroy(); 5349 } 5350 5351 if (this.drawer) { 5352 this.drawer.destroy(); 5353 } 5354 5355 this.isDestroyed = true; 5356 this.isReady = false; 5357 this.arraybuffer = null; 5358 } 5359 }]); 5360 5361 return WaveSurfer; 5362}(util.Observer); 5363 5364exports.default = WaveSurfer; 5365WaveSurfer.VERSION = "3.3.3"; 5366WaveSurfer.util = util; 5367module.exports = exports.default; 5368 5369/***/ }), 5370
5371/***/ "./src/webaudio.js": 5372/*!*************************!*\ 5373 !*** ./src/webaudio.js ***! 5374 \*************************/ 5375/*! no static exports found */ 5376/***/ (function(module, exports, __webpack_require__) { 5377 5378"use strict"; 5379 5380 5381Object.defineProperty(exports, "__esModule", { 5382 value: true 5383}); 5384exports.default = void 0; 5385 5386var util = _interopRequireWildcard(__webpack_require__(/*! ./util */ "./src/util/index.js")); 5387 5388function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; } 5389 5390function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } 5391 5392function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } 5393 5394function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } 5395 5396function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 5397 5398function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } 5399 5400function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } 5401 5402function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } 5403 5404function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } 5405 5406function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } 5407 5408function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } 5409 5410function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } 5411 5412// using constants to prevent someone writing the string wrong 5413var PLAYING = 'playing'; 5414var PAUSED = 'paused'; 5415var FINISHED = 'finished'; 5416/** 5417 * WebAudio backend 5418 * 5419 * @extends {Observer} 5420 */ 5421 5422var WebAudio = 5423/*#__PURE__*/ 5424function (_util$Observer) { 5425 _inherits(WebAudio, _util$Observer); 5426 5427 _createClass(WebAudio, [{ 5428 key: "supportsWebAudio", 5429 5430 /** scriptBufferSize: size of the processing buffer */ 5431 5432 /** audioContext: allows to process audio with WebAudio API */ 5433 5434 /** @private */ 5435 5436 /** @private */ 5437 5438 /** 5439 * Does the browser support this backend 5440 * 5441 * @return {boolean} Whether or not this browser supports this backend 5442 */ 5443 value: function supportsWebAudio() { 5444 return !!(window.AudioContext || window.webkitAudioContext); 5445 } 5446 /** 5447 * Get the audio context used by this backend or create one 5448 * 5449 * @return {AudioContext} Existing audio context, or creates a new one 5450 */ 5451 5452 }, { 5453 key: "getAudioContext", 5454 value: function getAudioContext() { 5455 if (!window.WaveSurferAudioContext) { 5456 window.WaveSurferAudioContext = new (window.AudioContext || window.webkitAudioContext)(); 5457 } 5458 5459 return window.WaveSurferAudioContext; 5460 } 5461 /** 5462 * Get the offline audio context used by this backend or create one 5463 * 5464 * @param {number} sampleRate The sample rate to use 5465 * @return {OfflineAudioContext} Existing offline audio context, or creates 5466 * a new one 5467 */ 5468 5469 }, { 5470 key: "getOfflineAudioContext", 5471 value: function getOfflineAudioContext(sampleRate) { 5472 if (!window.WaveSurferOfflineAudioContext) { 5473 window.WaveSurferOfflineAudioContext = new (window.OfflineAudioContext || window.webkitOfflineAudioContext)(1, 2, sampleRate); 5474 } 5475 5476 return window.WaveSurferOfflineAudioContext; 5477 } 5478 /** 5479 * Construct the backend 5480 * 5481 * @param {WavesurferParams} params Wavesurfer parameters 5482 */ 5483 5484 }]); 5485 5486 function WebAudio(params) { 5487 var _this$stateBehaviors, _this$states; 5488 5489 var _this; 5490 5491 _classCallCheck(this, WebAudio); 5492 5493 _this = _possibleConstructorReturn(this, _getPrototypeOf(WebAudio).call(this)); 5494 /** @private */ 5495 5496 _this.audioContext = null; 5497 _this.offlineAudioContext = null; 5498 _this.stateBehaviors = (_this$stateBehaviors = {}, _defineProperty(_this$stateBehaviors, PLAYING, {
5499 init: function init() { 5500 this.addOnAudioProcess(); 5501 }, 5502 getPlayedPercents: function getPlayedPercents() { 5503 var duration = this.getDuration(); 5504 return this.getCurrentTime() / duration || 0; 5505 }, 5506 getCurrentTime: function getCurrentTime() { 5507 return this.startPosition + this.getPlayedTime(); 5508 } 5509 }), _defineProperty(_this$stateBehaviors, PAUSED, { 5510 init: function init() { 5511 this.removeOnAudioProcess(); 5512 }, 5513 getPlayedPercents: function getPlayedPercents() { 5514 var duration = this.getDuration(); 5515 return this.getCurrentTime() / duration || 0; 5516 }, 5517 getCurrentTime: function getCurrentTime() { 5518 return this.startPosition; 5519 } 5520 }), _defineProperty(_this$stateBehaviors, FINISHED, { 5521 init: function init() { 5522 this.removeOnAudioProcess(); 5523 this.fireEvent('finish'); 5524 }, 5525 getPlayedPercents: function getPlayedPercents() { 5526 return 1; 5527 }, 5528 getCurrentTime: function getCurrentTime() { 5529 return this.getDuration(); 5530 } 5531 }), _this$stateBehaviors); 5532 _this.params = params; 5533 /** ac: Audio Context instance */ 5534 5535 _this.ac = params.audioContext || (_this.supportsWebAudio() ? _this.getAudioContext() : {}); 5536 /**@private */ 5537 5538 _this.lastPlay = _this.ac.currentTime; 5539 /** @private */ 5540 5541 _this.startPosition = 0; 5542 /** @private */ 5543 5544 _this.scheduledPause = null; 5545 /** @private */ 5546 5547 _this.states = (_this$states = {}, _defineProperty(_this$states, PLAYING, Object.create(_this.stateBehaviors[PLAYING])), _defineProperty(_this$states, PAUSED, Object.create(_this.stateBehaviors[PAUSED])), _defineProperty(_this$states, FINISHED, Object.create(_this.stateBehaviors[FINISHED])), _this$states); 5548 /** @private */ 5549 5550 _this.buffer = null; 5551 /** @private */ 5552 5553 _this.filters = []; 5554 /** gainNode: allows to control audio volume */ 5555 5556 _this.gainNode = null; 5557 /** @private */ 5558 5559 _this.mergedPeaks = null; 5560 /** @private */ 5561 5562 _this.offlineAc = null; 5563 /** @private */ 5564 5565 _this.peaks = null; 5566 /** @private */ 5567 5568 _this.playbackRate = 1; 5569 /** analyser: provides audio analysis information */ 5570 5571 _this.analyser = null; 5572 /** scriptNode: allows processing audio */ 5573 5574 _this.scriptNode = null; 5575 /** @private */ 5576 5577 _this.source = null; 5578 /** @private */ 5579 5580 _this.splitPeaks = []; 5581 /** @private */ 5582 5583 _this.state = null; 5584 /** @private */ 5585 5586 _this.explicitDuration = params.duration; 5587 /** 5588 * Boolean indicating if the backend was destroyed. 5589 */ 5590 5591 _this.destroyed = false; 5592 return _this; 5593 } 5594 /** 5595 * Initialise the backend, called in `wavesurfer.createBackend()` 5596 */ 5597 5598 5599 _createClass(WebAudio, [{ 5600 key: "init", 5601 value: function init() { 5602 this.createVolumeNode(); 5603 this.createScriptNode(); 5604 this.createAnalyserNode(); 5605 this.setState(PAUSED); 5606 this.setPlaybackRate(this.params.audioRate); 5607 this.setLength(0); 5608 } 5609 /** @private */ 5610 5611 }, { 5612 key: "disconnectFilters", 5613 value: function disconnectFilters() { 5614 if (this.filters) { 5615 this.filters.forEach(function (filter) { 5616 filter && filter.disconnect(); 5617 }); 5618 this.filters = null; // Reconnect direct path 5619 5620 this.analyser.connect(this.gainNode); 5621 } 5622 } 5623 /** 5624 * @private 5625 * 5626 * @param {string} state The new state 5627 */ 5628 5629 }, { 5630 key: "setState", 5631 value: function setState(state) { 5632 if (this.state !== this.states[state]) { 5633 this.state = this.states[state]; 5634 this.state.init.call(this); 5635 } 5636 } 5637 /** 5638 * Unpacked `setFilters()` 5639 * 5640 * @param {...AudioNode} filters One or more filters to set 5641 */ 5642 5643 }, { 5644 key: "setFilter", 5645 value: function setFilter() { 5646 for (var _len = arguments.length, filters = new Array(_len), _key = 0; _key < _len; _key++) { 5647 filters[_key] = arguments[_key]; 5648 } 5649 5650 this.setFilters(filters); 5651 } 5652 /** 5653 * Insert custom Web Audio nodes into the graph 5654 * 5655 * @param {AudioNode[]} filters Packed filters array 5656 * @example 5657 * const lowpass = wavesurfer.backend.ac.createBiquadFilter(); 5658 * wavesurfer.backend.setFilter(lowpass); 5659 */ 5660 5661 }, { 5662 key: "setFilters", 5663 value: function setFilters(filters) { 5664 // Remove existing filters 5665 this.disconnectFilters(); // Insert filters if filter array not empty 5666 5667 if (filters && filters.length) { 5668 this.filters = filters; // Disconnect direct path before inserting filters 5669 5670 this.analyser.disconnect(); // Connect each filter in turn 5671 5672 filters.reduce(function (prev, curr) { 5673 prev.connect(curr); 5674 return curr; 5675 }, this.analyser).connect(this.gainNode); 5676 } 5677 } 5678 /** Create ScriptProcessorNode to process audio */ 5679 5680 }, { 5681 key: "createScriptNode", 5682 value: function createScriptNode() { 5683 if (this.params.audioScriptProcessor) { 5684 this.scriptNode = this.params.audioScriptProcessor; 5685 } else { 5686 if (this.ac.createScriptProcessor) { 5687 this.scriptNode = this.ac.createScriptProcessor(WebAudio.scriptBufferSize); 5688 } else { 5689 this.scriptNode = this.ac.createJavaScriptNode(WebAudio.scriptBufferSize); 5690 } 5691 } 5692 5693 this.scriptNode.connect(this.ac.destination); 5694 } 5695 /** @private */ 5696 5697 }, { 5698 key: "addOnAudioProcess", 5699 value: function addOnAudioProcess() { 5700 var _this2 = this; 5701 5702 this.scriptNode.onaudioprocess = function () { 5703 var time = _this2.getCurrentTime(); 5704 5705 if (time >= _this2.getDuration()) { 5706 _this2.setState(FINISHED); 5707 5708 _this2.fireEvent('pause'); 5709 } else if (time >= _this2.scheduledPause) { 5710 _this2.pause(); 5711 } else if (_this2.state === _this2.states[PLAYING]) { 5712 _this2.fireEvent('audioprocess', time); 5713 } 5714 }; 5715 } 5716 /** @private */ 5717 5718 }, { 5719 key: "removeOnAudioProcess", 5720 value: function removeOnAudioProcess() { 5721 this.scriptNode.onaudioprocess = function () {}; 5722 } 5723 /** Create analyser node to perform audio analysis */ 5724 5725 }, { 5726 key: "createAnalyserNode", 5727 value: function createAnalyserNode() { 5728 this.analyser = this.ac.createAnalyser(); 5729 this.analyser.connect(this.gainNode); 5730 } 5731 /** 5732 * Create the gain node needed to control the playback volume. 5733 * 5734 */ 5735 5736 }, { 5737 key: "createVolumeNode", 5738 value: function createVolumeNode() { 5739 // Create gain node using the AudioContext 5740 if (this.ac.createGain) { 5741 this.gainNode = this.ac.createGain(); 5742 } else { 5743 this.gainNode = this.ac.createGainNode(); 5744 } // Add the gain node to the graph 5745 5746 5747 this.gainNode.connect(this.ac.destination); 5748 } 5749 /** 5750 * Set the sink id for the media player 5751 * 5752 * @param {string} deviceId String value representing audio device id. 5753 * @returns {Promise} A Promise that resolves to `undefined` when there 5754 * are no errors. 5755 */ 5756 5757 }, { 5758 key: "setSinkId", 5759 value: function setSinkId(deviceId) { 5760 if (deviceId) { 5761 /** 5762 * The webaudio API doesn't currently support setting the device 5763 * output. Here we create an HTMLAudioElement, connect the 5764 * webaudio stream to that element and setSinkId there. 5765 */ 5766 var audio = new window.Audio(); 5767 5768 if (!audio.setSinkId) { 5769 return Promise.reject(new Error('setSinkId is not supported in your browser')); 5770 } 5771 5772 audio.autoplay = true; 5773 var dest = this.ac.createMediaStreamDestination(); 5774 this.gainNode.disconnect(); 5775 this.gainNode.connect(dest); 5776 audio.srcObject = dest.stream; 5777 return audio.setSinkId(deviceId); 5778 } else { 5779 return Promise.reject(new Error('Invalid deviceId: ' + deviceId)); 5780 } 5781 } 5782 /** 5783 * Set the audio volume 5784 * 5785 * @param {number} value A floating point value between 0 and 1. 5786 */ 5787 5788 }, { 5789 key: "setVolume", 5790 value: function setVolume(value) { 5791 this.gainNode.gain.setValueAtTime(value, this.ac.currentTime); 5792 } 5793 /** 5794 * Get the current volume 5795 * 5796 * @return {number} value A floating point value between 0 and 1. 5797 */ 5798 5799 }, { 5800 key: "getVolume", 5801 value: function getVolume() { 5802 return this.gainNode.gain.value; 5803 } 5804 /** 5805 * Decode an array buffer and pass data to a callback 5806 * 5807 * @private 5808 * @param {ArrayBuffer} arraybuffer The array buffer to decode 5809 * @param {function} callback The function to call on complete. 5810 * @param {function} errback The function to call on error. 5811 */ 5812 5813 }, { 5814 key: "decodeArrayBuffer", 5815 value: function decodeArrayBuffer(arraybuffer, callback, errback) { 5816 if (!this.offlineAc) { 5817 this.offlineAc = this.getOfflineAudioContext(this.ac && this.ac.sampleRate ? this.ac.sampleRate : 44100); 5818 } 5819 5820 this.offlineAc.decodeAudioData(arraybuffer, function (data) { 5821 return callback(data); 5822 }, errback); 5823 } 5824 /** 5825 * Set pre-decoded peaks 5826 * 5827 * @param {number[]|Number.<Array[]>} peaks Peaks data 5828 * @param {?number} duration Explicit duration 5829 */ 5830 5831 }, { 5832 key: "setPeaks", 5833 value: function setPeaks(peaks, duration) { 5834 if (duration != null) { 5835 this.explicitDuration = duration; 5836 } 5837 5838 this.peaks = peaks; 5839 } 5840 /** 5841 * Set the rendered length (different from the length of the audio) 5842 * 5843 * @param {number} length The rendered length 5844 */ 5845 5846 }, { 5847 key: "setLength", 5848 value: function setLength(length) { 5849 // No resize, we can preserve the cached peaks. 5850 if (this.mergedPeaks && length == 2 * this.mergedPeaks.length - 1 + 2) { 5851 return; 5852 } 5853 5854 this.splitPeaks = []; 5855 this.mergedPeaks = []; // Set the last element of the sparse array so the peak arrays are 5856 // appropriately sized for other calculations. 5857 5858 var channels = this.buffer ? this.buffer.numberOfChannels : 1; 5859 var c; 5860 5861 for (c = 0; c < channels; c++) { 5862 this.splitPeaks[c] = []; 5863 this.splitPeaks[c][2 * (length - 1)] = 0; 5864 this.splitPeaks[c][2 * (length - 1) + 1] = 0; 5865 } 5866 5867 this.mergedPeaks[2 * (length - 1)] = 0; 5868 this.mergedPeaks[2 * (length - 1) + 1] = 0; 5869 } 5870 /** 5871 * Compute the max and min value of the waveform when broken into <length> subranges. 5872 * 5873 * @param {number} length How many subranges to break the waveform into. 5874 * @param {number} first First sample in the required range. 5875 * @param {number} last Last sample in the required range. 5876 * @return {number[]|Number.<Array[]>} Array of 2*<length> peaks or array of arrays of 5877 * peaks consisting of (max, min) values for each subrange. 5878 */ 5879 5880 }, { 5881 key: "getPeaks", 5882 value: function getPeaks(length, first, last) { 5883 if (this.peaks) { 5884 return this.peaks; 5885 } 5886 5887 if (!this.buffer) { 5888 return []; 5889 } 5890 5891 first = first || 0; 5892 last = last || length - 1; 5893 this.setLength(length); 5894 5895 if (!this.buffer) { 5896 return this.params.splitChannels ? this.splitPeaks : this.mergedPeaks; 5897 } 5898 /** 5899 * The following snippet fixes a buffering data issue on the Safari 5900 * browser which returned undefined It creates the missing buffer based 5901 * on 1 channel, 4096 samples and the sampleRate from the current 5902 * webaudio context 4096 samples seemed to be the best fit for rendering 5903 * will review this code once a stable version of Safari TP is out 5904 */ 5905 5906 5907 if (!this.buffer.length) { 5908 var newBuffer = this.createBuffer(1, 4096, this.sampleRate); 5909 this.buffer = newBuffer.buffer; 5910 } 5911 5912 var sampleSize = this.buffer.length / length; 5913 var sampleStep = ~~(sampleSize / 10) || 1; 5914 var channels = this.buffer.numberOfChannels; 5915 var c; 5916 5917 for (c = 0; c < channels; c++) { 5918 var peaks = this.splitPeaks[c]; 5919 var chan = this.buffer.getChannelData(c); 5920 var i = void 0; 5921 5922 for (i = first; i <= last; i++) { 5923 var start = ~~(i * sampleSize); 5924 var end = ~~(start + sampleSize); 5925 var min = 0; 5926 var max = 0; 5927 var j = void 0; 5928 5929 for (j = start; j < end; j += sampleStep) { 5930 var value = chan[j]; 5931 5932 if (value > max) { 5933 max = value; 5934 } 5935 5936 if (value < min) { 5937 min = value; 5938 } 5939 } 5940 5941 peaks[2 * i] = max; 5942 peaks[2 * i + 1] = min; 5943 5944 if (c == 0 || max > this.mergedPeaks[2 * i]) { 5945 this.mergedPeaks[2 * i] = max; 5946 } 5947 5948 if (c == 0 || min < this.mergedPeaks[2 * i + 1]) { 5949 this.mergedPeaks[2 * i + 1] = min; 5950 } 5951 } 5952 } 5953 5954 return this.params.splitChannels ? this.splitPeaks : this.mergedPeaks; 5955 } 5956 /** 5957 * Get the position from 0 to 1 5958 * 5959 * @return {number} Position 5960 */ 5961 5962 }, { 5963 key: "getPlayedPercents", 5964 value: function getPlayedPercents() { 5965 return this.state.getPlayedPercents.call(this); 5966 } 5967 /** @private */ 5968 5969 }, { 5970 key: "disconnectSource", 5971 value: function disconnectSource() { 5972 if (this.source) { 5973 this.source.disconnect(); 5974 } 5975 } 5976 /** 5977 * This is called when wavesurfer is destroyed 5978 */ 5979 5980 }, {
5981 key: "destroy", 5982 value: function destroy() { 5983 if (!this.isPaused()) { 5984 this.pause(); 5985 } 5986 5987 this.unAll(); 5988 this.buffer = null; 5989 this.destroyed = true; 5990 this.disconnectFilters(); 5991 this.disconnectSource(); 5992 this.gainNode.disconnect(); 5993 this.scriptNode.disconnect(); 5994 this.analyser.disconnect(); // close the audioContext if closeAudioContext option is set to true 5995 5996 if (this.params.closeAudioContext) { 5997 // check if browser supports AudioContext.close() 5998 if (typeof this.ac.close === 'function' && this.ac.state != 'closed') { 5999 this.ac.close(); 6000 } // clear the reference to the audiocontext 6001 6002 6003 this.ac = null; // clear the actual audiocontext, either passed as param or the 6004 // global singleton 6005 6006 if (!this.params.audioContext) { 6007 window.WaveSurferAudioContext = null; 6008 } else { 6009 this.params.audioContext = null; 6010 } // clear the offlineAudioContext 6011 6012 6013 window.WaveSurferOfflineAudioContext = null; 6014 } 6015 } 6016 /** 6017 * Loaded a decoded audio buffer 6018 * 6019 * @param {Object} buffer Decoded audio buffer to load 6020 */ 6021 6022 }, { 6023 key: "load", 6024 value: function load(buffer) { 6025 this.startPosition = 0; 6026 this.lastPlay = this.ac.currentTime; 6027 this.buffer = buffer; 6028 this.createSource(); 6029 } 6030 /** @private */ 6031 6032 }, { 6033 key: "createSource", 6034 value: function createSource() { 6035 this.disconnectSource(); 6036 this.source = this.ac.createBufferSource(); // adjust for old browsers 6037 6038 this.source.start = this.source.start || this.source.noteGrainOn; 6039 this.source.stop = this.source.stop || this.source.noteOff; 6040 this.source.playbackRate.setValueAtTime(this.playbackRate, this.ac.currentTime); 6041 this.source.buffer = this.buffer; 6042 this.source.connect(this.analyser); 6043 } 6044 /** 6045 * Used by `wavesurfer.isPlaying()` and `wavesurfer.playPause()` 6046 * 6047 * @return {boolean} Whether or not this backend is currently paused 6048 */ 6049 6050 }, { 6051 key: "isPaused", 6052 value: function isPaused() { 6053 return this.state !== this.states[PLAYING]; 6054 } 6055 /** 6056 * Used by `wavesurfer.getDuration()` 6057 * 6058 * @return {number} Duration of loaded buffer 6059 */ 6060 6061 }, { 6062 key: "getDuration", 6063 value: function getDuration() { 6064 if (this.explicitDuration) { 6065 return this.explicitDuration; 6066 } 6067 6068 if (!this.buffer) { 6069 return 0; 6070 } 6071 6072 return this.buffer.duration; 6073 } 6074 /** 6075 * Used by `wavesurfer.seekTo()` 6076 * 6077 * @param {number} start Position to start at in seconds 6078 * @param {number} end Position to end at in seconds 6079 * @return {{start: number, end: number}} Object containing start and end 6080 * positions 6081 */ 6082 6083 }, { 6084 key: "seekTo", 6085 value: function seekTo(start, end) { 6086 if (!this.buffer) { 6087 return; 6088 } 6089 6090 this.scheduledPause = null; 6091 6092 if (start == null) { 6093 start = this.getCurrentTime(); 6094 6095 if (start >= this.getDuration()) { 6096 start = 0; 6097 } 6098 } 6099 6100 if (end == null) { 6101 end = this.getDuration(); 6102 } 6103 6104 this.startPosition = start; 6105 this.lastPlay = this.ac.currentTime; 6106 6107 if (this.state === this.states[FINISHED]) { 6108 this.setState(PAUSED); 6109 } 6110 6111 return { 6112 start: start, 6113 end: end 6114 }; 6115 } 6116 /** 6117 * Get the playback position in seconds 6118 * 6119 * @return {number} The playback position in seconds 6120 */ 6121 6122 }, { 6123 key: "getPlayedTime", 6124 value: function getPlayedTime() { 6125 return (this.ac.currentTime - this.lastPlay) * this.playbackRate; 6126 } 6127 /** 6128 * Plays the loaded audio region. 6129 * 6130 * @param {number} start Start offset in seconds, relative to the beginning 6131 * of a clip. 6132 * @param {number} end When to stop relative to the beginning of a clip. 6133 */ 6134 6135 }, { 6136 key: "play", 6137 value: function play(start, end) { 6138 if (!this.buffer) { 6139 return; 6140 } // need to re-create source on each playback 6141 6142 6143 this.createSource(); 6144 var adjustedTime = this.seekTo(start, end); 6145 start = adjustedTime.start; 6146 end = adjustedTime.end; 6147 this.scheduledPause = end; 6148 this.source.start(0, start); 6149 6150 if (this.ac.state == 'suspended') { 6151 this.ac.resume && this.ac.resume(); 6152 } 6153 6154 this.setState(PLAYING); 6155 this.fireEvent('play'); 6156 } 6157 /** 6158 * Pauses the loaded audio. 6159 */ 6160 6161 }, { 6162 key: "pause", 6163 value: function pause() { 6164 this.scheduledPause = null; 6165 this.startPosition += this.getPlayedTime(); 6166 this.source && this.source.stop(0); 6167 this.setState(PAUSED); 6168 this.fireEvent('pause'); 6169 } 6170 /** 6171 * Returns the current time in seconds relative to the audio-clip's 6172 * duration. 6173 * 6174 * @return {number} The current time in seconds 6175 */ 6176 6177 }, { 6178 key: "getCurrentTime", 6179 value: function getCurrentTime() { 6180 return this.state.getCurrentTime.call(this); 6181 } 6182 /** 6183 * Returns the current playback rate. (0=no playback, 1=normal playback) 6184 * 6185 * @return {number} The current playback rate 6186 */ 6187 6188 }, { 6189 key: "getPlaybackRate", 6190 value: function getPlaybackRate() { 6191 return this.playbackRate; 6192 } 6193 /** 6194 * Set the audio source playback rate. 6195 * 6196 * @param {number} value The playback rate to use 6197 */ 6198 6199 }, { 6200 key: "setPlaybackRate", 6201 value: function setPlaybackRate(value) { 6202 value = value || 1; 6203 6204 if (this.isPaused()) { 6205 this.playbackRate = value; 6206 } else { 6207 this.pause(); 6208 this.playbackRate = value; 6209 this.play(); 6210 } 6211 } 6212 /** 6213 * Set a point in seconds for playback to stop at. 6214 * 6215 * @param {number} end Position to end at 6216 * @version 3.3.0 6217 */ 6218 6219 }, { 6220 key: "setPlayEnd", 6221 value: function setPlayEnd(end) { 6222 this.scheduledPause = end; 6223 } 6224 }]); 6225 6226 return WebAudio; 6227}(util.Observer); 6228 6229exports.default = WebAudio; 6230WebAudio.scriptBufferSize = 256; 6231module.exports = exports.default; 6232 6233/***/ })
6233 6234 6235/******/ }); 6236}); 6237//# sourceMappingURL=wavesurfer.js.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.