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

  

Web Audio API之手把手教你用web api处理声音信号:可视化音乐demo的更多相关文章

  1. 手把手教你把web应用丢到服务器上(单页应用+ 服务端渲染)

    前两篇文章中,我分别介绍了框架的搭建利用vue-cli + vant搭建一个移动端开发模板,并且把项目中axios请求和vuex的用法做了简要的介绍如何在项目里管理好axios请求与vuex.在这两篇 ...

  2. 手把手教你入门web.xml:吃透监听器

    监听器的原理: 被监听对象→对象拥有的事件→捕获到事件变化→监听器捕捉事件→监听器处理该事件 Web服务器上有4个范围,抛开page范围,还有request范围,session范围,applicati ...

  3. 手把手教你搭建WEB服务器和FTP服务器

    注:本次教程的环境是在“Windows 10 PC中远程控制的Windows Server 2012 R2服务器”,你可以自己在自己电脑中安装虚拟机再安装Windows Server 2012 R2服 ...

  4. 手把手教你用Python网络爬虫获取网易云音乐歌曲

    前天给大家分享了用Python网络爬虫爬取了网易云歌词,在文尾说要爬取网易云歌曲,今天小编带大家一起来利用Python爬取网易云音乐,分分钟将网站上的音乐down到本地. 跟着小编运行过代码的筒子们将 ...

  5. 【Web Audio API】 — 那些年的 web audio

    转 TAT.Jdo:[Web Audio API] - 那些年的 web audio 这主题主要是早期对 web audio api的一些尝试,这里整理一下以便以后翻阅,如有错误,诚请指正. 在这之前 ...

  6. 手把手教你如何优雅的使用Aop记录带参数的复杂Web接口日志

    前言 不久前,因为需求的原因,需要实现一个操作日志.几乎每一个接口被调用后,都要记录一条跟这个参数挂钩的特定的日志到数据库.举个例子,就比如禁言操作,日志中需要记录因为什么禁言,被禁言的人的id和各种 ...

  7. 【HTML5】Web Audio API打造超炫的音乐可视化效果

    HTML5真是太多炫酷的东西了,其中Web Audio API算一个,琢磨着弄了个音乐可视化的demo,先上效果图: 项目演示:别说话,点我!  源码已经挂到github上了,有兴趣的同学也可以去st ...

  8. 关于HTML5音频——audio标签和Web Audio API各平台浏览器的支持情况

    对比audio标签 和 Web Audio API 各平台浏览器的支持情况:   audio element Web Audio API desktop browsers Chrome 14 Yes  ...

  9. [Javascript] Intro to the Web Audio API

    An introduction to the Web Audio API. In this lesson, we cover creating an audio context and an osci ...

随机推荐

  1. 关于GitHub推送时发生Permission denied (publickey)的问题

    今天在学习廖雪峰老师官网的git教程“添加远程库”时发现总是推送失败,下边提示“Permission denied (publickey) 这个问题” 传送门:https://www.liaoxuef ...

  2. [原创]Docker学习记录: Shipyard+Swarm+Consul+Service Discover 搭建教程

    网上乱七八糟的资料实在是太多了, 乱, 特别乱, 而看书呢, 我读了2本书, 一本叫做<>, 另一本叫做<< Docker进阶与实战>> 在 服务发现这块讲的又不清 ...

  3. 普通Java类获取Spring的Bean的方法

    普通Java类获取Spring的Bean的方法 在SSH集成的前提下.某些情况我们需要在Action以外的类中来获得Spring所管理的Service对象. 之前我在网上找了好几好久都没有找到合适的方 ...

  4. POJ 2177 Ghost Busters(三维几何)

    Description The famous Ghost Busters team has decided to upgrade their Ectomobile (aka Ecto-1) with ...

  5. HDU 1042 N!(高精度乘)

    Problem Description Given an integer N(0 ≤ N ≤ 10000), your task is to calculate N!   Input One N in ...

  6. HDU 1569 方格取数(2)(最大流最小割の最大权独立集)

    Description 给你一个m*n的格子的棋盘,每个格子里面有一个非负数. 从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大.   ...

  7. 自测之Lesson14:多线程编程

    题目:创建一个线程,并理清主线程结束时会发生什么. 代码: #include <stdio.h> #include <pthread.h> #include <unist ...

  8. coding.net 版本控制

    这是版本测试的所有内容,其中用到了  git 和coding的远程连接. 代码及版本控制 git地址:https://git.coding.net/tianjiping/11111.git

  9. About Dynamic Programming

    Main Point: Dynamic Programming = Divide + Remember + Guess 1. Divide the key is to find the subprob ...

  10. C++计算器项目的初始部分(第三次作业)

    C++计算器项目的初始部分 项目源文件地址:calculator 项目信息: * 项目名称:Calculator * 项目实现: * 对四则运算表达式进行拆解 * 对拆解的表达式进行简单的错误判断 * ...