您现在的位置是:网站首页> HTML&JS
基于Web Audio API实现音频可视化效果
- HTML&JS
- 2022-06-07
- 757人已阅读
<!doctype html>
<html>
<head>
<meta charset="UTF-8"/>
<title>可视化音乐播放器</title>
</head>
<body>
<input type="file" name="" value="" id="musicFile">
<p id="tip"></p>
<canvas id="casvased" width="500" height="500"></canvas>
</body>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script type="text/javascript">
//随机变颜色
function randomRgbColor() { //随机生成RGB颜色
var r = Math.floor(Math.random() * 256); //随机生成256以内r值
var g = Math.floor(Math.random() * 256); //随机生成256以内g值
var b = Math.floor(Math.random() * 256); //随机生成256以内b值
return `rgb(${r},${g},${b})`; //返回rgb(r,g,b)格式颜色
}
//随机数 0-255
function sum (m,n){
var num = Math.floor(Math.random()*(m - n) + n);
}
console.log(sum(0,100));
console.log(sum(100,255));
//展示音频可视化
var canvas = document.getElementById("casvased");
var canvasCtx = canvas.getContext("2d");
//首先实例化AudioContext对象 很遗憾浏览器不兼容,只能用兼容性写法;audioContext用于音频处理的接口,并且工作原理是将AudioContext创建出来的各种节点(AudioNode)相互连接,音频数据流经这些节点并作出相应处理。
//总结就一句话 AudioContext 是音频对象,就像 new Date()是一个时间对象一样
var AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext;
if (!AudioContext) {
alert("您的浏览器不支持audio API,请更换浏览器(chrome、firefox)再尝试,另外本人强烈建议使用谷歌浏览器!")
}
var audioContext = new AudioContext();//实例化
// 总结一下接下来的步骤
// 1 先获取音频文件(目前只支持单个上传)
// 2 读取音频文件,读取后,获得二进制类型的音频文件
// 3 对读取后的二进制文件进行解码
$('#musicFile').change(function(){
if (this.files.length == 0) return;
var file = $('#musicFile')[0].files[0];//通过input上传的音频文件
var fileReader = new FileReader();//使用FileReader异步读取文件
fileReader.readAsArrayBuffer(file);//开始读取音频文件
fileReader.onload = function(e) {//读取文件完成的回调
//e.target.result 即为读取的音频文件(此文件为二进制文件)
//下面开始解码操作 解码需要一定时间,这个时间应该让用户感知到
var count = 0;
$('#tip').text('开始解码')
var timer = setInterval(function(){
count++;
$('#tip').text('解码中,已用时'+count+'秒')
},1000)
//开始解码,解码成功后执行回调函数
audioContext.decodeAudioData(e.target.result, function(buffer) {
clearInterval(timer)
$('#tip').text('解码成功,用时共计:'+count+'秒')
// 创建AudioBufferSourceNode 用于播放解码出来的buffer的节点
var audioBufferSourceNode = audioContext.createBufferSource();
// 创建AnalyserNode 用于分析音频频谱的节点
var analyser = audioContext.createAnalyser();
//fftSize (Fast Fourier Transform) 是快速傅里叶变换,一般情况下是固定值2048。具体作用是什么我也不太清除,但是经过研究,这个值可以决定音频频谱的密集程度。值大了,频谱就松散,值小就密集。
analyser.fftSize = 256;
// 连接节点,audioContext.destination是音频要最终输出的目标,
// 我们可以把它理解为声卡。所以所有节点中的最后一个节点应该再
// 连接到audioContext.destination才能听到声音。
audioBufferSourceNode.connect(analyser);
analyser.connect(audioContext.destination);
console.log(audioContext.destination)
// 播放音频
audioBufferSourceNode.buffer = buffer; //回调函数传入的参数
audioBufferSourceNode.start(); //部分浏览器是noteOn()函数,用法相同
//可视化 创建数据
// var dataArray = new Uint8Array(analyser.fftSize);
// analyser.getByteFrequencyData(dataArray)//将数据放入数组,用来进行频谱的可视化绘制
// console.log(analyser.getByteFrequencyData)
var bufferLength = analyser.frequencyBinCount;
console.log(bufferLength);
var dataArray = new Uint8Array(bufferLength);
console.log(dataArray)
canvasCtx.clearRect(0, 0, 500, 500);
function draw() {
drawVisual = requestAnimationFrame(draw);
analyser.getByteFrequencyData(dataArray);
canvasCtx.fillStyle = 'rgb(0, 0, 0)';
//canvasCtx.fillStyle = ;
canvasCtx.fillRect(0, 0, 500, 500);
var barWidth = (500 / bufferLength) * 2.5;
var barHeight;
var x = 0;
for(var i = 0; i < bufferLength; i++) {
barHeight = dataArray[i];
//随机数0-255 Math.floor(Math.random()*255)
// 随机数 10*Math.random()
canvasCtx.fillStyle = 'rgb(' + (barHeight+100) + ','+Math.floor(Math.random()*(20- 120) + 120)+','+Math.floor(Math.random()*(10 - 50) + 50)+')';
canvasCtx.fillRect(x,500-barHeight/2,barWidth,barHeight/2);
x += barWidth + 1;
}
};
draw();
});
}
})
</script>
</html>
其他代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>Document</title>
</head>
<body>
<div id="container">
<canvas id="canvas1"></canvas>
<audio id="audio1" controls ></audio>
<input type="file" id="fileupload" accept="audio/*">
</div>
<script src="script.js"></script>
</body>
</html>
script.js
let audio1 = new Audio();
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const file = document.getElementById('fileupload');
audio1.src = '8-Bit Sound Library/Mp3/Climb_Rope_Loop_00.mp3';
const container = document.getElementById('container');
const canvas = document.getElementById('canvas1')
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const ctx = canvas.getContext('2d');
let audioSource;
let analyser;
file.addEventListener('change', function() {
const files = this.files;
const audio1 = document.getElementById('audio1');
audio1.src = URL.createObjectURL(files[0]);
audio1.load();
audio1.play();
audioSource = audioContext.createMediaElementSource(audio1);
analyser = audioContext.createAnalyser();
audioSource.connect(analyser);
analyser.connect(audioContext.destination);
analyser.fftSize = 64;
const bufferLength = analyser.frequencyBinCount;
console.log(bufferLength);
const dataArray = new Uint8Array(bufferLength);
const barWidth = canvas.width / bufferLength;
let barHeight;
let x;
function animate() {
x = 0;
ctx.clearRect(0, 0, canvas.width, canvas.height);
analyser.getByteFrequencyData(dataArray);
for (let i = 0; i < bufferLength; i++) {
barHeight = dataArray[i]*3;
ctx.fillStyle = 'white';
ctx.fillRect(x, canvas.height-barHeight, barWidth, barHeight);
x += barWidth;
}
requestAnimationFrame(animate);
}
animate();
})
style.css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
#container {
position: absolute;
top: 0;
left: 0;
background: black;
width: 100%;
height: 100%;
}
#canvas1 {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
#audio1 {
width: 50%;
margin: 50px auto;
display: block;
}
#fileupload {
position: absolute;
top: 150px;
z-index: 100;
color: white;
}