在前端的世界里,我们对声音的印象一般停留在vedio上,其实js里有一个webAudio的API,它可以用来播放,分析,处理声音。今天给大家讲解一下用webAudio做录音的相关知识,先来一睹为快:

webAudio录音和PCM和WAV相关知识 gif webAudio录音和PCM和WAV相关知识

上面是已经写好的demo,大家可以自行测试,现在大家可能对下拉框里面选择的参数没有什么概念,不过大家可以先玩玩看,参数大概的意思就是用来控制录音的音质的,后面会讲到。

如果你是第一次打开,可能会弹出下面的东西:

这里你需要点击允许,因为录音需要获取麦克风权限,这里浏览器询问你是否可以使用你的麦克风,如果你点击不允许的话,是没有录音效果的。

允许之后,浏览器的右上角就会出现上面的图标,表示现在正在录音中。

注:这个只在chrome上有效果。

运行流程

声音通过麦克风会产生一连串的电压变化,可以得到许多[-1,1]之间的数字,然后这些数字怎么才能播放呢?第一步是需要转换成PCM格式。

PCM格式通过三个参数来描述,采样频率,采样位数,声道数。

background Layer 1 水平方向为采样频率 垂直方向为采样位数 图1 图2

大家应该都知道,声音是一个波,PCM的核心思想就是水平和垂直分割成若干小块,然后用这些坐标上的点近似的描述一个波(声音)。其中的水平分割叫做采样频率,垂直分割交采样位数。

大家可以看到上图,图2的切割明显比图1的更小,所以,图2的能够更加准确的描述一个声音。

采样频率的一般数值为 44100(44kHZ),22050(22kHZ),11025(11kHZ),相当于单位时间内采集44100,22050,11025等次样本。采样位数一般为8位和16位,这里的8和16代表的是2^8和2^16,意思就是将垂直方向划分成256和65536份。

采样频率为44100,采样位数16,代表CD音质;采样频率为22050,采样位数16,代表广播音质;采样频率为11025,采样位数8,代表电话音质。

background Layer 1 0 1 2 3 4 255 254 253 252 8位的将垂直位置分成0到255,一共256份 0 1 2 3 4 32767 32766 32765 32764 . . . . . . . . . . . . . . . -1 -2 -3 -4 -32768 -32767 -32766 -32765 16位的将垂直位置分成-32768到32767,共65536份

对于采样位数,我们需要注意的是,8位的是划分成2^8=256份,它的范围是0-255;16位的划分的是2^16=65536份,范围是-32768到32767。这个将是我们接下来处理数据的依据。因为我们收集的数据范围在[-1,1],那么你想转换成16位的话,只需要对负数*32768,对正数*32767,即可得到范围在[-32768,32767]的数据。对于8位的话,负数*128,正数*127,然后整体向上平移128(+128),即可得到[0,255]范围的数据。

16位的虽然比8位的保存的更加精确,不过空间也要大1倍,因为1个字节8位,如果存采样位数为8的,一个字节刚好放一个信息,可是如果是采样位数为16的,需要两个字节来存储一个信息。

background Layer 1 采样1 采样2 采样3 8位1声道 采样1 采样1 采样2 8位2声道 采样2 采样3 采样3 左声道 右声道 左声道 右声道 左声道 右声道 16位1声道 8位的一个采样占用一个字节 采样1 采样2 采样3 3个字节 6个字节 16位2声道 采样1 采样1 采样2 采样2 采样3 采样3 16位的一个采样占用两个字节 6个字节 12个字节 左声道 右声道 左声道 右声道 左声道 右声道

声道这个概念相对简单一些,有单声道和双声道的区别,上图从存储的角度描述了单,双声道在存储上的区别。可以看到,对于单声道来说,基本比较简单,一个采样放一个坑(8位的占一个坑,16位的占两个坑);双声道的话,就是左右声道的数据交叉放,一个放左声道,一个放右声道,当然,不一定要先放左声道,先放右声道也是可以的,只要他们是交叉放就好,不分左右。

background Layer 1 假设输入的采样频率44100,那么就是说单位时间内收集44100个采样 假设输出的采样频率22050,那么就是说单位时间内输出22050个采样 相当于只是播放了收集的一半 最终会导致声音变慢一倍,并且只播放一半的声音

这里有一个比较难理解的就是输入采样频率和输出采样频率,特别是当它们不同的时候。

输入采样频率是指你的麦克风收集声音的频率,因为麦克风需要将波形的声音转换成[-1,1]的信号,意味着它也需要一个采样频率(假设是44100),用它来指定在单位时间内收集多少个样本。

