• Web Audio API之手把手教你用web api处理声音信号:可视化音乐demo


    1.Web Audio API 介绍

           Web Audio API 提供了在Web上控制音频的一个非常有效通用的系统 ,这些通用系统通俗的讲就是我们可以利用Web Audio API提供的各种方法操作各种源中的声音,处理声音,使声音可视化等。

      要使用Web Audio API,我们还是先来简单的了解一下它的工作流程:

    1. 创建音频环境(eg. AudioContext..)
    2. 在音频环境里创建源 — 例如 , 振荡器, 流(eg. navigator.getUserMedia/createMediaElementSource..)
    3. 创建效果节点,例如混响、双二阶滤波器、平移、压缩(Web Audio API 提供一些简单的滤波器或者延时器等,可以制作一个简单的混音工具)
    4. 为音频选择一个目地,例如你的系统扬声器
    5. 连接源到效果器,以及效果器和目地(分析和可视化eg. AnalyserNode)

           其兼容性如下:

      桌面端

    浏览器 Chrome Firefox (Gecko) Internet Explorer Opera Safari (WebKit)
    支持版本 14 
    23 未实现 15 6

      移动端

    浏览器

    Android

    Chrome

    Firefox Mobile (Gecko)

    Firefox OS

    IE Phone

    Opera Mobile

    Safari Mobile

    支持版本 未实现 28 
    25 1.2 未实现 未实现

    2.示例代码

      "talking is cheap , show me the codes."

      我知道各位看官并不想听什么时域频域变换,什么傅立叶变换,什么web audio api原理,那我就废话不多说,直接放码过来了,先看看效果再来给大家解释。

      尽情复制粘贴,然后拿个现代一点的浏览器跑一下(用IE的请点右上角红叉,谢谢)。

          注意:audio标签的src属性内容请自己在本机找一个浏览器支持的声音源格式。

    <!DOCTYPE html>
    <html>
    <head>
    	<meta charset="UTF-8" />
    	<meta name="Author" contect="GabrielChen">
    	<meta name="keywords" contect="Web Audio API">
        <title>Web Audio API 学习</title>
        <script>
            var canvas;
            var ctx;
            var audioContext;
            var analyser;
            var mic;
    
            function init() {
                canvasOne = document.getElementById('canvasOne');
                ctx = canvasOne.getContext("2d");
                canvasTwo = document.getElementById('canvasTwo');
                ctx2 = canvasTwo.getContext("2d");
            
                
            }
          
            navigator.getMedia = ( navigator.getUserMedia ||
                    navigator.webkitGetUserMedia ||
                    navigator.mozGetUserMedia ||
                    navigator.msGetUserMedia);
    
            navigator.getMedia ( { audio: true }, function (stream) {
                audioContext = new (window.AudioContext || window.webkitAudioContext);
                
                mic = audioContext.createMediaStreamSource(stream);
               
                analyser= audioContext.createAnalyser();
               
                analyser.fftSize = 256;
                mic.connect(analyser);
                drawSpectrum();
            },function(){});
    
            
    
            function drawSpectrum() {
                var WIDTH = canvasOne.width;
                var HEIGHT= canvasOne.height;
    
                var array =  new Uint8Array(128);
                analyser.getByteFrequencyData(array);
                ctx.clearRect(0, 0, WIDTH, HEIGHT);
                ctx2.clearRect(0, 0, 800, 800);
                for ( var i = 0; i < (array.length); i++ ){
                    var value = array[i];
                    ctx.fillRect(i*5,HEIGHT-value,3,HEIGHT);
                }
    
              
                for ( var i = 0; i < (array.length); i++ ){
                    var value = array[i];
                    ctx2.beginPath();
    				ctx2.arc(300,300,value,0,360,false);
    				ctx2.lineWidth=5;
    				ctx2.strokeStyle="rgba("+value+","+value+",0,0.2)";
    				ctx2.stroke();//画空心圆
    				ctx2.closePath();
            
                }
                
                requestAnimationFrame(drawSpectrum);
            };
    
    
    
    
        </script>
        <style>
            #canvasOne {
                border: 1px solid #ddd;
            }
        </style>
    </head>
    <body onload="init();">
    <h1>从audio源获取声音</h1>
    <audio src="./Fatbros.ogg" controls="controls" id="audio">你的浏览器不支持audio标签</audio>
    <h1>audio读取声音</h1>
    <canvas id="canvasFormAudio" width="640"></canvas>
    <h1>频域图模仿</h1>
    <canvas id="canvasOne" width="640"></canvas>
    <h1>圆形声波图</h1>
    <canvas id="canvasTwo" width="800" height="800"></canvas>
    
    <script type="text/javascript">
    
    
            var context1;
            var source;
            var analyserfa;
            var canvasFormAudio;
            var ctxfa;
    
            canvasFormAudio = document.getElementById('canvasFormAudio');
            ctxfa = canvasFormAudio.getContext("2d");
            try {
           
        	 context1 = new (window.AudioContext || window.webkitAudioContext);
    		} catch(e) {
        	 throw new Error('The Web Audio API is unavailable');
    		}
    
    		analyserfa=context1.createAnalyser();
    
    		window.addEventListener('load', function(e) {
      	         var audio =document.getElementById("audio");
     		 var source = context1.createMediaElementSource(audio);
     		 source.connect(analyserfa);
      		 analyserfa.connect(context1.destination);
      	
      		 drawSpectrumfa();
      
    }, false);
            function drawSpectrumfa() {
                var WIDTH = canvasFormAudio.width;
                var HEIGHT= canvasFormAudio.height;
    
                var array =  new Uint8Array(128);
               
                analyserfa.getByteFrequencyData(array);
    
                ctxfa.clearRect(0, 0, WIDTH, HEIGHT);
               
                for ( var i = 0; i < (array.length); i++ ){
                    var value = array[i];
               ctxfa.fillRect(i*5,HEIGHT-value,3,HEIGHT);
                }
    
             	
                requestAnimationFrame(drawSpectrumfa);
            }
    </script>
    </body>
    </html>
    

      

      

    3.代码分析

    我们从body部分入手分析

    <body onload="init();">
    <h1>从audio源获取声音</h1>
    <audio src="./Fatbros.ogg" controls="controls" id="audio">你的浏览器不支持audio标签</audio>
    <h1>audio读取声音</h1>
    <canvas id="canvasFormAudio" width="640"></canvas>
    <h1>频域图模仿</h1>
    <canvas id="canvasOne" width="640"></canvas>
    <h1>圆形声波图</h1>
    <canvas id="canvasTwo" width="800" height="800"></canvas>
    

    用onload属性调用初始化函数init(),主要在页面生成之后初始化一些变量,避免读不到相关DOM。

           function init() {
                canvasOne = document.getElementById('canvasOne');
                ctx = canvasOne.getContext("2d");
                canvasTwo = document.getElementById('canvasTwo');
                ctx2 = canvasTwo.getContext("2d");
            
                
            }
    

    第一块canvas:从audio源获取声音

    首先一个audio标签,在本机选定一个src,设置controls属性代表浏览器显示播放器控制页面,设置id为audio。

    再设置一个id为"canvasFormAudio"的画布canvas。

    <audio src="./Fatbros.ogg" controls="controls" id="audio">你的浏览器不支持audio标签</audio>
    <h1>audio读取声音</h1>
    <canvas id="canvasFormAudio" width="640"></canvas>
    

    获取声音源以及绘图

    //直接从audio处理音频源,声明一些必要的变量
            var context1;
            var source;
            var analyserfa;
            var canvasFormAudio;
            var ctxfa;
    //初始化画布
            canvasFormAudio = document.getElementById('canvasFormAudio');
            ctxfa = canvasFormAudio.getContext("2d");
    //建立一个音频环境,因为浏览器实现不同,做了一点兼容性处理 try { context1 = new (window.AudioContext || window.webkitAudioContext); } catch(e) { throw new Error('The Web Audio API is unavailable'); } //建立一个分析器 analyserfa=context1.createAnalyser(); window.addEventListener('load', function(e) { // 从audio标签获取声音源 source var audio =document.getElementById("audio"); var source = context1.createMediaElementSource(audio); source.connect(analyserfa); analyserfa.connect(context1.destination); //调用绘图函数 drawSpectrumfa(); }, false);
          //绘图函数 function drawSpectrumfa() { var WIDTH = canvasFormAudio.width; var HEIGHT= canvasFormAudio.height; var array = new Uint8Array(128); //复制当前的频率值到一个无符号数组中 analyserfa.getByteFrequencyData(array); //clearRect(矩形左上角x坐标,矩形左上角y坐标,清除矩形的宽,清除矩形的高) ctxfa.clearRect(0, 0, WIDTH, HEIGHT); //循环生成长条矩形 for ( var i = 0; i < (array.length); i++ ){ var value = array[i]; //fillRect(矩形左上角x坐标,矩形左上角y坐标,矩形宽,矩形高)
             //这里我们的array一共有128组数据,所以我们当时canvas设置的宽度为5*128=640 ctxfa.fillRect(i*5,HEIGHT-value,3,HEIGHT); } //根据浏览器频率绘图或者操作一些非css效果 requestAnimationFrame(drawSpectrumfa); }

      

    第二块:频域图模仿和圆形声波图

    这两个图的音源都是利用浏览器调用电脑麦克风取得,所以一定要同意浏览器请求的麦克风权限。

    绘图区域

    <h1>频域图模仿</h1>
    <canvas id="canvasOne" width="640"></canvas>
    <h1>圆形声波图</h1>
    <canvas id="canvasTwo" width="800" height="800"></canvas>
    

    初始化init()函数、从麦克风获取音源和绘图函数

            var canvas;
            var ctx;
            var audioContext;
            var analyser;
            var mic;
    //初始化两个画布的函数,声明为2d绘图
            function init() {
                canvasOne = document.getElementById('canvasOne');
                ctx = canvasOne.getContext("2d");
                canvasTwo = document.getElementById('canvasTwo');
                ctx2 = canvasTwo.getContext("2d");
            
                
            }
           //getMedia调用参数如下,返回一个多媒体流
        //constraints可选{ video: true, audio: true },代表获取多媒体的类型
    //var stream = navigator.getUserMedia(constraints, successCallback, errorCallback); navigator.getMedia = ( navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia); navigator.getMedia ( { audio: true }, function (stream) { audioContext = new (window.AudioContext || window.webkitAudioContext); //返回一个多媒体流 mic = audioContext.createMediaStreamSource(stream); //creates an AnalyserNode 创建一个分析节点 analyser= audioContext.createAnalyser(); //fftsize默认值2048,是快速傅立叶变换用于频域分析的值,必须为2的幂,而我们得到的数据通常为其的一半,下面会说道 analyser.fftSize = 256; mic.connect(analyser);
          //调用绘图函数 drawSpectrum(); },function(){});      //圆形声波绘图和矩形绘图 function drawSpectrum() { var WIDTH = canvasOne.width; var HEIGHT= canvasOne.height;        //长度为128无符号数组用于保存getByteFrequencyData返回的频域数据 var array = new Uint8Array(128); analyser.getByteFrequencyData(array);
           //以下是根据频率数据画图,主要为canvas知识,不做详细解答 ctx.clearRect(0, 0, WIDTH, HEIGHT); ctx2.clearRect(0, 0, 800, 800); for ( var i = 0; i < (array.length); i++ ){ var value = array[i]; ctx.fillRect(i*5,HEIGHT-value,3,HEIGHT); } //ctx2.clearRect(700, 700, WIDTH, HEIGHT); for ( var i = 0; i < (array.length); i++ ){ var value = array[i]; ctx2.beginPath(); ctx2.arc(300,300,value,0,360,false); ctx2.lineWidth=5; ctx2.strokeStyle="rgba("+value+","+value+",0,0.2)"; ctx2.stroke();//画空心圆 ctx2.closePath(); } // requestAnimationFrame(drawSpectrum); };

     

    4.最终效果

     

    6.最新进展

      文中的getMedia方法(getUserMedia)在chrome 47后已经不可以从非安全源访问(Insecure Origins),即http协议,.firefox还可以但不知道为什么有bug,几秒钟后就share设备失败。

      现在chrome开发者可以使用以下方法继续在非安全源使用这个函数:

      You can run chrome with the --unsafely-treat-insecure-origin-as-secure="example.com" flag (replacing "example.com"with the origin you actually want to test), which will treat that origin as secure for this session. Note that you also need to include the --user-data-dir=/test/only/profile/dir to create a fresh testing profile for the flag to work

     

    7.参考

    1.MDN

    2.api接口查询

    3.chrome

      

  • 相关阅读:
    关于Linux联网的问题
    MapD的数据导出与扩容(利用现有的表)
    系统重启后,MapD报错Thrift的连接被拒绝
    关于Linux系统只读(Ubuntu16.4.1)
    javaBean的依赖注入中构造注入和依赖注入的区别
    Struts2开发中遇到的坑。。。
    通过配置文件设置定时任务,以及时间的选择
    微信小程序开发的movable开发的坑
    spring基础概念
    Hibernate的三种查询方式
  • 原文地址:https://www.cnblogs.com/gabrielchen/p/5078760.html
Copyright © 2020-2023  润新知