Changed how listening to ranges of a visualizer works.

This commit is contained in:
Harrison Deng 2022-04-17 02:29:40 -05:00
parent 45093faf4e
commit bf3cef97be
2 changed files with 51 additions and 25 deletions

View File

@ -14,20 +14,22 @@ import VisualizerUpdateManager from "../visualization/VisualizerUpdateManager.js
* Maps the red component of the text color to a certain range of bins. * Maps the red component of the text color to a certain range of bins.
* *
* @param {HTMLElement} element The element whose text's red value should be mapped. * @param {HTMLElement} element The element whose text's red value should be mapped.
* @param {number} color Where 0 for red, 1, for blue, 2 for green, and 3 for alpha. * @param {number} color Where r for red, g, for green, b for blue, and a for alpha.
* @param {number} min The lower bound of the bins to be mapped. * @param {number} lowerBin The lower bound of the bins to be mapped.
* @param {VisualizerUpdateManager} visUpdateManager The visualizer update manager associated with the audio playback you would like the mapping with. * @param {VisualizerUpdateManager} visUpdateManager The visualizer update manager associated with the audio playback you would like the mapping with.
* @param {interpolator} interpolator The interpolation function to use. * @param {interpolator} interpolator The interpolation function to use.
* @param {number} [max=undefined] The upper bound of the bins to be mapped. If left undefined, then only the bin defined by the min value is used. * @param {number} [upperBin=undefined] The upper bound of the bins to be mapped. If left undefined, then only the bin defined by the min value is used.
* @param {boolean} [reversed=true] If true, then the quieter, the greater the red value. * @param {boolean} [reversed=true] If true, then the quieter, the greater the red value.
*/ */
export function mapColor(element, color, min, visUpdateManager, interpolator, max = undefined, reversed = false) { export function mapColor(element, color, lowerBin, visUpdateManager, interpolator, upperBin = undefined, reversed = false) {
if (!max) max = min; const rgbaStr = "rgba";
visUpdateManager.addVisualizerRangeUpdateListener(min, max, (timeDelta, amp) => { color = rgbaStr.indexOf(color);
if (color < 0) throw new Error("Invalid color parameter provided.");
if (!upperBin) upperBin = lowerBin;
visUpdateManager.addVisualizerRangeUpdateListener(lowerBin, upperBin, (timeDelta, amp) => {
const rgba = parseColor(element.style.color); const rgba = parseColor(element.style.color);
rgba[color] = interpolator(rgba[color], amp, timeDelta); rgba[color] = interpolator(rgba[color], amp, timeDelta);
if (reversed) rgba[color] = 255 - rgba[color]; if (reversed) rgba[color] = 255 - rgba[color];
element.style.color = rgbaToHexRgba(rgba); element.style.color = rgbaToHexRgba(rgba);
}); });
} }

View File

