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 ...
随机推荐
- Java进阶知识点:不要只会写synchronized - JDK十大并发编程组件总结
一.背景 提到Java中的并发编程,首先想到的便是使用synchronized代码块,保证代码块在并发环境下有序执行,从而避免冲突.如果涉及多线程间通信,可以再在synchronized代码块中使用w ...
- Centos7下安装mysql服务
yum install -y perl-Module-Install.noarch yum -y install perl perl-devel #命令下载mysql wget http://dev. ...
- [Install] TeamViewer
安装TeamViwer 1. $ sudo apt-get -f install 2. 使用gdebi安装TeamViwer. 所以先安装gdebi package. $ sudo apt-get i ...
- ARM架构中的程序执行与调用
ARM架构中的程序执行与调用 1. 几个名词 ABI : 可执行文件必须遵守的规范,以在特定执行环境中运行: 单独产生的可重定址的文件必须遵守的规范,以用来链接和执行. EABI: 适用于嵌入式环境的 ...
- Python高级编程-序列化
在程序运行的过程中,所有的变量都是在内存中,比如,定义一个dict: dict1 = {'name': 'Rob', 'age': 19, 'score': 90} 可以随时修改变量,比如把age改成 ...
- 自测之Lesson9:时钟与信号
题目一:编写一个获取当前时间的程序,并将其以“year-mon-day time”的形式输出. 程序代码: #include <stdio.h> #include <time.h&g ...
- Catch That Cow(BFS广搜)
Description Farmer John has been informed of the location of a fugitive cow and wants to catch her i ...
- c# word 删除指定内容
1.首先简单的是获取得到的range,直接rangge.delete() 2.文本框的删除: foreach (Microsoft.Office.Interop.Word.Shape shape in ...
- (beta冲刺5/7)
团队信息 队名:爸爸饿了 组长博客:here 作业博客:here 组员情况 组员1(组长):王彬 过去两天完成了哪些任务 推进后端完成安卓端接口的开发 在测试中发现返回地图接口存在错误(待修复) 推进 ...
- java中 i = i++和 j = i++ 的区别
由于i++和i--的使用会导致值的改变,所以在处理后置的++和--的时候,java的编译器会重新为变量分配一块新的内存空间,用来存放原来的值, 而完成赋值运算之后,这块内存会被释放. (1)对于j = ...