musicvis-lib
Version:
Music analysis and visualization library
120 lines (111 loc) • 2.94 kB
JavaScript
import * as d3 from 'd3'
/**
* @module utils/MathUtils
*/
/**
* Generates a random float in [min, max)
*
* @param {number} min minimum
* @param {number} max maximum
* @returns {number} random float
*/
export function randFloat (min = 0, max = 1) {
return Math.random() * (max - min) + min
}
/**
* Returns a random element from the given array.
*
* @param {Array} array an array
* @returns {any} random element from the array
*/
export function choose (array) {
const index = d3.randomInt(0, array.length)()
return array[index]
}
/**
* Shortcut for Math.max(minValue, Math.min(maxValue, value))
*
* @param {number} value value
* @param {number} minValue lower limit
* @param {number} maxValue upper limit
* @returns {number} clipped number
*/
export function clipValue (value, minValue, maxValue) {
return Math.max(minValue, Math.min(maxValue, value))
}
/**
* Rounds a number to a given number of decimals
*
* @param {number} number a number
* @param {number} n number of digits
* @returns {number} rounded number
*/
export function roundToNDecimals (number, n) {
return +number.toFixed(n)
}
/**
* Swaps two numbers if the first is larger than the second
*
* @param {number} x a number
* @param {number} y a number
* @returns {number[]} array with the smaller number first
*/
export function swapSoSmallerFirst (x, y) {
if (x <= y) {
return [x, y]
}
return [y, x]
}
/**
* Counts the number of 1s in a binary number, e.g 100101 has 3 1s
*
* @see https://prismoskills.appspot.com/lessons/Bitwise_Operators/Count_ones_in_an_integer.jsp
* @param {number} integer an integer number
* @returns {number} number of 1s
*/
export function countOnesOfBinary (integer) {
let count = 0
while (integer !== 0) {
// eslint-disable-next-line no-bitwise
integer = integer & (integer - 1)
count++
}
return count
}
/**
* Local maxima are found by looking at entries that are higher than their left
* and right neighbor, or higher than their only neighbor if they are at the
* boundary.
* IMPORTANT: does not find plateaus
*
* @param {number[]} array array
* @returns {number[]} array with indices of maxima
*/
export function findLocalMaxima (array) {
if (array.length <= 1) { return [] }
if (array.length === 2) {
if (array[0] > array[1]) { return [0] }
if (array[1] > array[0]) { return [1] }
return []
}
// General case with 3 or more
const maximaIndices = []
if (array[0] > array[1]) {
maximaIndices.push(0)
}
let last = array[0]
let current = array[1]
for (let index = 1; index < array.length - 1; index++) {
const next = array[index + 1]
if (current > last && current > next) {
maximaIndices.push(index)
}
last = current
current = next
}
const lastIndex = array.length - 1
if (array[lastIndex] > array[lastIndex - 1]) {
maximaIndices.push(array.length - 1)
}
return maximaIndices
}