一、音频格式总览
说到语音技术就不得不说起音频数据,从硬件设备采集语音信号,语音信号的处理,到语音信号A/D转换得到原始数据(raw data),再到对原始数据进行编码得到音频文件,对音频文件解码进行播放。那么为什么会出现如此多的音频格式?使用最多的几种音频格式有MP3、WMA、WAV、AAC、FLAC、APE、WV、ASF、VQF、MID、OGG、M4A、eAAC+。目前只用到了其中三种,故详细分析WAV、MP3、OGG。
二、原始数据(raw data,以PCM编码为例)
模拟音频信号经模数转换(A/D变换)直接形成的二进制序列,该文件没有附加的文件头和文件结束标志。而PCM(Pulse-code Modulation,脉冲编码调制)是一种模拟信号的数字化方法,常被用于数字电信系统中,非常频繁地,PCM编码以一种串行通信的形式,使数字传讯由一点至下一点变得更容易——不论在已给定的系统内,或物理位置。
PCM过程放在ALSA的实践中作为理论部分呈现,这里给出多通道音频数据的比特位特征。
图1 多通道音频数据的比特流格式
如图1所示,单通道音频数据以采样位数(bit)串行记录在比特流中:
1) 8 bit 采样位数: 意味着每个采样值能占据1个字节大小;
+------+------+------+------+------+------+------+------+------+
| 500 | 300 | -100 | -20 | -300 | 900 | -200 | -50 | 250 |
+------+------+------+------+------+------+------+------+------+
2)16 bit 采样位数:分为两个字节以小端(little-endian)方式存储在比特流中;
双通道及多通道数据音频数据以采样位数组织如下(n 为采样位数):
+-- n bit---+---n bit---+-----+---n bit---+---n bit--+------+--n bit---+---n bit---+----------+
| channel1 | channel2 | ... | channel1 | channel2 | ... | channel1 | channel2 | ... |
+----------+----------+---------+----------+---------+----------+---------+----------+----------+
PCM的每个样本值包含在一个整数i中,i的长度为容纳指定样本长度所需的最小字节数。首先存储低有效字节,表示样本幅度的位放在i的高有效位上,剩下的位置为0。
计算机读入原始音频数据的方式与打开二进制文件相同。
#include <stdio.h>
#include <stdlib.h>
int main()
{
char *fn;
char *data;
FILE *fp;
int len;
fn = "./test.pcm";
fp = fopen(fn, "rb");
if(!fp) {
printf("file open failed.\n");
exit(1);
}
fseek(fp, 0, SEEK_END);
len = ftell(fp);
if(!len) {
printf("file is null.\n");
fclose(fp);
exit(1);
}
printf("file len = %d\n",len);
data = (char *)malloc(len);
fseek(fp, 0, SEEK_SET);
fread(data, sizeof(__int16_t), len/sizeof(__int16_t), fp);
fclose(fp);
printf("%.*s\n",1,data);
free(data);
return 0;
}
三、wav文件
wav(Waveform Audio FIle Format),即波形声音文件,由微软公司开发,是最早的数字音频格式,音质与CD相差无几,但缺点是wav文件非常庞大,不利于数据传输。
struct waitor_wav_format
{
#pragma pack(1)
char riff_id[4]; // "RIFF",big-endian
__uint32_t file_len; // file length,little-endian
char wave_id[4]; // "WAVE“,big-endian
char fmt_id[4]; // "fmt",big-endian,beginning of fmt chunk
char transition[4]; // size of fmt chunk
__uint16_t fmt_type; // 1-PCM
__uint16_t channel; // 通道数
__uint16_t sample_rate; // 采样率
__uint32_t avg_bytes_per_sec; // sample_rate * block_align
__uint16_t block_align; // 每次采样大小
__uint16_t bit_per_second; // 采样精度
//__uint16_t cbsize // 附加