输出采样频率就是单位时间内播放多少个采样。一般情况下,最好保持两个不变,但是实际中为了考虑存储空间因素,输出频率要小于采样频率(假设22050)。但是这样会导致声音变慢一倍,为什么?

看上图就可以知道,其实很简单,单位时间内,麦克风收集到了44100个样本,但是你用22050的频率去播放,那么单位时间内只能播放所有采样的一半,就好比波被拉长了一倍。

background Layer 1 假设输入的采样频率44100,那么就是说单位时间内收集44100个采样 将收集到的采样,每两个采样只保留第一个采样,删除第二个采样 当输出频率为22050的时候,刚好还是一个完整的波形,声音正常

解决方案就是将收集到的44100个采样,每两个中采样中删除第二个采样,保留第一个采样,这样就可以得到22050个采样,这样可以保持波形基本不变。简单一点的如下所示:

background Layer 1 收集到的采样(6个) 采样1 采样2 采样3 采样4 采样5 采样6 正常输出采样(3个) 采样1 采样2 采样3 每两个采样保留第一个采样,输出采样(3个) 采样1 采样3 采样5 声音变慢一倍,并且只能播放一半的声音 声音正常,但是没有之前清楚,因为损失了一半采样

代码难点

通过上面的讲解,你可能已经对整体流程有所了解,大致流程如下:

background Layer 1 麦克风 webAduio解释数据 将采样收集 采样变PCM PCM变WAV

获取麦克风还是比较简单的,关键代码如下:

接下来就是用webAudio来解释麦克风信息了,这里具体收集的是一个叫做createScriptProcessor的方法,它可以指定收集采样的大小,注意,这个和采样频率不同,采样频率是PCM里面的概念,这里的采样大小是createScriptProcessor里的第一个参数,数值一般为1024,2048,4096等,取不同的值对收集的效果是不同的,应该根据情况决定采样大小,这里我们为了方便,用的是4096。关键代码如下:

createScriptProcessord的第二,三个参数分别是输入的声道数和输出的声道数。这两个一般情况下保持一致即可。

现在webAduio和麦克风都准备好了,就差把它们链接起来了,这时候就要用到webAudio播放声音的一般套路了。

background Layer 1 声音源 过滤处理器 扬声器

这里的麦克风就相当于声音源,createScriptProcessor就相当于过滤处理器,用来监听从麦克风传来的数据。链接的关键代码如下:

链接完成后,createScriptProcessor的onaudioprocess方法可以持续不断的返回采样数据,这些数据范围在[-1,1]之间,类型是Float32。现在要做的就是将它们收集起来。注意这里有一个坑,就是你不能用一般的方法去收集采样,需要用Woker去收集,我尝试了很多次不用Worker去收集采样,但是最后的结果就是播放的声音是乱的。Worker可以让浏览器开一个稳定的线程去处理一些事情,很适合I/O流的处理。

当然,我们这里也不用一般的Woker去处理,我们用的是内联Woker,不懂得可以看看 worker和内联worker

收集完了之后,我们接下来就是转成PCM了,核心逻辑之前也讲过了,这里讲一个代码里面的一个比较坑的点:setInt16(offset,value,big-endian)。先来看看下面代码的运行结果是什么:

答案是1,2,2,1。想想是为什么?

background Layer 1 258的二进制为 100000010 现在要把它放入两个字节中,前面不足的用0补全 0000000100000010 00000010 00000001 因此getInt8(0)是1,getInt8(1)是2 setInt16(0,258),默认是big-endian,即高位字节放在低地址端 0000000100000010 00000010 00000001 因此getInt8(2)是2,getInt8(3)是1 setInt16(2,258,true),启用little-endian,即高位字节放在高地址端

这是因为在使用一个字节以上来存储内容的时候,存在little-endian和big-endian两种不同的存放数据的方法。注意的是,这里所有的存储都是使用little-endian的。

PCM是没有头信息的,为了可以播放音乐,这里需要转成WAV。转成WAV其实很简单,只要增加44个字节的头信息即可,头信息都是固定的,直接用即可,头信息关键代码如下:

最后

这个录音其实还是可以优化的,因为现在录音出来的wav格式的体积比较大,最好可以录成map3格式的,这个以后有空再研究研究。

DEMO下载

点击下载 [0积分]一共下载0

其他文章

0
我要评论

评论

返回
×

我要评论

回复:

昵称:(昵称不超过20个字)

图片:

提交
还可以输入500个字