语音文件
PCM
我们在音频处理的时候经常会接触到PCM数据:它是模拟音频信号经模数转换(A/D变换)直接形成的二进制序列,该文件没有附加的文件头和文件结束标志。
声音本身是模拟信号,而计算机只能识别数字信号,要在计算机中处理声音,就需要将声音数字化,这个过程叫经模数转换(A/D变换)。最常见的方式是透过脉冲编码调制PCM (Pulse Code Modulation) 。
运作原理如下:首先我们考虑声音经过麦克风,转换成一连串电压变化的信号,如下图所示。这张图的横座标为秒,纵座标为电压大小。
要将这样的信号转为 PCM 时,需要将声音量化,我们一般从如下几个维度描述一段声音:
1.声道数 2.采样位数 3.采样频率 4.时长
采样频率:即取样频率,指每秒钟取得声音样本的次数。采样频率越高,声音的质量也就越好,声音的还原也就越真实,但同时它占的资源比较多。由于人耳的分辨率很有限,太高的频率并不能分辨出来。在16位声卡中有22KHz、44KHz等几级,其中,22KHz相当于普通FM广播的音质,44KHz已相当于CD音质了,目前的常用采样频率都不超过48KHz。
采样位数:即采样值或取样值(就是将采样样本幅度量化)。它是用来衡量声音波动变化的一个参数,也可以说是声卡的分辨率。它的数值越大,分辨率也就越高,所发出声音的能力越强。
声道数:很好理解,有单声道和立体声之分,单声道的声音只能使用一个喇叭发声(有的也处理成两个喇叭输出同一个声道的声音),立体声的PCM 可以使两个喇叭都发声(一般左右声道有分工) ,更能感受到空间效果。
时长: 采样的时长
下面再用图解来看看采样位数和采样频率的概念。让我们来看看这几幅图。
图中的黑色曲线表示的是PCM 文件录制的自然界的声波,
红色曲线表示的是PCM 文件输出的声波,
这个图中,采样点是离散的,每一个点对应pcm一个单元的数据。
采样频率越高,x轴采样点就越密集,声音越接近原始数据
采样位数越高,y轴采样点就越密集,声音越接近原始数据
采样频率单位为Hz,表示每秒采样的次数:
一般有11025HZ(11KHz)、22050HZ(22KHz)、44100Hz(44KHz)三种。
采样位数单位为bit(位),一般有 8bit 和 16bit 。8bit 表示用 8bit 空间量化某时刻的声音,这一点基本是和图片用r、g、b三单位共 24bit 量化颜色一样。
综上所述,我们可以得到pcm文件的体积计算公式(这里我们把 采样位数/8 是因为电脑上是将bit转化为byte):
存储量
存储量 = (采样频率 × 采样位数/8) × 声道 × 时间.
每个采样数据记录的是振幅,采样精度取决于储存空间的大小。
1字节(8bit)只能记录256个数,也就是只能将振幅划分到256个等级。
2字符(16bit)可以记录个数,将振幅划分到65536个等级,是CD的标准。
4字节(32bit)细分到个数, 没有必要,太精细了。
以8k 16bit音频为例、采样率8k=8000个采样点/秒。
16bit音频是16位。每8位一个字节,所以16bit是两个字节。
上面的是单声道(nomo),如果是双声道,所有信息全部×2
时间是这个音频的秒数
例如,数字激光唱盘(CD-DA,红皮书标准)的标准采样频率为44.l kHz,采样数位为16 位,立体声(2声道),可以几乎无失真地播出频率高达22 kHz的声音,这也是人类所能听到的最高频率声音。激光唱盘一分钟音乐需要的存储量为:
(44.1*1000* l6 *2)*60/8=10,584,000(字节)=10.584 M Bytes
这个数值就是 PCM 声音文件在硬盘中所占磁盘空间的存储量。
单双声道
数据以二进制序列储存在文件里
单声道8bit (1字节): 声音
双声道8bit (2字节): 左声道 右声道
单声道8bit (2字节): 声音低字节 声音高字节
单声道16bit(4字节): 左音道低字节 左声道高字节 右声道低字节 右声道高字节
双声道音频的存储方式是LRLRLRLR,16bit音频是每个声道都是16bit(2字节)么?PCM是interleaved的方式存储,具体存储的时候还有小端(little endian)和 (big endian)的问题,一般的存储是小端的,也就是2字节,低位在前,高位在后一个采样点16位是0x 1234 存储的时候是 0x34 和 0x12 , 如果是大端就反过来。
一个单声道的pcm无头音频1M ,转成 双声道就变成2M了,就算是有一条声道没信息(或者微弱信号噪声),但是 转成双声道的时候就算是静音,数据大小是0x0000他也是要占着位数的,所以不管怎样,只要是双声道就会变成2倍大小。
WAV和PCM的关系
前面也介绍到了,PCM 数据本身只是一个裸码流,它是由声道、采样位数、采样频率、时长共同决定的,因此我们至少要知道其中的三个才能将 PCM 所代表的数据提取出来。
因此,纯PCM数据是无法播放的,因此还需要一段描述数据。计算机系统中的一个比较常见的做法是将pcm码流和描述信息封装在一起,形成一个音频文件。这样就可以直接播放了。
一种常见的方式是使用wav格式定义的规范将pcm码流和描述信息封装起来。查看 pcm 和对应wav文件的 hex(16进制)文件,可以发现,wav文件只是在pcm文件的开头多了44字节 ,来表征其声道数、采样频率和采样位数等信息。这个其实和bmp非常类似。
多种音频格式
WAV、G729、G723 、MP3 等音频格式都是8k 16bit wav音频经过压缩的格式。
由于厂商众多、 很多音频格式 应运而生,比如nice公司出品的 nmf 其实音频,其实就是一个经过多层再包装的g729;vox 格式是华为公司出品的音频。
VOX格式
vox 格式是华为的格式、他的后缀一种是 V3 的,直接把后缀改成vox就可以听;还有一种后缀就是vox。
vox格式因为本身是没有头信息的看不到,所以不知道采样率不能转码、这时候用 cooledit 打开听一下,选择8k的采样率打开如果语速很快音频实际是6k;如果选择6k的采样率打开如果语速很快音频实际是8k。现在 得知采样率之后就可以用工具转码,下面会说到工具ffmpeg以及他的轻量版sox。
G729
G729以10字节作为一个解码单元,G729转码时先把头去掉再转。
G729是十六倍压缩。8k 16bit 8kb/s (正常是128kb/s 压缩16倍)
MP3
和g729一样是16倍压缩,但是由于压缩算法不一样,G729的频谱是光滑的、而MP3音频的损失很多。是最差的一种音频格式。
Alaw
8k 8bit stereo 128kb/s音频格式,应该是非压缩的格式
音频转码
首先音频格式之间转码,比如g729 转 mp3 流程是g729->8k、16bit wav -> mp3,都是要先经过wav的。
抓码工具
<1> 8k8bit nist --> 8k16bit pcm
sox -r 8000 -b 8 -c 1 -t nist 1.nist -s -r 8000 -b 16 1.wav dither
<2> wav->amr->wav
ffmpeg -i inFile1.wav -ab 12.2k outFile.amr
ffmpeg -i outFile.amr outFile.wav
or
ffmpeg -acodec libopencore_amrnb -i outFile.amr outFile.wav
<3> wav-alaw->wav
ffmpeg -i inFile1.wav -acodec pcm_alaw -ar 8000 outFile1.wav
ffmpeg -i outFile1.wav outFile.wav
<4> mulaw->wav
ffmpeg -i inFile.wav outFile.wav
<5> mp3->wav
ffmpeg -i inFile.mp3 outFile.wav
<6> alaw->wav
sox -e a-law alaw.wav -r 8000 -b 16 out.wav
<7> music.mp3 -> wav
ffmpeg -i music.mp3 -ar 8000 -ac 1 outFile.wav
<8> pcm add header -> wav
sox -s -t raw -r 8000 -c 1 -2 in.pcm out.wav
ffmpeg -acodec pcm_s16le -f s16le -ar 8000 -i in.pcm -ar 8000 -ac 1 -ab 128k out.wav
<9> sphere-->wav (wsj data)
sph2pipe 1.WV1 -f wav 1.wav
<10> vox-->wav
./ffmpeg -acodec adpcm_ima_oki -f s16le -ar 6000 -i 1211452.V3 12.wav
<11> two path->mono注:mono.wav -> 单声道 stereo.wav -> 双声道(立体声)
ffmpeg -i left.wav -i right.wav -filter_complex amix=inputs=2 mono.wav
ffmpeg -i left.wav -i right.wav -filter_complex "amovie=left.wav [l];amovie=right.wav [r]; [l] [r] amerge" stereo.wav
<12> stereo filter
ffmpeg -i fa.mp3 -map_channel 0.0.0 -ar 8000 -ab 128k left.wav -map_channel 0.0.1 -ar 8000 -ab 128k right.wav
<13> wav speed up #声音加速
ffmpeg -i 16k.wav -filter:a "atempo=1.75" 16k_fast.wav
<14>g729 tranfer
removeHead xx.V3 58 xx.g729
ffmpeg -acodec g729 -f g729 -i xx.g729 xx.wav
<15> nmf->g729->wav
./nmf2g729 1.nmf 1.nmf.g729ffmpeg -acodec g729 -f g729 -i xx.g729 xx.wav
sox
一般会内置的轻量级ffmpeg工具。
合并多个音频
sox 1.wav 2.wav 3.wav 1_2_3.wav
hexdump查看音频文件头信息
hexdump -Cv in.wav | less
音频头字节信息
标准音频的头字节是44位
查看音频字节信息是:hexdump -C in.wav
看红色部分
其中音频大小可以在第40-43位(从0位开始)倒着看是音频大小:0x 00 02 53 a0
转换成十进制是152480 加上标准头字节 44 是152524字节
查看音频的文件大小是152524字节 与计算结果吻合
其实看4-7位也行,4-7位查看下来是152516字节
152516+8=152524字节其实这个152516就是除了头字节的八个字节后面的字节数
看蓝色部分
第24-25位是0x 40 1f = 8k 这个位置标记的是音频的采样率大小标准音频的头字节是44位
PCM头信息
一个裸的PCM格式音频数据,如果不带头信息,不知道其采样率等相关信息,就无法用播放器播放出来。下面是默认的头信息格式:
//音频头部格式
struct wave_pcm_hdr
{
char riff[4]; // = "RIFF"
SR_DWORD size_8; // = FileSize - 8
char wave[4]; // = "WAVE"
char fmt[4]; // = "fmt "
SR_DWORD dwFmtSize; // = 下一个结构体的大小 : 16
SR_WORD format_tag; // = PCM : 1
SR_WORD channels; // = 通道数 : 1
SR_DWORD samples_per_sec; // = 采样率 : 8000 | 6000 | 11025 | 16000
SR_DWORD avg_bytes_per_sec; // = 每秒字节数 : dwSamplesPerSec *wBitsPerSample / 8
SR_WORD block_align; // = 每采样点字节数 : wBitsPerSample / 8
SR_WORD bits_per_sample; // = 量化比特数: 8 | 16
char data[4]; // = "data";
SR_DWORD data_size; // = 纯数据长度 : FileSize - 44
} ;
//默认音频头部数据
struct wave_pcm_hdr default_pcmwavhdr =
{
{ 'R', 'I', 'F', 'F' },
0,
{'W', 'A', 'V', 'E'},
{'f', 'm', 't', ' '},
16,
1,
1,
16000,
32000,
2,
16,
{'d', 'a', 't', 'a'},
0
};