UNPKG

waveform-playlist-nartj

Version:

Multiple track web audio editor and player with waveform preview

1,402 lines (1,187 loc) 41.9 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator")); var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _lodash = _interopRequireDefault(require("lodash.defaults")); var _h = _interopRequireDefault(require("virtual-dom/h")); var _diff = _interopRequireDefault(require("virtual-dom/diff")); var _patch = _interopRequireDefault(require("virtual-dom/patch")); var _inlineWorker = _interopRequireDefault(require("inline-worker")); var _fileSaver = _interopRequireDefault(require("file-saver")); var _conversions = require("./utils/conversions"); var _LoaderFactory = _interopRequireDefault(require("./track/loader/LoaderFactory")); var _ScrollHook = _interopRequireDefault(require("./render/ScrollHook")); var _TimeScale = _interopRequireDefault(require("./TimeScale")); var _Track = _interopRequireDefault(require("./Track")); var _Playout = _interopRequireDefault(require("./Playout")); var _AnnotationList = _interopRequireDefault(require("./annotation/AnnotationList")); var _exportoggWorker = _interopRequireDefault(require("worker-loader!./utils/exportogg.worker.js")); var _exportWavWorker = _interopRequireDefault(require("./utils/exportWavWorker")); var _Undoer = _interopRequireDefault(require("./Undoer")); var _default = /*#__PURE__*/function () { function _default() { (0, _classCallCheck2["default"])(this, _default); this.tracks = []; this.soloedTracks = []; this.mutedTracks = []; this.playoutPromises = []; this.cursor = 0; this.playbackSeconds = 0; this.duration = 0; this.scrollLeft = 0; this.scrollTimer = undefined; this.showTimescale = false; // whether a user is scrolling the waveform this.isScrolling = false; this.fadeType = 'logarithmic'; this.masterGain = 1; this.annotations = []; this.durationFormat = 'hh:mm:ss.uuu'; this.isAutomaticScroll = false; this.resetDrawTimer = undefined; this.undoer = new _Undoer["default"](); } // TODO extract into a plugin (0, _createClass2["default"])(_default, [{ key: "initExporter", value: function initExporter() { this.wavExportWorker = new _inlineWorker["default"](_exportWavWorker["default"]); this.oggExportWorker = new _exportoggWorker["default"](); } // TODO extract into a plugin }, { key: "initRecorder", value: function initRecorder(stream) { var _this = this; this.mediaRecorder = new window.MediaRecorder(stream); this.mediaRecorder.onstart = function () { var track = new _Track["default"](); track.setName('Recording'); track.setEnabledStates(); track.setEventEmitter(_this.ee); _this.recordingTrack = track; _this.tracks.push(track); _this.chunks = []; _this.working = false; }; this.mediaRecorder.ondataavailable = function (e) { _this.chunks.push(e.data); // throttle peaks calculation if (!_this.working) { var recording = new Blob(_this.chunks, { type: 'audio/ogg; codecs=opus' }); var loader = _LoaderFactory["default"].createLoader(recording, _this.ac); loader.load().then(function (audioBuffer) { // ask web worker for peaks. _this.recorderWorker.postMessage({ samples: audioBuffer.getChannelData(0), samplesPerPixel: _this.samplesPerPixel }); _this.recordingTrack.setCues(0, audioBuffer.duration); _this.recordingTrack.setBuffer(audioBuffer); _this.recordingTrack.setPlayout(new _Playout["default"](_this.ac, audioBuffer)); _this.adjustDuration(); })["catch"](function () { _this.working = false; }); _this.working = true; } }; this.mediaRecorder.onstop = function () { _this.chunks = []; _this.working = false; }; this.recorderWorker = new _inlineWorker["default"](RecorderWorkerFunction); // use a worker for calculating recording peaks. this.recorderWorker.onmessage = function (e) { _this.recordingTrack.setPeaks(e.data); _this.working = false; _this.drawRequest(); }; } }, { key: "setShowTimeScale", value: function setShowTimeScale(show) { this.showTimescale = show; } }, { key: "setMono", value: function setMono(mono) { this.mono = mono; } }, { key: "setExclSolo", value: function setExclSolo(exclSolo) { this.exclSolo = exclSolo; } }, { key: "setSeekStyle", value: function setSeekStyle(style) { this.seekStyle = style; } }, { key: "getSeekStyle", value: function getSeekStyle() { return this.seekStyle; } }, { key: "setSampleRate", value: function setSampleRate(sampleRate) { this.sampleRate = sampleRate; } }, { key: "setSamplesPerPixel", value: function setSamplesPerPixel(samplesPerPixel) { this.samplesPerPixel = samplesPerPixel; } }, { key: "setAudioContext", value: function setAudioContext(ac) { this.ac = ac; } }, { key: "setControlOptions", value: function setControlOptions(controlOptions) { this.controls = controlOptions; } }, { key: "setWaveHeight", value: function setWaveHeight(height) { this.waveHeight = height; } }, { key: "setColors", value: function setColors(colors) { this.colors = colors; } }, { key: "setAnnotations", value: function setAnnotations(config) { this.annotationList = new _AnnotationList["default"](this, config.annotations, config.controls, config.editable, config.linkEndpoints, config.isContinuousPlay); } }, { key: "setEventEmitter", value: function setEventEmitter(ee) { this.ee = ee; } }, { key: "getEventEmitter", value: function getEventEmitter() { return this.ee; } }, { key: "setUpEventEmitter", value: function setUpEventEmitter() { var _this2 = this; var ee = this.ee; function arrayMove(arr, fromIndex, toIndex) { var element = arr[fromIndex]; arr.splice(fromIndex, 1); arr.splice(toIndex, 0, element); } ee.on('moveUp', function (track) { var idx = _this2.tracks.indexOf(track); if (idx > 0) { arrayMove(_this2.tracks, idx, idx - 1); _this2.drawRequest(); } }); ee.on('moveDown', function (track) { var idx = _this2.tracks.indexOf(track); if (idx < _this2.tracks.length - 1) { arrayMove(_this2.tracks, idx, idx + 1); _this2.drawRequest(); } }); ee.on('undo', function (val) { _this2.undoer.pop(); console.log('undo'); }); ee.on('redo', function (val) { console.log('redo'); // todo }); ee.on('load', function (val) { _this2.undoer.clear(); console.log('load'); // todo }); ee.on('save', /*#__PURE__*/function () { var _ref = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee(val) { var blob; return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: console.log('save'); blob = new Blob([JSON.stringify(_this2.tracks, null)], { type: "text/plain;charset=utf-8" }); _fileSaver["default"].saveAs(blob, "playlist.json"); // todo case 3: case "end": return _context.stop(); } } }, _callee); })); return function (_x) { return _ref.apply(this, arguments); }; }()); ee.on('draw', function (val) { _this2.drawRequest(); }); ee.on('duplicate', /*#__PURE__*/function () { var _ref2 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2(track) { var self, dupTrack, undo; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: self = _this2; // todo it does not duplicate ease in and out, should it do it? _context2.next = 3; return track.duplicateTrack(track, track.startTime, track.cueIn, track.cueOut, 1); case 3: dupTrack = _context2.sent; undo = function undo() { self.removeTrack(dupTrack); }; _this2.undoer.push(undo); case 6: case "end": return _context2.stop(); } } }, _callee2); })); return function (_x2) { return _ref2.apply(this, arguments); }; }()); ee.on('delete', /*#__PURE__*/function () { var _ref3 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee3(track) { var self, undo; return _regenerator["default"].wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: self = _this2; _this2.removeTrack(track); undo = function undo() {//const dupTrack = await track.duplicateTrack(track, track.startTime, track.cueIn, track.cueOut, 1); // todo }; _this2.undoer.push(undo); // todo we should also receive the duration of the audio, the audio duration might be shorter we removed the track _this2.drawRequest(); case 5: case "end": return _context3.stop(); } } }, _callee3); })); return function (_x3) { return _ref3.apply(this, arguments); }; }()); ee.on('add', /*#__PURE__*/function () { var _ref4 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee4(file) { var track, self, undo; return _regenerator["default"].wrap(function _callee4$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: _context4.next = 2; return _this2.load([{ src: file, name: file.name }]); case 2: track = _context4.sent[0]; self = _this2; undo = function undo() { self.removeTrack(track); self.drawRequest(); }; _this2.undoer.push(undo); case 6: case "end": return _context4.stop(); } } }, _callee4); })); return function (_x4) { return _ref4.apply(this, arguments); }; }()); ee.on('automaticscroll', function (val) { _this2.isAutomaticScroll = val; }); ee.on('durationformat', function (format) { _this2.durationFormat = format; _this2.drawRequest(); }); ee.on('select', function (start, end, track) { if (_this2.isPlaying()) { _this2.lastSeeked = start; _this2.pausedAt = undefined; _this2.restartPlayFrom(start); } else { // reset if it was paused. _this2.seek(start, end, track); _this2.ee.emit('timeupdate', start); _this2.drawRequest(); } }); ee.on('startaudiorendering', function (type) { _this2.startOfflineRender(type); }); ee.on('statechange', function (state) { _this2.setState(state); _this2.drawRequest(); }); ee.on('shift', function (deltaTime, track) { track.setStartTime(track.getStartTime() + deltaTime); _this2.adjustDuration(); _this2.drawRequest(); }); ee.on('shiftbegin', function (deltaTime, track) {}); ee.on('shiftend', function (deltaTime, track, undo) { var startTime = track.getStartTime(); _this2.undoer.push(function () { undo(); track.setStartTime(startTime - deltaTime); _this2.adjustDuration(); _this2.drawRequest(); }); }); ee.on('record', function () { _this2.record(); }); ee.on('play', function (start, end) { _this2.play(start, end); }); ee.on('pause', function () { _this2.pause(); }); ee.on('stop', function () { _this2.stop(); }); ee.on('rewind', function () { _this2.rewind(); }); ee.on('fastforward', function () { _this2.fastForward(); }); ee.on('clear', function () { _this2.clear().then(function () { _this2.drawRequest(); }); }); ee.on('solo', function (track) { _this2.soloTrack(track); _this2.adjustTrackPlayout(); _this2.drawRequest(); }); ee.on('mute', function (track) { _this2.muteTrack(track); _this2.adjustTrackPlayout(); _this2.drawRequest(); }); ee.on('volumechange', function (volume, track) { track.setGainLevel(volume / 100); }); ee.on('mastervolumechange', function (volume) { _this2.masterGain = volume / 100; _this2.tracks.forEach(function (track) { track.setMasterGainLevel(_this2.masterGain); }); }); ee.on('fadein', function (duration, track) { var fadeEnd = 0; if (track.fades && track.fadeIn && track.fades[track.fadeIn]) { fadeEnd = track.fades[track.fadeIn].end; } var fadeType = _this2.fadeType; var undo = function undo() { track.setFadeIn(fadeEnd, fadeType); _this2.drawRequest(); }; _this2.undoer.push(undo); track.setFadeIn(duration, _this2.fadeType); _this2.drawRequest(); }); ee.on('fadeout', function (duration, track) { var fadeBegin = 0; if (track.fades && track.fadeIn && track.fades[track.fadeIn]) { fadeBegin = track.fades[track.fadeIn].end; } var fadeType = _this2.fadeType; var undo = function undo() { track.setFadeOut(fadeBegin, fadeType); _this2.drawRequest(); }; _this2.undoer.push(undo); track.setFadeOut(duration, _this2.fadeType); _this2.drawRequest(); }); ee.on('stereopan', function (panvalue, track) { track.setStereoPanValue(panvalue); }); ee.on('fadetype', function (type) { _this2.fadeType = type; }); ee.on('duplicateTrack', function (track, start, cueIn, cueOut, trackOffset) { track.duplicateTrack(track, start, cueIn, cueOut, trackOffset); }); ee.on('trim', /*#__PURE__*/(0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee5() { var track, timeSelection, undo; return _regenerator["default"].wrap(function _callee5$(_context5) { while (1) { switch (_context5.prev = _context5.next) { case 0: track = _this2.getActiveTrack(); timeSelection = _this2.getTimeSelection(); _context5.next = 4; return track.trim(timeSelection.start, timeSelection.end); case 4: undo = _context5.sent; track.calculatePeaks(_this2.samplesPerPixel, _this2.sampleRate); _this2.setTimeSelection(0, 0); _this2.drawRequest(); _this2.undoer.push(undo); case 9: case "end": return _context5.stop(); } } }, _callee5); }))); ee.on('zoomin', function () { var zoomIndex = Math.max(0, _this2.zoomIndex - 1); var zoom = _this2.zoomLevels[zoomIndex]; if (zoom !== _this2.samplesPerPixel) { _this2.setZoom(zoom); _this2.drawRequest(); } }); ee.on('zoomout', function () { var zoomIndex = Math.min(_this2.zoomLevels.length - 1, _this2.zoomIndex + 1); var zoom = _this2.zoomLevels[zoomIndex]; if (zoom !== _this2.samplesPerPixel) { _this2.setZoom(zoom); _this2.drawRequest(); } }); ee.on('scroll', function () { _this2.isScrolling = true; _this2.drawRequest(); clearTimeout(_this2.scrollTimer); _this2.scrollTimer = setTimeout(function () { _this2.isScrolling = false; }, 200); }); } }, { key: "removeTrack", value: function removeTrack(track) { this.tracks = this.tracks.filter(function (t) { return t !== track; }); } }, { key: "load", value: function load(trackList) { var _this3 = this; var loadPromises = trackList.map(function (trackInfo) { var loader = _LoaderFactory["default"].createLoader(trackInfo.src, _this3.ac, _this3.ee); return loader.load(); }); var newTrack; var trackOffset; var isTrackDuplication = false; return Promise.all(loadPromises).then(function (audioBuffers) { _this3.ee.emit('audiosourcesloaded'); var tracks = audioBuffers.map(function (audioBuffer, index) { var info = trackList[index]; var trck = info.track || undefined; isTrackDuplication = trck !== undefined; var name = info.name || 'Untitled'; var start = info.start || 0; var states = info.states || {}; var fadeIn = info.fadeIn; var fadeOut = info.fadeOut; var cueIn = info.cueIn || 0; var cueOut = info.cueOut || audioBuffer.duration; var gain = info.gain || 1; var muted = info.muted || false; var soloed = info.soloed || false; var selection = info.selected; var peaks = info.peaks || { type: 'WebAudio', mono: _this3.mono }; var customClass = info.customClass || undefined; var waveOutlineColor = info.waveOutlineColor || undefined; var stereoPan = info.stereoPan || 0; var duplicationNumber = info.duplicationNumber || 0; trackOffset = info.trackOffset || 0; // webaudio specific playout for now. var playout = new _Playout["default"](_this3.ac, audioBuffer); var track = new _Track["default"](); track.setSrc(info.src); track.setBuffer(audioBuffer); track.setSrcTrack(trck); track.setDuplicationNumber(trck === undefined ? duplicationNumber : trck.srcTrack === undefined ? trck.duplicationNumber + 1 : trck.srcTrack.duplicationNumber + 1); track.setName(name); track.setEventEmitter(_this3.ee); track.setEnabledStates(states); track.setCues(cueIn, cueOut); track.setCustomClass(customClass); track.setWaveOutlineColor(waveOutlineColor); if (fadeIn !== undefined) { track.setFadeIn(fadeIn.duration, fadeIn.shape); } if (fadeOut !== undefined) { track.setFadeOut(fadeOut.duration, fadeOut.shape); } if (selection !== undefined) { _this3.setActiveTrack(track); _this3.setTimeSelection(selection.start, selection.end); } if (peaks !== undefined) { track.setPeakData(peaks); } track.setState(_this3.getState()); track.setStartTime(start); track.setPlayout(playout); track.setGainLevel(gain); track.setStereoPanValue(stereoPan); if (muted) { _this3.muteTrack(track); } if (soloed) { _this3.soloTrack(track); } // extract peaks with AudioContext for now. track.calculatePeaks(_this3.samplesPerPixel, _this3.sampleRate); newTrack = track; return track; }); if (tracks.length > 1) { _this3.tracks = _this3.tracks.concat(tracks); } else if (isTrackDuplication) { _this3.tracks.splice(_this3.tracks.indexOf(_this3.getActiveTrack()) + _this3.getActiveTrack().duplicationNumber - newTrack.duplicationNumber + trackOffset, 0, newTrack); } else { _this3.tracks.push(tracks[0]); } _this3.adjustDuration(); _this3.draw(_this3.render()); _this3.ee.emit('audiosourcesrendered'); return tracks; })["catch"](function (e) { _this3.ee.emit('audiosourceserror', e); return []; }); } }, { key: "virtualLoad", value: function virtualLoad(trackList) { var _this4 = this; var loadPromises = trackList.map(function (trackInfo) { var loader = _LoaderFactory["default"].createLoader(trackInfo.src, _this4.ac, _this4.ee); return loader.load(); }); var newTrack = undefined; var trackOffset = undefined; var isTrackDuplication = false; return Promise.all(loadPromises).then(function (audioBuffers) { _this4.ee.emit('audiosourcesloaded'); var tracks = audioBuffers.map(function (audioBuffer, index) { var info = trackList[index]; var trck = info.track || undefined; isTrackDuplication = trck !== undefined; var name = info.name || 'Untitled'; var start = info.start || 0; var states = info.states || {}; var fadeIn = info.fadeIn; var fadeOut = info.fadeOut; var cueIn = info.cueIn || 0; var cueOut = info.cueOut || audioBuffer.duration; var gain = info.gain || 1; var muted = info.muted || false; var soloed = info.soloed || false; var selection = info.selected; var peaks = info.peaks || { type: 'WebAudio', mono: _this4.mono }; var customClass = info.customClass || undefined; var waveOutlineColor = info.waveOutlineColor || undefined; var stereoPan = info.stereoPan || 0; var duplicationNumber = info.duplicationNumber || 0; trackOffset = info.trackOffset || 0; // webaudio specific playout for now. var playout = new _Playout["default"](_this4.ac, audioBuffer); var track = new _Track["default"](); track.setSrc(info.src); track.setBuffer(audioBuffer); track.setSrcTrack(trck); track.setDuplicationNumber(trck === undefined ? duplicationNumber : trck.srcTrack === undefined ? trck.duplicationNumber + 1 : trck.srcTrack.duplicationNumber + 1); track.setName(name); track.setEventEmitter(_this4.ee); track.setEnabledStates(states); track.setCues(cueIn, cueOut); track.setCustomClass(customClass); track.setWaveOutlineColor(waveOutlineColor); if (fadeIn !== undefined) { track.setFadeIn(fadeIn.duration, fadeIn.shape); } if (fadeOut !== undefined) { track.setFadeOut(fadeOut.duration, fadeOut.shape); } if (selection !== undefined) { _this4.setActiveTrack(track); _this4.setTimeSelection(selection.start, selection.end); } if (peaks !== undefined) { track.setPeakData(peaks); } track.setState(_this4.getState()); track.setStartTime(start); track.setPlayout(playout); track.setGainLevel(gain); track.setStereoPanValue(stereoPan); if (muted) { _this4.muteTrack(track); } if (soloed) { _this4.soloTrack(track); } // extract peaks with AudioContext for now. track.calculatePeaks(_this4.samplesPerPixel, _this4.sampleRate); newTrack = track; return track; }); if (tracks.length > 1) { _this4.tracks = _this4.tracks.concat(tracks); } else if (isTrackDuplication) { _this4.tracks.splice(_this4.tracks.indexOf(_this4.getActiveTrack()) + _this4.getActiveTrack().duplicationNumber - newTrack.duplicationNumber + trackOffset, 0, newTrack); } _this4.adjustDuration(); _this4.draw(_this4.render()); _this4.ee.emit('audiosourcesrendered'); })["catch"](function (e) { _this4.ee.emit('audiosourceserror', e); }); } /* track instance of Track. */ }, { key: "setActiveTrack", value: function setActiveTrack(track) { this.activeTrack = track; } }, { key: "getActiveTrack", value: function getActiveTrack() { return this.activeTrack; } }, { key: "isSegmentSelection", value: function isSegmentSelection() { return this.timeSelection.start !== this.timeSelection.end; } /* start, end in seconds. */ }, { key: "setTimeSelection", value: function setTimeSelection() { var start = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0; var end = arguments.length > 1 ? arguments[1] : undefined; this.timeSelection = { start: start, end: end === undefined ? start : end }; this.cursor = start; } }, { key: "startOfflineRender", value: function startOfflineRender(type) { var _this5 = this; if (this.isRendering) { return; } this.isRendering = true; this.offlineAudioContext = new OfflineAudioContext(2, 44100 * this.duration, 44100); var currentTime = this.offlineAudioContext.currentTime; this.tracks.forEach(function (track) { track.setOfflinePlayout(new _Playout["default"](_this5.offlineAudioContext, track.buffer)); track.schedulePlay(currentTime, 0, 0, { shouldPlay: _this5.shouldTrackPlay(track), masterGain: 1, isOffline: true }); }); /* TODO cleanup of different audio playouts handling. */ this.offlineAudioContext.startRendering().then(function (audioBuffer) { if (type === 'buffer') { _this5.ee.emit('audiorenderingfinished', type, audioBuffer); _this5.isRendering = false; } else if (type === 'ogg') { // callback for `encodeOGG` _this5.oggExportWorker.onmessage = function (e) { _this5.ee.emit('audiorenderingfinished', type, e.data); _this5.isRendering = false; }; // ask the worker for a OGG _this5.oggExportWorker.postMessage({ command: 'encodeOGG', buffer: [// todo check if mono or stereo audioBuffer.getChannelData(0), audioBuffer.getChannelData(1)], sampleRate: audioBuffer.sampleRate, numberOfChannels: audioBuffer.numberOfChannels, quality: 0.5, tags: {} }); } else if (type === 'wav') { _this5.wavExportWorker.postMessage({ command: 'init', config: { sampleRate: 44100 } }); // callback for `exportWAV` _this5.wavExportWorker.onmessage = function (e) { _this5.ee.emit('audiorenderingfinished', type, e.data); _this5.isRendering = false; // clear out the buffer for next renderings. _this5.wavExportWorker.postMessage({ command: 'clear' }); }; // send the channel data from our buffer to the worker _this5.wavExportWorker.postMessage({ command: 'record', buffer: [audioBuffer.getChannelData(0), audioBuffer.getChannelData(1)] }); // ask the worker for a WAV _this5.wavExportWorker.postMessage({ command: 'exportWAV', type: 'audio/wav' }); } })["catch"](function (e) { throw e; }); } }, { key: "getTimeSelection", value: function getTimeSelection() { return this.timeSelection; } }, { key: "setState", value: function setState(state) { this.state = state; this.tracks.forEach(function (track) { track.setState(state); }); } }, { key: "getState", value: function getState() { return this.state; } }, { key: "setZoomIndex", value: function setZoomIndex(index) { this.zoomIndex = index; } }, { key: "setZoomLevels", value: function setZoomLevels(levels) { this.zoomLevels = levels; } }, { key: "setZoom", value: function setZoom(zoom) { var _this6 = this; this.samplesPerPixel = zoom; this.zoomIndex = this.zoomLevels.indexOf(zoom); this.tracks.forEach(function (track) { track.calculatePeaks(zoom, _this6.sampleRate); }); } }, { key: "muteTrack", value: function muteTrack(track) { var index = this.mutedTracks.indexOf(track); if (index > -1) { this.mutedTracks.splice(index, 1); } else { this.mutedTracks.push(track); } } }, { key: "soloTrack", value: function soloTrack(track) { var index = this.soloedTracks.indexOf(track); if (index > -1) { this.soloedTracks.splice(index, 1); } else if (this.exclSolo) { this.soloedTracks = [track]; } else { this.soloedTracks.push(track); } } }, { key: "adjustTrackPlayout", value: function adjustTrackPlayout() { var _this7 = this; this.tracks.forEach(function (track) { track.setShouldPlay(_this7.shouldTrackPlay(track)); }); } }, { key: "adjustDuration", value: function adjustDuration() { this.duration = this.tracks.reduce(function (duration, track) { return Math.max(duration, track.getEndTime()); }, 0); } }, { key: "shouldTrackPlay", value: function shouldTrackPlay(track) { var shouldPlay; // if there are solo tracks, only they should play. if (this.soloedTracks.length > 0) { shouldPlay = false; if (this.soloedTracks.indexOf(track) > -1) { shouldPlay = true; } } else { // play all tracks except any muted tracks. shouldPlay = true; if (this.mutedTracks.indexOf(track) > -1) { shouldPlay = false; } } return shouldPlay; } }, { key: "isPlaying", value: function isPlaying() { return this.tracks.reduce(function (isPlaying, track) { return isPlaying || track.isPlaying(); }, false); } /* * returns the current point of time in the playlist in seconds. */ }, { key: "getCurrentTime", value: function getCurrentTime() { var cursorPos = this.lastSeeked || this.pausedAt || this.cursor; return cursorPos + this.getElapsedTime(); } }, { key: "getElapsedTime", value: function getElapsedTime() { return this.ac.currentTime - this.lastPlay; } }, { key: "setMasterGain", value: function setMasterGain(gain) { this.ee.emit('mastervolumechange', gain); } }, { key: "restartPlayFrom", value: function restartPlayFrom(start, end) { this.stopAnimation(); this.tracks.forEach(function (editor) { editor.scheduleStop(); }); return Promise.all(this.playoutPromises).then(this.play.bind(this, start, end)); } }, { key: "play", value: function play(startTime, endTime) { var _this8 = this; clearTimeout(this.resetDrawTimer); var currentTime = this.ac.currentTime; var selected = this.getTimeSelection(); var playoutPromises = []; var start = startTime || this.pausedAt || this.cursor; var end = endTime; if (!end && selected.end !== selected.start && selected.end > start) { end = selected.end; } if (this.isPlaying()) { return this.restartPlayFrom(start, end); } this.tracks.forEach(function (track) { track.setState('cursor'); playoutPromises.push(track.schedulePlay(currentTime, start, end, { shouldPlay: _this8.shouldTrackPlay(track), masterGain: _this8.masterGain })); }); this.lastPlay = currentTime; // use these to track when the playlist has fully stopped. this.playoutPromises = playoutPromises; this.startAnimation(start); return Promise.all(this.playoutPromises); } }, { key: "pause", value: function pause() { if (!this.isPlaying()) { return Promise.all(this.playoutPromises); } this.pausedAt = this.getCurrentTime(); return this.playbackReset(); } }, { key: "stop", value: function stop() { if (this.mediaRecorder && this.mediaRecorder.state === 'recording') { this.mediaRecorder.stop(); } this.pausedAt = undefined; this.playbackSeconds = 0; return this.playbackReset(); } }, { key: "playbackReset", value: function playbackReset() { var _this9 = this; this.lastSeeked = undefined; this.stopAnimation(); this.tracks.forEach(function (track) { track.scheduleStop(); track.setState(_this9.getState()); }); this.drawRequest(); return Promise.all(this.playoutPromises); } }, { key: "rewind", value: function rewind() { var _this10 = this; return this.stop().then(function () { _this10.scrollLeft = 0; _this10.ee.emit('select', 0, 0); }); } }, { key: "fastForward", value: function fastForward() { var _this11 = this; return this.stop().then(function () { if (_this11.viewDuration < _this11.duration) { _this11.scrollLeft = _this11.duration - _this11.viewDuration; } else { _this11.scrollLeft = 0; } _this11.ee.emit('select', _this11.duration, _this11.duration); }); } }, { key: "clear", value: function clear() { var _this12 = this; return this.stop().then(function () { _this12.tracks = []; _this12.soloedTracks = []; _this12.mutedTracks = []; _this12.playoutPromises = []; _this12.cursor = 0; _this12.playbackSeconds = 0; _this12.duration = 0; _this12.scrollLeft = 0; _this12.seek(0, 0, undefined); }); } }, { key: "record", value: function record() { var _this13 = this; var playoutPromises = []; this.mediaRecorder.start(300); this.tracks.forEach(function (track) { track.setState('none'); playoutPromises.push(track.schedulePlay(_this13.ac.currentTime, 0, undefined, { shouldPlay: _this13.shouldTrackPlay(track) })); }); this.playoutPromises = playoutPromises; } }, { key: "startAnimation", value: function startAnimation(startTime) { var _this14 = this; this.lastDraw = this.ac.currentTime; this.animationRequest = window.requestAnimationFrame(function () { _this14.updateEditor(startTime); }); } }, { key: "stopAnimation", value: function stopAnimation() { window.cancelAnimationFrame(this.animationRequest); this.lastDraw = undefined; } }, { key: "seek", value: function seek(start, end, track) { if (this.isPlaying()) { this.lastSeeked = start; this.pausedAt = undefined; this.restartPlayFrom(start); } else { // reset if it was paused. this.setActiveTrack(track || this.tracks[0]); this.pausedAt = start; this.setTimeSelection(start, end); if (this.getSeekStyle() === 'fill') { this.playbackSeconds = start; } } } /* * Animation function for the playlist. * Keep under 16.7 milliseconds based on a typical screen refresh rate of 60fps. */ }, { key: "updateEditor", value: function updateEditor(cursor) { var _this15 = this; var currentTime = this.ac.currentTime; var selection = this.getTimeSelection(); var cursorPos = cursor || this.cursor; var elapsed = currentTime - this.lastDraw; if (this.isPlaying()) { var playbackSeconds = cursorPos + elapsed; this.ee.emit('timeupdate', playbackSeconds); this.animationRequest = window.requestAnimationFrame(function () { _this15.updateEditor(playbackSeconds); }); this.playbackSeconds = playbackSeconds; this.draw(this.render()); this.lastDraw = currentTime; } else { if (cursorPos + elapsed >= (this.isSegmentSelection() ? selection.end : this.duration)) { this.ee.emit('finished'); } this.stopAnimation(); this.resetDrawTimer = setTimeout(function () { _this15.pausedAt = undefined; _this15.lastSeeked = undefined; _this15.setState(_this15.getState()); _this15.playbackSeconds = 0; _this15.draw(_this15.render()); }, 0); } } }, { key: "drawRequest", value: function drawRequest() { var _this16 = this; window.requestAnimationFrame(function () { _this16.draw(_this16.render()); }); } }, { key: "draw", value: function draw(newTree) { var patches = (0, _diff["default"])(this.tree, newTree); this.rootNode = (0, _patch["default"])(this.rootNode, patches); this.tree = newTree; // use for fast forwarding. this.viewDuration = (0, _conversions.pixelsToSeconds)(this.rootNode.clientWidth - this.controls.width, this.samplesPerPixel, this.sampleRate); } }, { key: "getTrackRenderData", value: function getTrackRenderData() { var data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; var defaults = { height: this.waveHeight, resolution: this.samplesPerPixel, sampleRate: this.sampleRate, controls: this.controls, isActive: false, timeSelection: this.getTimeSelection(), playlistLength: this.duration, playbackSeconds: this.playbackSeconds, colors: this.colors }; return (0, _lodash["default"])(data, defaults); } }, { key: "isActiveTrack", value: function isActiveTrack(track) { var activeTrack = this.getActiveTrack(); if (this.isSegmentSelection()) { return activeTrack === track; } return true; } }, { key: "renderAnnotations", value: function renderAnnotations() { return this.annotationList.render(); } }, { key: "renderTimeScale", value: function renderTimeScale() { var controlWidth = this.controls.show ? this.controls.width : 0; var timeScale = new _TimeScale["default"](this.duration, this.scrollLeft, this.samplesPerPixel, this.sampleRate, controlWidth, this.colors); return timeScale.render(); } }, { key: "renderTrackSection", value: function renderTrackSection() { var _this17 = this; var trackElements = this.tracks.map(function (track) { return track.render(_this17.getTrackRenderData({ isActive: _this17.isActiveTrack(track), shouldPlay: _this17.shouldTrackPlay(track), soloed: _this17.soloedTracks.indexOf(track) > -1, muted: _this17.mutedTracks.indexOf(track) > -1 })); }); return (0, _h["default"])('div.playlist-tracks', { attributes: { style: 'overflow: auto;' }, onscroll: function onscroll(e) { _this17.scrollLeft = (0, _conversions.pixelsToSeconds)(e.target.scrollLeft, _this17.samplesPerPixel, _this17.sampleRate); _this17.ee.emit('scroll', _this17.scrollLeft); }, hook: new _ScrollHook["default"](this) }, trackElements); } }, { key: "render", value: function render() { var containerChildren = []; if (this.showTimescale) { containerChildren.push(this.renderTimeScale()); } containerChildren.push(this.renderTrackSection()); if (this.annotationList.length) { containerChildren.push(this.renderAnnotations()); } return (0, _h["default"])('div.playlist', { attributes: { style: 'overflow: hidden; position: relative;' } }, containerChildren); } }, { key: "getInfo", value: function getInfo() { var info = []; this.tracks.forEach(function (track) { info.push(track.getTrackDetails()); }); return info; } }]); return _default; }(); exports["default"] = _default;