From a93f4e9a93b2f444438d259f6f62ddcf6f84919a Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Mon, 4 Sep 2017 11:01:52 -0700 Subject: [PATCH] Convert Medai to es6 class, support toggle EQ --- js/media.js | 174 +++++++++++++++++++++++------------------- js/mediaMiddleware.js | 10 ++- js/winamp.js | 2 +- 3 files changed, 106 insertions(+), 80 deletions(-) diff --git a/js/media.js b/js/media.js index 82136b20..04546c4a 100644 --- a/js/media.js +++ b/js/media.js @@ -2,28 +2,27 @@ import { BANDS } from "./constants"; import MyFile from "./myFile"; -export default { - _context: new (window.AudioContext || window.webkitAudioContext)(), - _source: null, - _buffer: null, - _callbacks: { - waiting: function() {}, - stopWaiting: function() {}, - playing: function() {}, - timeupdate: function() {}, - visualizerupdate: function() {}, - ended: function() {}, - fileLoaded: function() {} - }, - _startTime: 0, - _position: 0, - _balance: 0, - _playing: false, - _loop: false, - autoPlay: false, - name: null, - - init: function(fileInput) { +export default class Media { + constructor(fileInput) { + this._context = new (window.AudioContext || window.webkitAudioContext)(); + this._source = null; + this._buffer = null; + this._callbacks = { + waiting: function() {}, + stopWaiting: function() {}, + playing: function() {}, + timeupdate: function() {}, + visualizerupdate: function() {}, + ended: function() {}, + fileLoaded: function() {} + }; + this._startTime = 0; + this._position = 0; + this._balance = 0; + this._playing = false; + this._loop = false; + this.autoPlay = false; + this.name = null; this.fileInput = fileInput; // The _source node has to be recreated each time it's stopped or @@ -57,9 +56,11 @@ export default { // | // | // preamp - // | - // [biquadFilters] - // | + // |_____________ + // | \ + // [...biquadFilters] | <-- Optional bypass + // | ____________/ + // |/ // (split using createChannelSplitter) // | // / \ @@ -117,10 +118,10 @@ export default { // Kick off the animation loop this._draw(0); return this; - }, + } // Load from bufferArray - loadBuffer: function(buffer, loadedCallback) { + loadBuffer(buffer, loadedCallback) { this.stop(); this._callbacks.waiting(); @@ -138,36 +139,42 @@ export default { }; // Decode the target file into an arrayBuffer and pass it to loadBuffer this._context.decodeAudioData(buffer, loadAudioBuffer.bind(this), error); - }, + } /* Properties */ - duration: function() { + duration() { return this._buffer.duration; - }, - timeElapsed: function() { + } + + timeElapsed() { return this._position; - }, - timeRemaining: function() { + } + + timeRemaining() { return this.duration() - this.timeElapsed(); - }, - percentComplete: function() { + } + + percentComplete() { return this.timeElapsed() / this.duration() * 100; - }, - channels: function() { + } + + channels() { if (!this._buffer) { return 0; } return this._buffer.numberOfChannels; - }, - sampleRate: function() { + } + + sampleRate() { return this._buffer.sampleRate; - }, + } /* Actions */ - previous: function() { + previous() { // Implement this when we support playlists - }, - play: function(position) { + } + + play(position) { if (this._playing) { // So we don't get a race condition with _position getting overwritten this.pause(); @@ -185,46 +192,47 @@ export default { this._playing = true; this._callbacks.playing(); } - }, - pause: function() { + } + + pause() { if (!this._playing) { return; } this._silence(); this._updatePosition(); - }, + } - stop: function() { + stop() { this._silence(); this._position = 0; - }, + } - _silence: function() { + _silence() { if (this._source) { this._source.stop(0); this._source = null; } this._playing = false; - }, + } /* Actions with arguments */ - seekToPercentComplete: function(percent) { + seekToPercentComplete(percent) { const seekTime = this.duration() * (percent / 100); this.seekToTime(seekTime); - }, + } // From 0-1 - setVolume: function(volume) { + setVolume(volume) { this._gainNode.gain.value = volume / 100; - }, + } // From 0-1 - setPreamp: function(value) { + setPreamp(value) { this._preamp.gain.value = value / 100; - }, + } // From -100 to 100 - setBalance: function(balance) { + setBalance(balance) { let changeVal = Math.abs(balance) / 100; // Hack for Firefox. Having either channel set to 0 seems to revert us @@ -245,67 +253,77 @@ export default { this._rightGain.gain.value = 1; } this._balance = balance; - }, + } - setEqBand: function(band, value) { + setEqBand(band, value) { const db = value / 100 * 24 - 12; this.bands[band].gain.value = db; - }, + } - toggleRepeat: function() { + disableEq() { + this._preamp.disconnect(); + this._preamp.connect(this._chanSplit); + } + + enableEq() { + this._preamp.disconnect(); + this._preamp.connect(this.bands[BANDS[0]]); + } + + toggleRepeat() { this._loop = !this._loop; - }, + } - toggleShuffle: function() { + toggleShuffle() { // Implement this when we support playlists - }, + } /* Listeners */ - addEventListener: function(event, callback) { + addEventListener(event, callback) { this._callbacks[event] = callback; - }, + } - seekToTime: function(time) { + seekToTime(time) { // Make sure we are within range // TODO: Use clamp time = Math.min(time, this.duration()); time = Math.max(time, 0); this.play(time); - }, + } - loadFromFileReference: function(fileReference) { + loadFromFileReference(fileReference) { const file = new MyFile(); file.setFileReference(fileReference); this.autoPlay = true; this.name = file.name; file.processBuffer(this._loadBuffer.bind(this)); - }, + } // Used only for the initial load, since it must have a CORS header - loadFromUrl: function(url, fileName) { + loadFromUrl(url, fileName) { const file = new MyFile(); this.name = fileName; file.setUrl(url, fileName); file.processBuffer(this._loadBuffer.bind(this)); - }, + } /* Listeners */ - _loadBuffer: function(buffer) { + _loadBuffer(buffer) { // Note, this will not happen right away this.loadBuffer(buffer, this._callbacks.fileLoaded); - }, + } // There is probably a more reasonable way to do this, rather than having // it always running. - _draw: function() { + _draw() { if (this._playing) { this._updatePosition(); this._callbacks.timeupdate(); } window.requestAnimationFrame(this._draw.bind(this)); - }, + } - _updatePosition: function() { + _updatePosition() { this._position = this._context.currentTime - this._startTime; if (this._position >= this._buffer.duration && this._playing) { // Idealy we could use _source.loop, but it makes updating the position tricky @@ -317,4 +335,4 @@ export default { } } } -}; +} diff --git a/js/mediaMiddleware.js b/js/mediaMiddleware.js index 4ec60d1e..93216367 100644 --- a/js/mediaMiddleware.js +++ b/js/mediaMiddleware.js @@ -15,7 +15,9 @@ import { STOP_WORKING, TOGGLE_REPEAT, TOGGLE_SHUFFLE, - UPDATE_TIME_ELAPSED + UPDATE_TIME_ELAPSED, + SET_EQ_OFF, + SET_EQ_ON } from "./actionTypes"; export default media => store => { @@ -92,6 +94,12 @@ export default media => store => { media.setEqBand(action.band, action.value); } break; + case SET_EQ_OFF: + media.disableEq(); + break; + case SET_EQ_ON: + media.enableEq(); + break; } return next(action); }; diff --git a/js/winamp.js b/js/winamp.js index efce87b5..7a8a5548 100755 --- a/js/winamp.js +++ b/js/winamp.js @@ -15,7 +15,7 @@ fileInput.type = "file"; fileInput.style.display = "none"; export default { - media: Media.init(fileInput), + media: new Media(fileInput), fileInput: fileInput, init: function(options) { this.fileInput.addEventListener("change", e => {