我正在做一个音乐可视化项目。
在我的HTML页面上,我有一个使用CSS样式的黄色圆圈的div,我想用JAVASCRIPT来收集音频文件的频率数据。
使用JAVASCRIPT,我想收集一个音频文件的频率数据,并利用这些数据,每当频率达到一个特定的数字时,就将圆圈的颜色改为粉红色--这个数字将代表音频中的瞬态。基本上,一个黄色的圆圈,会跟着歌曲的节拍变化成粉红色。
的HTML。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Flower</title>
<style>
/* centering */
body {
margin: 0;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
/* proportion and perspective */
#scene {
width: 200px;
height: 200px;
perspective: 600px;
perspective-origin: center top;
}
.flower {
width: 100%;
height: 100%;
position: relative;
transform-style: preserve-3d;
}
#center {
position: absolute;
width: 100px;
height: 100px;
border-radius: 50px;
background: yellow; // THIS IS YELLOW CIRCLE, AND PARAMETER I WANT TO CHANGE
transform: rotateX(180deg) translateX(50px) translateZ(-140px);
}
</style>
</head>
<body>
<input type="file" id="file-input" accept="audio/*,video/*,image/*" />
<canvas id="canvas"></canvas>
<div id="scene">
<div class="flower">
<div class="center" id="center"></div>
</div>
</div>
<audio id="audio" controls></audio>
<script src="audio.js"></script>
</body>
</html>
我现在的JS代码是:
window.onload = function() {
const file = document.getElementById("file-input");
const canvas = document.getElementById("canvas");
const audio = document.getElementById("audio");
file.onchange = function() {
const files = this.files;
console.log('FILES[0]: ', files[0])
audio.src = URL.createObjectURL(files[0]);
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const ctx = canvas.getContext("2d");
const flower = document.getElementById('center');
const context = new AudioContext();
let src = context.createMediaElementSource(audio);
const analyser = context.createAnalyser();
src.connect(analyser);
analyser.connect(context.destination);
analyser.fftSize = 1024;
const bufferLength = analyser.frequencyBinCount;
const dataArray = new Uint8Array(bufferLength);
const WIDTH = canvas.width;
const HEIGHT = canvas.height;
function renderFrame() {
requestAnimationFrame(renderFrame); // Takes callback function to invoke before rendering
analyser.getByteFrequencyData(dataArray); // Copies the frequency data into dataArray
// Results in a normalized array of values between 0 and 255
// Before this step, dataArray's values are all zeros (but with length of 8192)
for (let i = 0; i < bufferLength; i++) {
console.log("data array: ", dataArray)
//from here I can see the different frequencies collected in the array, but I don't know how to proceed
}
audio.play();
renderFrame();
};
};
};
我不知道如何制定FOR循环,然后如何将这些信息与CSS参数连接起来。
任何帮助都将是非常感激的! 我已经尝试了好几天,但没有任何进展。你可能会从我的代码中看出,我是一个完全的初学者。
所有最好的。
翡翠
只要做频率的平均值就可以了。这里是工作的例子。
const file = document.getElementById("file-input");
const canvas = document.getElementById("canvas");
const audio = document.getElementById("audio");
var threshold = 230; //Point where turn the "flower" pink
var frequencies = 10; //Number of records to count (You want to look for lower frequencies)
file.onchange = function() {
const files = this.files;
//console.log('FILES[0]: ', files[0])
audio.src = URL.createObjectURL(files[0]);
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const ctx = canvas.getContext("2d");
const flower = document.getElementById('center');
const context = new AudioContext();
let src = context.createMediaElementSource(audio);
const analyser = context.createAnalyser();
src.connect(analyser);
analyser.connect(context.destination);
analyser.fftSize = 1024;
const bufferLength = analyser.frequencyBinCount;
const dataArray = new Uint8Array(bufferLength);
const WIDTH = canvas.width;
const HEIGHT = canvas.height;
function renderFrame() {
requestAnimationFrame(renderFrame); // Takes callback function to invoke before rendering
analyser.getByteFrequencyData(dataArray); // Copies the frequency data into dataArray
// Results in a normalized array of values between 0 and 255
// Before this step, dataArray's values are all zeros (but with length of 8192)
let sum = 0;
for(let i = 0; i < bufferLength; i++) {
if(i < frequencies) sum += dataArray[i];
//Do some other stuff
}
//Change CSS according to threshold
let avg = sum / frequencies;
flower.style.backgroundColor = avg > threshold ? "pink" : "yellow";
flower.style.transform = `scale(${avg / 255})`;
flower.innerText = ~~avg;
};
//!!This functions have to be called outside of the rendering function (renderFrame)!!
audio.play();
renderFrame();
};
/* Sliders */
const sliderF = document.querySelector(".slider.f");
const sliderFvalue = document.querySelector(".slider-value.f");
const sliderT = document.querySelector(".slider.t");
const sliderTvalue = document.querySelector(".slider-value.t");
sliderF.oninput = function() {
sliderFvalue.innerText = this.value;
frequencies = +this.value;
}
sliderT.oninput = function() {
sliderTvalue.innerText = this.value;
threshold = +this.value;
}
/* centering */
body {
margin: 0;
}
canvas {
position: absolute;
pointer-events: none;
}
#audio {
width: 100vw;
}
#center {
width: 100px;
height: 100px;
border-radius: 50px;
background-color: yellow;
text-align: center;
line-height: 100px;
}
.slider-value {
display: inline-block;
width: 25px;
}
.slider {
width: 90vw;
}
<input type="file" id="file-input" accept="audio/*,video/*,image/*" /><br>
<canvas id="canvas"></canvas>
<audio id="audio" controls></audio>
<div class="center" id="center"></div>
<!-- Frequences Slider --->
<input type="range" min="0" max="500" value="10" step="1" class="slider f">
<span class="slider-value f">10</span>
<!-- Threshold Slider --->
<input type="range" min="0" max="255" value="230" step="1" class="slider t">
<span class="slider-value t">230</span>
你只需要调整滑块就可以了 但最好使用一些低通量的均衡器 这样你就可以得到更接近的结果了