乐趣区

HTML5开发动态音频图

概要

  • 本次我们会使用 html5 和 js 开发一个动态音频图
  • 用到的技术点:

(1)js
(2)canvas + audio
(3)Web Audio API

  • 实现方式:

(1)首先对于界面实现的考虑,由于区块非常多,我们使用传统 dom 节点实现是非常困难的(会占用大量的电脑 CPU)。在这里,我们考虑使用 canvas 进行渲染
(2)前端中,我们遵循 尽量少用 js 控制 dom 节点 的原则。能用 css3 实现的特效,就不要用 js 实现。(因为 js 不是标记语言,而是脚本语言,与 html5 不是同一种语言。会浪费浏览器大量时间加载,造成浏览器性能的浪费)。因此,用 js 就少用 dom,用 dom 就尽量用 css。
(3)通过 Web Audio API 在音频节点上进行音频操作(即实现音频可视化),流程图如下:

在图中,音频上下文提供了音频处理的一套系统方法。输入源指音乐文件,通过名称引入;效果就是对输入源进行加工,如制作音频图、音波图、3D 环绕、低音音效等;输出就是把效果输出到耳机、扬声器等目的地。

canvas 引入

  • 在当下,除了布局使用 dom 节点外,特效基本都是通过 canvas 实现了。
  • canvas 好处:

(1)写特效非常强大,性能优
(2)用于做游戏。由于 flash 将于 2020 年退役,现在的游戏开始转向用 html5 制作
(3)前端渲染大数据,数据可视化,大屏数据展示

canvas 流程:通过 js 创建画笔
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

    <style type="text/css">
        *{
            margin: 0;
            /* 外边距为 0,使 canvas 能够占满全屏 */
        }
        #canvas{
            background: linear-gradient(
                135deg,
                rgb(142,132,133) 0%,
                rgb(230,132,110) 100%
            );
            /* 创建线性渐变图像 */
        }
        
    </style>
</head>
<body>
    <canvas id="canvas" width="500" height="500"></canvas>

    <script>
        var cxt=canvas.getContext('2d');// 创建了画笔
        cxt.beginPath();// 开始画
        cxt.closePath();// 画完了
        
        cxt.fillStyle='#f2f';
        cxt.arc(250,250,100,0,2*Math.PI,false);
        cxt.fill();
    </script>
</body>
</html>
  • 在创建线性渐变图像时,若 100% 后边加“,”,谷歌便加载不出来;若不加,便能加载出来。但是不知道为何
  • 这里尤其注意 js 里 canvas 的流程,创建画笔 -》开始画 -》画完了 -》补充颜色、形状信息。其中前三步都是套路,只有如何去画根据任务的不同,代码不同

Web Audio APi 流程

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <audio id="audio" src="mp3/1.mp3" controls></audio>

    <script>
        
        
        var oCtx=new AudioContext();// 创建音频对象

        var oAudio=document.querySelector('audio');
        var audioSrc=oCtx.createMediaElementSource(oAudio);
        // 给音频对象创建媒体源

        var analyser=oCtx.createAnalyser();// 创建分析机
        audioSrc.connect(analyser);// 把分析机连接到媒体源上
        analyser.connect(oCtx.destination);// 把分析机得到的结果和扬声器相连

    </script>
</body>
</html>
  • 这里要注意的是,audio 中的 autoplay、js 中的 audio.play()已经失效(谷歌浏览器的安全策略:声音不能自动播放,必须在用户有了操作后才能播放)
  • 上述流程中少了最关键的一步:如何分析音频数据,这一步根据实现的任务不同,内容不同。但是其余的步骤都是一样的,满满的套路

动态音频图的开发

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style type="text/css">
        *{margin: 0;}
        #canvas{
            background:linear-gradient(
                135deg,
                rgb(142,132,133) 0%,
                rgb(230,132,110) 100%
            );
        }
    </style>
</head>
<body>
    <audio id="audio" src="mp3/1.mp3" controls></audio>
    <button type="button" onclick="play()"></button>
    <canvas id="canvas"></canvas>

    <script>
        // 先引入 canvas 画笔的创建流程
        var cCxt=canvas.getContext('2d');// 创建 2D 画笔
        cCxt.beginPath();// 开始画
        cCxt.closePath();// 画完了

        // 设计画布的样式
        // 设置画布大小为整个屏幕
        canvas.width=window.innerWidth;
        canvas.height=window.innerHeight;
        // 设置线条的渐变颜色
        var oW=canvas.width; var oH=canvas.height;
        var color=cCxt.createLinearGradient(oW/2,oH/2,oW/2,oH/2-100);
        color.addColorStop(0,'#000');
        color.addColorStop(.5,'#069');
        color.addColorStop(1,'#f6f');

        
        function play(){
            // 先引入 API 函数, 走完 Web Audio API 的流程
            var oCtx=new AudioContext();// 创建音频对象
            var oAudio=document.querySelector('audio');
            var audioSrc=oCtx.createMediaElementSource(oAudio);// 为音频对象创建媒体源
            var analyser=oCtx.createAnalyser();// 为音频对象创建分析机
            audioSrc.connect(analyser);// 将分析机与媒体源连接
            analyser.connect(oCtx.destination);// 将分析机与扬声器相连接
            var count=80;// 音频条的条数
            var voiceHeight=new Uint8Array(analyser.frequencyBinCount);// 建立一个数据缓冲区(此时为空)
        
            setInterval(draw(analyser,voiceHeight,count),1000);
            oAudio.play();}

        function draw(analyser,voiceHeight,count){analyser.getByteFrequencyData(voiceHeight);// 将当前频率数据传入到无符号字节数组中,进行实时连接
            var step=Math.round(voiceHeight.length/count);// 每隔 step 个数,取一个数组里的数
            for(var i=0;i<count;i++){var audioHeight=voiceHeight[step*i];
                cCxt.fillStyle=color;
                cCxt.fillRect(oW/2+(i*10),oH/2,7,-audioHeight);
                cCxt.fillRect(oW/2-(i*10),oH/2,7,-audioHeight);
             }
           //console.log(voiceHeight);
        }
        

        
    </script>
</body>
</html>
  • 上边的代码是不可行的,找了一下午也没找出错误到底出在哪里 … 问题主要如下:

(1)在谷歌浏览器中,显示歌在播放,但是没有声音。console.log(voiceHeight)即图中注释部分没有注释掉时,voiceHeight 只出现一次,而不是 1000ms 出现一次。没有图像

(2)在 edge 浏览器中,歌曲能正常播放。voiceHeight 仍然只出现一次,没有图像

还望各路大神解惑


退出移动版