您现在的位置是:网站首页> HTML&JS

基于Web Audio API实现音频可视化效果

  • HTML&JS
  • 2022-06-07
  • 757人已阅读
摘要

1.png

<!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;

}


Top