我有 JavaScript 代码,可以绘制垂直条并根据平均音乐频率更改其颜色。我尝试更改每个条形的颜色以匹配前一个条形的颜色,但我得到了不同的颜色。
const fileInput = document.getElementById('fileInput');
const canvas = document.getElementById('canvas');
const canvasCtx = canvas.getContext('2d');
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
// Function to resize canvas
function resizeCanvas() {
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas(); // Initial call to set canvas size
let barColors = [];
const defaultBarColors = [];
fileInput.addEventListener('change', function() {
const file = this.files[0];
if (file) {
const reader = new FileReader();
reader.onload = function(e) {
audioCtx.decodeAudioData(e.target.result, function(buffer) {
visualize(buffer);
});
};
reader.readAsArrayBuffer(file);
}
});
let rev;
function visualize(buffer) {
const source = audioCtx.createBufferSource();
source.buffer = buffer;
const analyser = audioCtx.createAnalyser();
source.connect(analyser);
analyser.connect(audioCtx.destination);
analyser.fftSize = 512;
const bufferLength = analyser.frequencyBinCount;
const dataArray = new Uint8Array(bufferLength);
source.start();
draw();
function draw() {
requestAnimationFrame(draw);
analyser.getByteFrequencyData(dataArray);
canvasCtx.clearRect(0, 0, canvas.width, canvas.height);
const barWidth = Math.floor(canvas.width / 5);
const sensitivity = 1;
const frequencyBands = [
{ from: 0, to: Math.floor(bufferLength * 0.2) }, // Low frequencies
{ from: Math.floor(bufferLength * 0.2), to: Math.floor(bufferLength * 0.4) }, // Low-mid frequencies
{ from: Math.floor(bufferLength * 0.4), to: Math.floor(bufferLength * 0.6) }, // Mid frequencies
{ from: Math.floor(bufferLength * 0.6), to: Math.floor(bufferLength * 0.8) }, // Upper-mid frequencies
{ from: Math.floor(bufferLength * 0.8), to: bufferLength } // High frequencies
];
let x = 0;
for (let i = 0; i < frequencyBands.length; i++) { // 0,1,2,3,4
const { from, to } = frequencyBands[i];
const sum = dataArray.slice(from, to).reduce((acc, val) => acc + val, 0);
const avg = sum / (to - from);
let colorValue = rev[i];
if (avg > 0) {
if (i > 0) {
colorValue = rev[i - 1];
} else if (i == 0) {
colorValue = "rgb(255, 255, 255)"; // Если первая колонка, то белый цвет
}
} else {
colorValue = rev[i];
}
canvasCtx.fillStyle = colorValue;
const barHeight = Math.max((avg / 255) * canvas.height * sensitivity, canvas.height);
canvasCtx.fillRect(x, canvas.height - barHeight, barWidth, barHeight);
x += barWidth;
}
}
}
function initializeCanvas() {
const barWidth = Math.floor(canvas.width / 5);
let x = 0;
for (let i = 4; i >= 0; i--) {
const colorValue = Math.floor(((i / 5) * (240 - 51)) + 51);
const color = `rgb(${colorValue}, ${colorValue}, ${colorValue})`;
defaultBarColors[i] = color;
canvasCtx.fillStyle = color;
canvasCtx.fillRect(x, 0, barWidth, canvas.height);
x += barWidth;
}
rev = defaultBarColors.reverse();
}
initializeCanvas();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title></title>
<style>
body, html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
#canvas {
width: 100%;
height: 100vh;
display: block;
}
</style>
</head>
<body>
<input type="file" id="fileInput" accept="audio/*">
<canvas id="canvas"></canvas>
</body>
</html>
这里为每个栏设置颜色的主要部分:
let colorValue = rev[i];
if (avg > 0) {
if (i > 0) {
colorValue = rev[i - 1];
} else if (i == 0) {
colorValue = "rgb(255, 255, 255)"; // Если первая колонка, то белый цвет
}
} else {
colorValue = rev[i];
}
如果列是 0(第一个),我将颜色更改为白色。如果 avg > 0 我尝试获取上一个栏的颜色。否则我从 rev 数组设置默认颜色。
一些变化:
function draw() {
requestAnimationFrame(draw);
const numBars = 5;
let bar = 0;
analyser.getByteFrequencyData(dataArray);
canvasCtx.fillStyle = "#000";
canvasCtx.fillRect(0, 0, canvas.width, canvas.height);
const barWidth = canvas.width / numBars;
for (let i = 0; i < numBars; i++) {
const start = Math.floor(i * bufferLength / numBars);
const end = Math.floor((i + 1) * bufferLength / numBars);
let sum = 0;
for (let j = start; j < end; j++) {
sum += dataArray[j];
}
const avg = sum / (end - start);
if (avg > 0) {
currentColors[i] = avg;
} else {
currentColors[i] = rev[i]; // Возвращаемся к исходному цвету
}
const rgbColor = `rgb(${currentColors[i]}, ${currentColors[i]}, ${currentColors[i]})`;
canvasCtx.fillStyle = rgbColor;
canvasCtx.fillRect(bar, 0, barWidth, canvas.height);
bar += barWidth;
}
}
我认为这就是您正在寻找的东西,但我可能是错的。
说明:
currentColors
的新数组,它将保存每个条形的当前颜色。currentColors
相同的初始颜色初始化 defaultBarColors
数组。colorValue
的旧逻辑没有正确更新条形的颜色。因此,我们利用 currentColors
数组来跟踪这些更改并更新其值。