本系列文章主要是介绍 Web Audio API 的相关知识,以及 web语音通信 中会遇到的一些问题,阐述可能存在错误,还请多多斧正!

很多粤语剧都提供了两个声道,一个左声道为粤语,一个右声道有国语。观看者可以自由切换声道,那么切换声道的原理是什么呢?在播放器中,只需要把不同的声道切换到声轨就行了,因为有左右两个声道,所以播放器至少是包含两个声轨的。如果我们想听粤语,只需要将右声道声轨的声音设置为 0,或者临时删掉右声道声轨。本文主要是利用 GainNode 节点控制音量的属性实现两个音轨之间的相互切换,Cross-fading 的意思可以在后面的 DEMO 中用耳朵体会出来~

本文地址:http://www.cnblogs.com/hustskyking/p/webAudio-cross-fading.html,转载请注明源地址。

P.S:请在较新版的 chrome 火狐 Firefox 中测试。

一、两个声音之间的声轨切换

1. 原理介绍

在一个 AudioContext 中可以输入多个音频流,而这些音频流在 AudioContext 这个环境中辗转反侧,最后的出路也就是 DestinationNode:

source 1 ---+

|----> Destination

source 2 ---+

而要实现上面两个声轨的切换,实则是它容易了,我们可以在他们到达 Destination 之前,加一个 GainNode,上文 已经对 GainNode 做了详细的说明,本文就不继续赘述了。

2. DEMO 演示

首先要创建两个音频,平时我们都是使用 audio 节点带上 src 属性,插入到 DOM 中让其自动播放音频,本文将使用其他的方式拿到音频流:

var tank = new Audio("http://qianduannotes.duapp.com/file/tankWar.mp3");

我准备了两个音频,一个是 tankWar.mp3 ,经典的坦克大战开场音乐,另一个是 SuperMario.mp3,超级玛丽的背景音乐,前者稍微短一些,所以在播放的时候将其设定为循环播放:

tank.loop = true;

然后利用 createMediaElementSource 这个函数从 Media 中获取到音频流:

var source1 = context.createMediaElementSource(tank);

过程十分简单,整个 AudioContext 的连接模型为:

source 1 --> GainNode 1 -+

|----> Destination

source 2 --> GainNode 2 -+

然后用同一个控制棒来控制 GainNode 1 和 2。

<input type="range" min="0" max="100" id="volume" />
<script type="text/javascript">
var tank = new Audio("http://qianduannotes.duapp.com/file/tankWar.mp3");
tank.loop = true;
var mario = new Audio("http://qianduannotes.duapp.com/file/SuperMario.mp3");
mario.loop = true; var AudioContext = AudioContext || webkitAudioContext;
var context = new AudioContext();
var source1 = context.createMediaElementSource(tank);
var source2 = context.createMediaElementSource(mario);
var gain1 = context.createGain();
var gain2 = context.createGain();
//连接:source → gain → destination
source1.connect(gain1);
source2.connect(gain2);
gain1.connect(context.destination);
gain2.connect(context.destination);
//音量控制
var value;
onload = volume.onchange = function(){
gain1.gain.value = volume.value / 100;
gain2.gain.value = 1 - volume.value / 100;
}; tank.onload = mario.onlond = function(){
console.log("var1, var2");
}
tank.play();
mario.play(); </script>

代码没有封装,写的稍微有些乱,不过看了之前的说明,应该可以理解这段代码~

3. 效果增强

上面的音量控制,我使用的是线性控制:

gain1.gain.value = volume.value / 100;
gain2.gain.value = 1 - volume.value / 100;

效果并不是特别好,他对音量的控制如下图:

稍微修改下控制函数:

var vol = volume.value / 100;
gain1.gain.value = Math.cos(vol * 0.5 * Math.PI);
gain2.gain.value = Math.cos((1.0 - vol) * 0.5 * Math.PI);

可以感受到音量的变化是这样的:

详情可以戳这个demo:http://qianduannotes.duapp.com/demo/audio/

二、小结

本文的目的是介绍 Web Audio API 的 GainNode 节点的使用,并将此应用到声道的切换之中,上面的例子不能算是严格的声道切换,但如果我们只给 volume 参数设定 0 ,50, 100 这三个值,那效果跟声道的切换就差不多了~

由于这几篇文章都是关于 Node 之间的相互连接,技术含量并不多,主要是读懂 API 以及相关使用方法。行文仓促,如有错误地方,还请斧正!

三、参考资料

