Added bin selection function.

This commit is contained in:
Harrison Deng 2022-04-23 01:11:01 -05:00
parent 193ff9703e
commit aa8c43044a
5 changed files with 81 additions and 43 deletions

View File

@ -1,6 +1,6 @@
import { hslaToCssHsla, hslaToRgba, parseColorToHsla, parseColorToRgba, rgbaToCssRgba, rgbaToHexRgba, rgbaToHsla } from "../support/colors.js";
import VisUpdateRouter from "../visualization/VisUpdateRouter.js";
import { numerical } from "./numeric.js";
import { numericalBins } from "./numeric.js";
/**@module */
@ -13,14 +13,15 @@ import { numerical } from "./numeric.js";
* @param {string} conf.select Where r for red, g, for green, b for blue, and a for alpha.
* @param {number} conf.lowerBin The lower bound of the bins to be mapped.
* @param {VisUpdateRouter} conf.visUpdateRouter The visualizer update manager associated with the audio playback you would like the mapping with.
* @param {Function} conf.interpolator The interpolation function to use.
* @param {module:support/bins~binSelector} [conf.binSelector=undefined] The bin selector to use to calculate a number to use for the mapping.
* @param {number} [conf.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 {Function} [conf.interpolator=undefined] The interpolation function to use.
* @param {boolean} [conf.reversed=true] If true, then the quieter, the greater the red value.
* @param {number} [conf.lowerVal=0] The lower boundary of possible values for the color component (0 to upperVal inclusive).
* @param {number} [conf.upperVal=0] The upper boundary of possible values for the color component (0 to 255 inclusive).
* @returns {{lower: number, upper: number, listener: VisUpdateRouter~visualizerRangedUpdateListener}} The ranged listener that was added.
*/
export function backgroundColorRgba({ element, select, lowerBin, visUpdateRouter, interpolator, upperBin = undefined, reversed = false, lowerVal = 0, upperVal = 255 }) {
export function backgroundColorRgba({ element, select, lowerBin, visUpdateRouter, binSelector = undefined, upperBin = undefined, interpolator = undefined, reversed = false, lowerVal = 0, upperVal = 255 }) {
const rgbaStr = "rgba";
const defaultColor = [0, 0, 0, 255];
select = rgbaStr.indexOf(select);
@ -50,11 +51,12 @@ export function backgroundColorRgba({ element, select, lowerBin, visUpdateRouter
upperBin: upperBin,
getter: getter,
setter: setter,
interpolator: interpolator,
binSelector: binSelector,
visUpdateRouter: visUpdateRouter,
interpolator: interpolator,
reversed: reversed
};
return numerical(conf);
return numericalBins(conf);
}
/**
@ -65,14 +67,15 @@ export function backgroundColorRgba({ element, select, lowerBin, visUpdateRouter
* @param {number} conf.select Where h for hue, s, for saturation, l for lightness, and a for alpha.
* @param {number} conf.lowerBin The lower bound of the bins to be mapped.
* @param {VisUpdateRouter} conf.visUpdateRouter The visualizer update manager associated with the audio playback you would like the mapping with.
* @param {Function} conf.interpolator The interpolation function to use.
* @param {module:support/bins~binSelector} [conf.binSelector=undefined] The bin selector to use to calculate a number to use for the mapping.
* @param {number} [conf.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 {Function} [conf.interpolator=undefined] The interpolation function to use.
* @param {boolean} [conf.reversed=true] If true, then the quieter, the greater the red value.
* @param {number} [conf.lowerVal=0] The lower boundary of possible values for the color component (0 to upperVal inclusive).
* @param {number} [conf.upperVal=0] The upper boundary of possible values for the color component (0 to 360 if conf.color is "h", 1 if conf.color is "s" or "l", and 255 if conf.color is "a").
* @returns {{lower: number, upper: number, listener: VisUpdateRouter~visualizerRangedUpdateListener}} The ranged listener that was added.
*/
export function backgroundColorHsla({ element, select, lowerBin, visUpdateRouter, interpolator, upperBin = undefined, reversed = false, lowerVal = 0, upperVal = undefined }) {
export function backgroundColorHsla({ element, select, lowerBin, visUpdateRouter, binSelector = undefined, upperBin = undefined, interpolator = undefined, reversed = false, lowerVal = 0, upperVal = undefined }) {
const rgbaStr = "hsla";
const defaultColor = [0, 0.5, 0.5, 255];
select = rgbaStr.indexOf(select);
@ -110,11 +113,12 @@ export function backgroundColorHsla({ element, select, lowerBin, visUpdateRouter
upperBin: upperBin,
getter: getter,
setter: setter,
binSelector: binSelector,
interpolator: interpolator,
visUpdateRouter: visUpdateRouter,
reversed: reversed
};
return numerical(conf);
return numericalBins(conf);
}
/**
@ -125,14 +129,15 @@ export function backgroundColorHsla({ element, select, lowerBin, visUpdateRouter
* @param {string} conf.select Where r for red, g, for green, b for blue, and a for alpha.
* @param {number} conf.lowerBin The lower bound of the bins to be mapped.
* @param {VisUpdateRouter} conf.visUpdateRouter The visualizer update manager associated with the audio playback you would like the mapping with.
* @param {Function} conf.interpolator The interpolation function to use.
* @param {module:support/bins~binSelector} [conf.binSelector=undefined] The bin selector to use to calculate a number to use for the mapping.
* @param {number} [conf.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 {Function} [conf.interpolator=undefined] The interpolation function to use.
* @param {boolean} [conf.reversed=true] If true, then the quieter, the greater the red value.
* @param {number} [conf.lowerVal=0] The lower boundary of possible values for the color component (0 to upperVal inclusive).
* @param {number} [conf.upperVal=0] The upper boundary of possible values for the color component (0 to 255 inclusive).
* @returns {{lower: number, upper: number, listener: VisUpdateRouter~visualizerRangedUpdateListener}} The ranged listener that was added.
*/
export function fontColorRgba({ element, select, lowerBin, visUpdateRouter, interpolator, upperBin = undefined, reversed = false, lowerVal = 0, upperVal = 255 }) {
export function fontColorRgba({ element, select, lowerBin, visUpdateRouter, binSelector = undefined, upperBin = undefined, interpolator = undefined, reversed = false, lowerVal = 0, upperVal = 255 }) {
const rgbaStr = "rgba";
const defaultColor = [0, 0, 0, 255];
select = rgbaStr.indexOf(select);
@ -162,11 +167,12 @@ export function fontColorRgba({ element, select, lowerBin, visUpdateRouter, inte
upperBin: upperBin,
getter: getter,
setter: setter,
binSelector: binSelector,
interpolator: interpolator,
visUpdateRouter: visUpdateRouter,
reversed: reversed
};
return numerical(conf);
return numericalBins(conf);
}
/**
@ -177,14 +183,15 @@ export function fontColorRgba({ element, select, lowerBin, visUpdateRouter, inte
* @param {number} conf.select Where h for hue, s, for saturation, l for lightness, and a for alpha.
* @param {number} conf.lowerBin The lower bound of the bins to be mapped.
* @param {VisUpdateRouter} conf.visUpdateRouter The visualizer update manager associated with the audio playback you would like the mapping with.
* @param {Function} conf.interpolator The interpolation function to use.
* @param {module:support/bins~binSelector} [conf.binSelector=undefined] The bin selector to use to calculate a number to use for the mapping.
* @param {number} [conf.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 {Function} [conf.interpolator=undefined] The interpolation function to use.
* @param {boolean} [conf.reversed=true] If true, then the quieter, the greater the red value.
* @param {number} [conf.lowerVal=0] The lower boundary of possible values for the color component (0 to upperVal inclusive).
* @param {number} [conf.upperVal=0] The upper boundary of possible values for the color component (0 to 360 if conf.color is "h", 1 if conf.color is "s" or "l", and 255 if conf.color is "a").
* @returns {{lower: number, upper: number, listener: VisUpdateRouter~visualizerRangedUpdateListener}} The ranged listener that was added.
*/
export function fontColorHsla({ element, select, lowerBin, visUpdateRouter, interpolator, upperBin = undefined, reversed = false, lowerVal = 0, upperVal = undefined }) {
export function fontColorHsla({ element, select, lowerBin, visUpdateRouter, binSelector = undefined, upperBin = undefined, interpolator = undefined, reversed = false, lowerVal = 0, upperVal = undefined }) {
const rgbaStr = "hsla";
const defaultColor = [0, 0.5, 0.5, 255];
select = rgbaStr.indexOf(select);
@ -224,9 +231,10 @@ export function fontColorHsla({ element, select, lowerBin, visUpdateRouter, inte
upperBin: upperBin,
getter: getter,
setter: setter,
binSelector: binSelector,
interpolator: interpolator,
visUpdateRouter: visUpdateRouter,
reversed: reversed
};
return numerical(conf);
return numericalBins(conf);
}

View File

@ -1,5 +1,5 @@
import VisUpdateRouter from "../visualization/VisUpdateRouter.js";
import { numerical } from "./numeric.js";
import { numericalBins } from "./numeric.js";
/**@module */
@ -13,12 +13,13 @@ import { numerical } from "./numeric.js";
* @param {string} conf.unit The unit the upper and lower bounds are measured in.
* @param {number} conf.lowerBin The lower boundary of bins to be mapped (or the single bin to be mapped if the upper bin is undefined).
* @param {VisUpdateRouter} conf.visUpdateRouter The visualizer update manager to be mapped to.
* @param {module:support/easings~interpolator} conf.interpolator The interpolation function to be used to transition from one value to the next.
* @param {module:support/bins~binSelector} [conf.binSelector=undefined] The bin selector function to use to get a number for the mapping.
* @param {number} [conf.upperBin] The upper bin or undefined, which results in mapping to a single bin.
* @param {module:support/easings~interpolator} [conf.interpolator=undefined] The interpolation function to be used to transition from one value to the next.
* @param {boolean} [conf.reversed=false] If true, then high amplitudes are mapped to lower values and vice versa.
* @returns {{bin: number, listener: VisUpdateRouter~visualizerBinUpdateListener}|{lower: number, upper: number, listener: VisUpdateRouter.visualizerRangedUpdateListener}} The listener that was added (ranged if an upper bound was provided, binned otherwise).
*/
export function width({ element, growLower, growUpper, unit, lowerBin, visUpdateRouter, interpolator, upperBin = undefined, reversed = false }) {
export function width({ element, growLower, growUpper, unit, lowerBin, visUpdateRouter, binSelector = undefined, upperBin = undefined, interpolator = undefined, reversed = false }) {
const getter = () => parseInt(element.style.width) || 0;
const setter = (value) => element.style.width = value + unit;
const conf = {
@ -28,11 +29,12 @@ export function width({ element, growLower, growUpper, unit, lowerBin, visUpdate
upperBin: upperBin,
getter: getter,
setter: setter,
binSelector: binSelector,
interpolator: interpolator,
visUpdateRouter: visUpdateRouter,
reversed: reversed
};
return numerical(conf);
return numericalBins(conf);
}
/**
@ -45,12 +47,13 @@ export function width({ element, growLower, growUpper, unit, lowerBin, visUpdate
* @param {string} conf.unit The unit the upper and lower bounds are measured in.
* @param {number} conf.lowerBin The lower boundary of bins to be mapped (or the single bin to be mapped if the upper bin is undefined).
* @param {VisUpdateRouter} conf.visUpdateRouter The visualizer update manager to be mapped to.
* @param {module:support/easings~interpolator} conf.interpolator The interpolation function to be used to transition from one value to the next.
* @param {module:support/bins~binSelector} [conf.binSelector=undefined] The bin selector function to use to get a number for the mapping.
* @param {number} [conf.upperBin] The upper bin or undefined, which results in mapping to a single bin.
* @param {module:support/easings~interpolator} [conf.interpolator=undefined] The interpolation function to be used to transition from one value to the next.
* @param {boolean} [conf.reversed=false] If true, then high amplitudes are mapped to lower values and vice versa.
* @returns {{bin: number, listener: VisUpdateRouter~visualizerBinUpdateListener}|{lower: number, upper: number, listener: VisUpdateRouter.visualizerRangedUpdateListener}} The listener that was added (ranged if an upper bound was provided, binned otherwise).
*/
export function height({ element, growLower, growUpper, unit, lowerBin, visUpdateRouter, interpolator, upperBin = undefined, reversed = false }) {
export function height({ element, growLower, growUpper, unit, lowerBin, visUpdateRouter, binSelector = undefined, upperBin = undefined, interpolator = undefined, reversed = false }) {
const getter = () => parseInt(element.style.height) || 0;
const setter = (value) => element.style.height = value + unit;
const conf = {
@ -60,28 +63,30 @@ export function height({ element, growLower, growUpper, unit, lowerBin, visUpdat
upperBin: upperBin,
getter: getter,
setter: setter,
binSelector: binSelector,
interpolator: interpolator,
visUpdateRouter: visUpdateRouter,
reversed: reversed
};
return numerical(conf);
return numericalBins(conf);
}
/**
*
* @param {object} fontSizeMapConfiguration The configuration of the font size mapping.
* @param {HTMLElement} fontSizeMapConfiguration.element The element whose font sizes will be mapped to the amplitude.
* @param {number} fontSizeMapConfiguration.growLower The lower limit of the font size.
* @param {number} fontSizeMapConfiguration.growUpper The upper limit of the font size.
* @param {string} fontSizeMapConfiguration.unit The unit the upper and lower bounds are measured in.
* @param {number} fontSizeMapConfiguration.lowerBin The lower boundary of bins to be mapped (or the single bin to be mapped if the upper bin is undefined).
* @param {VisUpdateRouter} fontSizeMapConfiguration.visUpdateRouter the visualizer update manager to be mapped to.
* @param {module:support/easings~interpolator} fontSizeMapConfiguration.interpolator The interpolation function to be used to transition from one value to the next.
* @param {number} [fontSizeMapConfiguration.upperBin=undefined] The upper bin, or undefined, which results in mapping to a single bin.
* @param {boolean} [fontSizeMapConfiguration.reversed=false] If true, then high amplitudes are mapped to lower values and vice versa.
* @param {object} conf The configuration of the font size mapping.
* @param {HTMLElement} conf.element The element whose font sizes will be mapped to the amplitude.
* @param {number} conf.growLower The lower limit of the font size.
* @param {number} conf.growUpper The upper limit of the font size.
* @param {string} conf.unit The unit the upper and lower bounds are measured in.
* @param {number} conf.lowerBin The lower boundary of bins to be mapped (or the single bin to be mapped if the upper bin is undefined).
* @param {VisUpdateRouter} conf.visUpdateRouter the visualizer update manager to be mapped to.
* @param {module:support/bins~binSelector} [conf.binSelector=undefined] The bin selector function to use to get a number for the mapping.
* @param {number} [conf.upperBin=undefined] The upper bin, or undefined, which results in mapping to a single bin.
* @param {module:support/easings~interpolator} [conf.interpolator=undefined] The interpolation function to be used to transition from one value to the next.
* @param {boolean} [conf.reversed=false] If true, then high amplitudes are mapped to lower values and vice versa.
* @returns {{bin: number, listener: VisUpdateRouter~visualizerBinUpdateListener}|{lower: number, upper: number, listener: VisUpdateRouter~visualizerRangedUpdateListener}} The listener that was added (ranged if an upper bound was provided, binned otherwise).
*/
export function fontSize({ element, growLower, growUpper, unit, lowerBin, visUpdateRouter, interpolator, upperBin = undefined, reversed = false }) {
export function fontSize({ element, growLower, growUpper, unit, lowerBin, visUpdateRouter, binSelector = undefined, upperBin = undefined, interpolator = undefined, reversed = false }) {
const getter = () => parseInt(element.style.fontSize) || 0;
const setter = (value) => element.style.fontSize = value + unit;
const conf = {
@ -91,9 +96,10 @@ export function fontSize({ element, growLower, growUpper, unit, lowerBin, visUpd
upperBin: upperBin,
getter: getter,
setter: setter,
binSelector: binSelector,
interpolator: interpolator,
visUpdateRouter: visUpdateRouter,
reversed: reversed
};
return numerical(conf);
return numericalBins(conf);
}

View File

@ -1,3 +1,5 @@
import { createUniAvgSel } from "../support/bins.js";
import { createEaseLinear } from "../support/easings.js";
import VisUpdateRouter from "../visualization/VisUpdateRouter.js";
/**@module */
@ -22,27 +24,25 @@ import VisUpdateRouter from "../visualization/VisUpdateRouter.js";
* @param {number} conf.minVal The minimum value of the numerical value.
* @param {number} conf.maxVal The maximum value of the numerical value.
* @param {number} conf.lowerBin The lower bin of the range of bins this value is to be mapped to.
* @param {number} [conf.upperBin=undefined] The upper bin of the range of bins this value si to be mapped to.
* @param {module:mappings/numeric~numericalGetter} conf.getter The getter callback to be used to get the current number.
* @param {module:mappings/numeric~numericalSetter} conf.setter The setter callback to be used to set the new number.
* @param {module:support/easings~interpolator} conf.interpolator The interpolation function to use.
* @param {VisUpdateRouter} conf.visUpdateRouter the visualizer update manager this mapping corresponds with.
* @param {module:support/bins~binSelector} [conf.binSelector=undefined] The bin selector function to use to get a number for the mapping.
* @param {number} [conf.upperBin=undefined] The upper bin of the range of bins this value is to be mapped to.
* @param {module:support/easings~interpolator} [conf.interpolator=undefined] The interpolation function to use.
* @param {boolean} [conf.reversed = false] If true, then high amplitudes will be mapped to low values and vice versa.
* @returns {{lower: number, upper: number, listener: VisUpdateRouter.visualizerRangedUpdateListener}} An object containing the lower and upper bounds for the range of a listener, which is also in the object.
*/
export function numerical({ minVal, maxVal, lowerBin, upperBin = undefined, getter, setter, interpolator, visUpdateRouter, reversed = false }) {
export function numericalBins({ minVal, maxVal, lowerBin, getter, setter, visUpdateRouter, binSelector = undefined, upperBin = undefined, interpolator = undefined, reversed = false }) {
if (!binSelector) binSelector = createUniAvgSel();
if (!interpolator) interpolator = createEaseLinear(2);
const rangedListener = {
lower: lowerBin,
upper: upperBin ? upperBin : lowerBin,
listener: (timeDelta, bins) => {
const normalBins = [...bins];
// TODO: Future: add weighting / distribution system?
let normAvg = 0;
for (let i = 0; i < normalBins.length; i++) {
normalBins[i] = normalBins[i] / 255.0;
normAvg += normalBins[i];
}
normAvg /= normalBins.length;
let normAvg = binSelector(bins);
normAvg /= 255;
const range = maxVal - minVal;
let interpolated = interpolator((getter() - minVal) / range, normAvg, Math.min(timeDelta, 1));

23
src/support/bins.js Normal file
View File

@ -0,0 +1,23 @@
/**@module */
/**
* @callback binSelector
* @param {number[]} bins Array of frequency bins.
* @returns {number} A number from 0 to 255 representing the bin value to be used.
*/
/**
* Creates a {@link module:support/bins~binSelector} that simply uniformly averages all bins and returns said average.
*
* @returns {module:support/bins~binSelector} that simply uniformly averages all bins and returns said average.
*/
export function createUniAvgSel() {
return (bins) => {
let normAvg = 0;
for (let i = 0; i < bins.length; i++) {
normAvg += bins[i];
}
normAvg /= bins.length;
return normAvg;
};
}

View File

@ -182,6 +182,7 @@
playlist.add("./assets/audio/XXI.mp3", "XXI", "QR");
playlist.add("./assets/audio/moments.mp3", "Moments", "Lost Identities x Robbie Rosen");
playlist.add("./assets/audio/pathetique.mp3", "Pathetique", "Cryvera (Beethoven Remix)");
const playlistDisp = playlist.generatePlaylistElement();
document.getElementById("playlist-display").appendChild(playlistDisp);