From 7b6d3f4b18ecdabf587b08338e17ce672cab6d79 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Wed, 26 Nov 2014 10:58:17 +0100 Subject: [PATCH] Make balance control work Using code by @lostsource, we've implemented support for the balance control. Fixes #13 --- media.js | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++----- winamp.js | 1 + 2 files changed, 75 insertions(+), 6 deletions(-) diff --git a/media.js b/media.js index 56d1dbeb..5558f552 100644 --- a/media.js +++ b/media.js @@ -17,13 +17,63 @@ Media = { autoPlay: false, init: function() { - this._gainNode = this._context.createGain(); - this._analyser = this._context.createAnalyser(); + // The _source node has to be recreated each time it's stopped or + // paused, so we don't create it here. + // Create the spliter node + this._chanSplit = this._context.createChannelSplitter(2); + + // Create the gains for left and right + this._leftGain = this._context.createGain(); + this._rightGain = this._context.createGain(); + + // Create channel merge + this._chanMerge = this._context.createChannelMerger(2); + + // Create the gain node for the volume control + this._gainNode = this._context.createGain(); + + // Create the analyser node for the visualizer + this._analyser = this._context.createAnalyser(); this._analyser.fftSize = 2048; this._bufferLength = this._analyser.frequencyBinCount; this._dataArray = new Uint8Array(this._bufferLength); this._analyser.getByteTimeDomainData(this._dataArray); + + // Connect all the nodes in the correct way + // (Note, source is created and connected later) + // + // + // |\ + // | + // | + // (split using createChannelSplitter) + // | + // / \ + // / \ + // leftGain rightGain + // \ / + // \ / + // | + // (merge using createChannelMerger) + // | + // chanMerge + // | + // gain + // | + // destination + + // Connect split channels to left / right gains + this._chanSplit.connect(this._leftGain,0); + this._chanSplit.connect(this._rightGain,1); + + // Reconnect the left / right gains to the merge node + this._leftGain.connect(this._chanMerge, 0, 0); + this._rightGain.connect(this._chanMerge, 0, 1); + + this._chanMerge.connect(this._gainNode); + + this._gainNode.connect(this._context.destination); return this; }, @@ -77,12 +127,11 @@ Media = { // So we don't get a race condition with _position getting overwritten this.pause(); } - this._source = this._context.createBufferSource(); if(this._buffer) { + this._source = this._context.createBufferSource(); this._source.buffer = this._buffer; this._source.connect(this._analyser); - this._analyser.connect(this._gainNode); - this._gainNode.connect(this._context.destination); + this._source.connect(this._chanSplit); this._position = typeof position !== 'undefined' ? position : this._position; this._startTime = this._context.currentTime - this._position; @@ -125,7 +174,26 @@ Media = { // From -100 to 100 setBalance: function(balance) { - // TODO + var changeVal = Math.abs(balance) / 100; + + // Hack for Firefox. Having either channel set to 0 seems to revert us + // to equal balance. + var changeVal = changeVal - .00000001; + + if(balance > 0) { // Right + this._leftGain.gain.value = 1 - changeVal; + this._rightGain.gain.value = 1; + } + else if(balance < 0) // Left + { + this._leftGain.gain.value = 1; + this._rightGain.gain.value = 1 - changeVal; + } + else // Center + { + this._leftGain.gain.value = 1; + this._rightGain.gain.value = 1; + } }, toggleRepeat: function() { diff --git a/winamp.js b/winamp.js index 0c0f81f1..17e663ad 100755 --- a/winamp.js +++ b/winamp.js @@ -292,6 +292,7 @@ function Winamp () { } self.skin.font.setNodeToString(self.nodes.balanceMessage, string); + self.media.setBalance(balance); balance = Math.abs(balance) / 100 sprite = Math.round(balance * 28); offset = (sprite - 1) * 15;