Web Audio API之手把手教你用web api处理声音信号:可视化音乐demo
1.Web Audio API 介绍
Web Audio API 提供了在Web上控制音频的一个非常有效通用的系统 ,这些通用系统通俗的讲就是我们可以利用Web Audio API提供的各种方法操作各种源中的声音,处理声音,使声音可视化等。
要使用Web Audio API,我们还是先来简单的了解一下它的工作流程:
- 创建音频环境(eg. AudioContext..)
- 在音频环境里创建源 — 例如
, 振荡器, 流(eg. navigator.getUserMedia/createMediaElementSource..) - 创建效果节点,例如混响、双二阶滤波器、平移、压缩(Web Audio API 提供一些简单的滤波器或者延时器等,可以制作一个简单的混音工具)
- 为音频选择一个目地,例如你的系统扬声器
- 连接源到效果器,以及效果器和目地(分析和可视化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 | 未实现 | 未实现 | 6 |
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的更多相关文章
- 手把手教你把web应用丢到服务器上(单页应用+ 服务端渲染)
前两篇文章中,我分别介绍了框架的搭建利用vue-cli + vant搭建一个移动端开发模板,并且把项目中axios请求和vuex的用法做了简要的介绍如何在项目里管理好axios请求与vuex.在这两篇 ...
- 手把手教你入门web.xml:吃透监听器
监听器的原理: 被监听对象→对象拥有的事件→捕获到事件变化→监听器捕捉事件→监听器处理该事件 Web服务器上有4个范围,抛开page范围,还有request范围,session范围,applicati ...
- 手把手教你搭建WEB服务器和FTP服务器
注:本次教程的环境是在“Windows 10 PC中远程控制的Windows Server 2012 R2服务器”,你可以自己在自己电脑中安装虚拟机再安装Windows Server 2012 R2服 ...
- 手把手教你用Python网络爬虫获取网易云音乐歌曲
前天给大家分享了用Python网络爬虫爬取了网易云歌词,在文尾说要爬取网易云歌曲,今天小编带大家一起来利用Python爬取网易云音乐,分分钟将网站上的音乐down到本地. 跟着小编运行过代码的筒子们将 ...
- 【Web Audio API】 — 那些年的 web audio
转 TAT.Jdo:[Web Audio API] - 那些年的 web audio 这主题主要是早期对 web audio api的一些尝试,这里整理一下以便以后翻阅,如有错误,诚请指正. 在这之前 ...
- 手把手教你如何优雅的使用Aop记录带参数的复杂Web接口日志
前言 不久前,因为需求的原因,需要实现一个操作日志.几乎每一个接口被调用后,都要记录一条跟这个参数挂钩的特定的日志到数据库.举个例子,就比如禁言操作,日志中需要记录因为什么禁言,被禁言的人的id和各种 ...
- 【HTML5】Web Audio API打造超炫的音乐可视化效果
HTML5真是太多炫酷的东西了,其中Web Audio API算一个,琢磨着弄了个音乐可视化的demo,先上效果图: 项目演示:别说话,点我! 源码已经挂到github上了,有兴趣的同学也可以去st ...
- 关于HTML5音频——audio标签和Web Audio API各平台浏览器的支持情况
对比audio标签 和 Web Audio API 各平台浏览器的支持情况: audio element Web Audio API desktop browsers Chrome 14 Yes ...
- [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 ...
随机推荐
- HashMap 阅读
最近研究了一下java中比较常见的map类型,主要有HashMap,HashTable,LinkedHashMap和concurrentHashMap.这几种map有各自的特性和适用场景.使用方法的话 ...
- 技本功丨知否知否,Redux源码竟如此意味深长(上集)
夫 子 说 元月二号欠下袋鼠云技术公号一篇关于Redux源码解读的文章,转眼月底,期间常被“债主”上门催债.由于年底项目工期比较紧,于是债务就这样被利滚利.但是好在这段时间有点闲暇,于是赶紧把这篇文章 ...
- 有个AI陪你一起写代码,是种怎样的体验?| 附ICLR论文
从前,任何程序的任何功能,都需要一行一行敲出来. 后来,程序猿要写的代码越来越多,世界上便有了各种各样的API,来减少大家的工作量.有些功能,可以让API来帮我们实现. 不过,人类写下的话,API并不 ...
- UVa 455 - Periodic Strings - ( C++ ) - 解题报告
1.题目大意 求一个长度不超过80的字符串的最小周期. 2.思路 非常简单,基本就是根据周期的定义做出来的,几乎不需要过脑. 3.应该注意的地方 (1) 最后输出的方式要注意,不然很容易就PE了.不过 ...
- mybatis 枚举类型使用
一.首先定义接口,提供获取数据库存取的值得方法,如下: public interface BaseEnum { int getCode(); } 二.定义mybatis的typeHandler扩展类, ...
- Python的top-level脚本为什么在磁盘上没有对应的字节码?
在Python中,如果你使用python script.py这样的方式运行Python脚本,那么script.py就被称为top-level脚本.对于Python来说,这个脚本的字节码是不会写入到磁盘 ...
- 如果Python对于磁盘没有写入权限,还会运行吗?
Python如果对于磁盘没有写入权限,那么编译成功的字节码文件就只会存储在内存当中,而不会写入到磁盘,每次运行Python都会重新编译,然后运行.
- jquery delayLoading.js插件的延迟加载效果和图片延迟加载
1.首页给大家介绍一下这款插件的主要用途 主要应用于图片的延迟加载,而且可以变换不同的延迟加载效果,适合相册图片.有做相册的可以考虑应用. 2.兼容IE7以上都兼容,其他的浏览器也兼容.所以说兼容性还 ...
- setsockopt 设置socket 详细用法
1.closesocket(一般不会立即关闭而经历TIME_WAIT的过程)后想继续重用该socket:BOOL bReuseaddr=TRUE;setsockopt(s,SOL_SOCKET ,SO ...
- Prepare方法和UnPrepare方法
Query组件提供的Prepare方法的作用是通知BDE或数据库服务器优化并准备执行SQL操作.Query的Prepare方法能优化执行的原因在于该方法是是在SQL语句执行前就对其进行分析.检查和编译 ...