[Voice communications] 声道的转换的更多相关文章

  1. [Voice communications] 声音的滤波

    本系列文章主要是介绍 Web Audio API 的相关知识,以及 web语音通信 中会遇到的一些问题,阐述可能存在错误,还请多多斧正! 通过设备获取音频流会不可避免的渗入一些杂音,这些杂音可能来自你 ...

  2. [Voice communications] 音量的控制

    改变音频的音量是音频处理中最基础的部分,我们可以利用 GainNode 来构建 Mixers 的结构块.GainNode 的接口是很简单的: interface GainNode : AudioNod ...

  3. [Voice communications] 看得到的音频流

    上文介绍了 Web Audio API 的相关知识,以及如何在你的 web 程序中引入 音频流,内容都是介绍性的,所以没有写太多 DEMO.本文重点讲解如何利用 Web Audio API 中的中间节 ...

  4. [Voice communications] 让音乐响起来

    本系列文章主要是介绍 Web Audio API 的相关知识,由于该技术还处在 web 草案阶段(很多标准被提出来,至于取舍需要等待稳定版文档来确定,草案阶段的文档很多都会被再次编辑甚至重写.全部删除 ...

  5. (Step by Step)How to setup IP Phone Server(VoIP Server) for free.

    You must have heard about IP Phone and SIP (Software IP Phone).Nowadays standard PSTN phone are bein ...

  6. Unity声音-音源组件

    音源组件(AudioSource) 音源是场景中在某个位置的发声装置,好像一个喇叭.它播放着音频片段 (Audio Clip). 发出的声音将输出到声音监听器(audio listener),或者声音 ...

  7. 每日英语:5 Things to Know About Missing Malaysia Airlines Flight and Air Safety

    Malaysia Airlines Flight MH370, with 239 people aboard, lost contact early Saturday with the airline ...

  8. XAudio2学习之调节音调

    频率比有两个地方能够设置.一个是在创建IXAudio2SourceVoice对象的时候.一个是调用IXAudio2SourceVoice::SetFrequencyRatio来调节. 在创建IXAud ...

  9. 转载:P2P技术原理及应用(1)

    转帖allen303allen的空间 作 者:金海 廖小飞 摘要:对等网络(P2P)有3种主要的组织结构:分布式哈希表(DHT)结构.树形结构.网状结构.P2P技术已 经延伸到几乎所有的网络应用领域, ...

随机推荐

  1. CheetSheet

    显示端口占用 lsof -i tcp:port sublime 添加到命令行别名 alias subl=\''/Applications/Sublime Text 2.app/Contents/Sha ...

  2. Qt基本框架介绍

    #include <QApplication>#include <QWidget> int main(int argc, char *argv[]){ QApplication ...

  3. LinkedList源码阅读笔记(基于JDK1.8)

    LinkedList是List接口的一个有序链表实现,存储节点是内部类Node,Node中有两个属性prev和next,负责连接前后两个元素.由于不是使用数组进行存储,所以查询需要遍历链表一半的元素( ...

  4. Beginning Scala study note(8) Scala Type System

    1. Unified Type System Scala has a unified type system, enclosed by the type Any at the top of the h ...

  5. 追踪记录每笔业务操作数据改变的利器——SQLCDC

    对于大部分企业应用来用,有一个基本的功能必不可少,那就是Audit Trail或者Audit Log,中文翻译为追踪检查.审核检查或者审核记录.我们采用Audit Trail记录每一笔业务操作的基本信 ...

  6. 【Centos】修改网卡名字&随之出现的问题

    自从学了工具tcpdump之后,里面会需要涉及到针对某个网卡抓包,因而会输入网卡名字,可是centOS7蛋疼的网卡默认命名实在是让人心碎,所以就想到了要修改网卡名字,步骤如下:(以下步骤涉及到我的错误 ...

  7. 指定eclipse启动使用的JVM

    不同eclispe对运行时要求不一样,而一台电脑只能同时使用一个运行时,当多个要求不同版本jvm的eclipse需要在一台电脑工作时,需要手动指定eclipse启动使用的jvm. [eclipse-j ...

  8. Ubuntu 树莓派2b交叉编译环境

    在一个平台上生成另一个平台上的可执行代码.为什么要大费周折的进行交叉编译呢?一句话:不得已而为之.有时是因为目的平台上不允许或不能够安装所需要的编译器,而又需要这个编译器的某些特征:有时是因为目的平台 ...

  9. delay(和setTimeout()的区别

    近来几日在写游戏代码时,频繁会用到定时器,偶尔想到有个.delay()方法,用了几次发现两者效果相差很大,遂就仔细考究了一下两者的区别! 1. setTimeout函数是从页面开始的时候计算time的 ...

  10. JQ 常见demo

    使用 hide() 和 show() 方法来隐藏和显示 HTML 元素: <!DOCTYPE html> <html> <head> <script src= ...