@ -14,22 +14,34 @@ export default class VisualizerUpdateManager {
*/ */
constructor(visualizer) { constructor(visualizer) {
this._binnedListeners = []; this._binnedListeners = [];
this._rangedListeners = [];
for (let i = 0; i < visualizer.getNumberOfBins(); i++) { for (let i = 0; i < visualizer.getNumberOfBins(); i++) {
this._binnedListeners.push([]); this._binnedListeners.push([]);
} }
this._lastBins = new Uint8Array(this._binnedListeners.length); this._lastBins = new Uint8Array(this._binnedListeners.length);
this._visualizer = visualizer;
visualizer.addUpdateListener((delta, bins) => { this._visualizerListener = (delta, bins) => {
const sortedCopyOfRangedListeners = [... this._rangedListeners].sort((a, b) => a[0] - b[0]); // Priority queue could be better.
for (let binInd = 0; binInd < this._lastBins.length; binInd++) { for (let binInd = 0; binInd < this._lastBins.length; binInd++) {
const lastBin = this._lastBins[binInd]; const lastBin = this._lastBins[binInd];
if (lastBin !== bins[binInd]) { if (lastBin !== bins[binInd]) {
this._binnedListeners[binInd].forEach(listener => { this._binnedListeners[binInd].forEach(listener => {
listener(delta, bins[binInd], bins[binInd] - lastBin); listener(delta, bins[binInd], bins[binInd] - lastBin);
}); });
for (let rangedInd = 0; rangedInd < sortedCopyOfRangedListeners.length; rangedInd++) { // Could switch to a while loop.
const [min, max, listener] = sortedCopyOfRangedListeners[rangedInd];
if (min > binInd) break; // Don't need to check the rest if the current lowest minimum is greater than the current bin index.
if (binInd <= max) {
listener(delta, bins.slice(min, max));
sortedCopyOfRangedListeners.shift();
rangedInd--;
}
}
this._lastBins[binInd] = bins[binInd]; this._lastBins[binInd] = bins[binInd];
} }
} }
}); };
visualizer.addUpdateListener(this._visualizerListener);
} }
/** /**
@ -39,12 +51,18 @@ export default class VisualizerUpdateManager {
* @param {number} ampDelta change in amplitude of the frequency bin. * @param {number} ampDelta change in amplitude of the frequency bin.
*/ */
/**
* @callback visualizerRangeUpdateListener
* @param {number} timeDelta elapsed time since last update.
* @param {number} bins the bins of the range.
*/
/** /**
* *
* @param {number} freqBin the frequency bin this update listener should listen to. * @param {number} freqBin the frequency bin this update listener should listen to.
* @param {visualizerBinUpdateListener} listener the listener itself that will be called upon the bin updating. * @param {visualizerBinUpdateListener} listener the listener itself that will be called upon the bin updating.
* @returns {boolean} true if and only if the updater was added successfully, otherwise, false. * @returns {boolean} true if and only if the updater was added successfully.
*/ */
AddVisualizerBinUpdateListener(freqBin, listener) { AddVisualizerBinUpdateListener(freqBin, listener) {
if (this._binnedListeners[freqBin].includes(listener)) return false; if (this._binnedListeners[freqBin].includes(listener)) return false;
@ -53,19 +71,18 @@ export default class VisualizerUpdateManager {
} }
/** /**
* Similar to {@link VisualizerUpdateManager#AddVisualizerBinUpdateListener}, this method adds the same listener to a range of bins. * Similar to {@link VisualizerUpdateManager#AddVisualizerBinUpdateListener}, this method adds a listener for to a range of bins.
* *
* @param {number} min The lower bound of the bins to listen to (inclusive). * @param {number} min The lower bound of the bins to listen to (inclusive).
* @param {number} max The upper bound of the bins to listen to (inclusive). * @param {number} max The upper bound of the bins to listen to (inclusive).
* @param {visualizerBinUpdateListener} listener The listener to register to these bins. * @param {visualizerRangeUpdateListener} listener The listener to register to the range.
* @returns {boolean} True if and only if the listener was added at least once. * @returns {boolean} True if and only if the ranged listener was added successfully.
*/ */
addVisualizerRangeUpdateListener(min, max, listener) { addVisualizerRangeUpdateListener(min, max, listener) {
let added = false; const rangedListener = [min, max, listener];
for (let i = min; i <= max; i++) { if (this._rangedListeners.includes(rangedListener)) return false;
if (this.AddVisualizerBinUpdateListener(i, listener)) added = true; this._rangedListeners.push(rangedListener);
} return true;
return added;
} }
/** /**
@ -87,14 +104,14 @@ export default class VisualizerUpdateManager {
* @param {number} min The lower bound of bins to remove the listener from (inclusive). * @param {number} min The lower bound of bins to remove the listener from (inclusive).
* @param {number} max The upper bound of bin to remove the listener from (inclusive.) * @param {number} max The upper bound of bin to remove the listener from (inclusive.)
* @param {visualizerBinUpdateListener} listener The update listener to remove from the bins. * @param {visualizerBinUpdateListener} listener The update listener to remove from the bins.
* @returns {boolean} True if and only if at least one listener was removed. * @returns {boolean} True if and only if the given listener was removed.
*/ */
removeVisualizerRangeUpdateListener(min, max, listener) { removeVisualizerRangeUpdateListener(min, max, listener) {
let removed = false; const rangedListener = [min, max, listener];
for (let i = min; i <= max; i++) { const removeIndex = this._rangedListeners.indexOf(rangedListener);
if (this.removeVisualizerBinUpdateListener(i, listener)) removed = true; if (removeIndex < 0) return false;
} this._binnedListeners.splice(removeIndex, 1);
return removed; return true;
} }
/** /**
@ -124,4 +141,11 @@ export default class VisualizerUpdateManager {
bin.length = 0; bin.length = 0;
}); });
} }
/**
* Unbinds this update manager from the initial visualizer. Effectively meaning this manager will no longer be used.
*/
unbindVisualizer() {
this._visualizer.removeUpdateListener(this._visualizerListener);
}
} }