I’m trying to figure out a way to "fill" an array of audio meters to to fit a certain width. For instance, if I say that I need the resulting array to have 12 elements, then,
const input = [ -160, -140, -100, -80 ]
would become
const result = [ -160, -160, -160, -140, -140, -140, -100, -100, -100, -80, -80, -80, ]
Likewise, if the input has more than 12 elements, for instance:
// 20 elements
const input = [ -160, -160, -160, -140, -140, -140, -100, -100, -100, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, ]
then here we know that each meter value represents 1.67 bars (20 elements / 12 required width contraint), so the result should be something like this:
const result = [ -160, -160, -140, -140, -100, -80, -80, -80, -80, -80, -80, -80, ]
Here’s one of my attempts at the following:
const input = [ -160, -160, -160, -140, -140, -140, -100, -100, -100, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, ];
const MAX_BARS_FOR_AMPLITUDE = 12;
const metersPerBar = input.length / MAX_BARS_FOR_AMPLITUDE;
const barsPerMeter = 1 / metersPerBar;
const { result } = input.reduce(
(
acc,
meter,
) => {
if (barsPerMeter < 1) {
if (acc.chunkAccumulator.chunks < 1) {
acc.chunkAccumulator.meterValue ||= meter;
acc.chunkAccumulator.chunks += barsPerMeter;
} else {
acc.result.push(acc.chunkAccumulator.meterValue);
acc.chunkAccumulator.meterValue = 0;
acc.chunkAccumulator.chunks = 0;
}
} else {
if (acc.chunkAccumulator.chunks < barsPerMeter) {
acc.chunkAccumulator.meterValue ||= meter;
acc.chunkAccumulator.chunks += barsPerMeter;
} else {
acc.result.push(acc.chunkAccumulator.meterValue);
acc.chunkAccumulator.meterValue = 0;
acc.chunkAccumulator.chunks = 0;
}
}
return acc;
},
{
result: [],
chunkAccumulator: {
meterValue: 0,
chunks: 0,
},
},
);
console.log(result);
I’ve tried fiddling around, but the above solution never returns a resulting array of required length (MAX_BARS_FOR_AMPLITUDE
), and I feel like I’m taking the wrong approach altogether. I’m also unsure of how I should be handling the case when, for instance, 1.67 meter values represent 1 whole bar.
The idea here is to draw out an audiowave with an always-set number of bars, regardless of the number of meter values in the input
set. For instance, input could be const input = [-20]
, and this would result in an array of length MAX_BARS_FOR_AMPLITUDE
, where each element would be equal to -20
. Metering is recorder every 50ms, so this particular input
array would represent a 50ms audio recording.
By audiowave, I mean something like this:
What am I doing wrong here or is there a better way to handle this altogether?
Here’s another attempt, but this doesn’t work for an input with a length less that that of MAX_BARS_FOR_AMPLITTUDE
:
const input = [ -160, -160, -160, -140, -140, -140, -100, -100, -100, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, ];
const MAX_BARS_FOR_AMPLITUDE = 40;
const metersPerBar = input.length / MAX_BARS_FOR_AMPLITUDE;
const barsPerMeter = 1 / metersPerBar;
let currentPoint = 0;
let currentChunk = 0;
const result = Array.from({ length: MAX_BARS_FOR_AMPLITUDE }, (_, index) => {
if (barsPerMeter > currentChunk) {
currentChunk += barsPerMeter;
} else {
currentPoint++;
currentChunk = 0
}
return input[currentPoint];
});
console.log(result);
2
Answers
Just map your needed range to range of your actual values: