最近的工作涉及到语音识别相关的研究,因此先简单的梳理一下WAV格式和PCM。以前用c++实现了mp3 player,这个时候再来回顾下代码实现,将WAV的播放 看了下。
什么是PCM
直接上百度百科的定义:PCM(Pulse Code Modulation)脉冲编码调制是数字通信的编码方式之一。主要过程是将话音、图像等模拟信号每隔一定时间进行取样,使其离散化,同时将抽样值按分层单位四舍五入取整量化,同时将抽样值按一组二进制码来表示抽样脉冲的幅值。
简单的说,PCM就是直接对原始的模拟声波信号 进行 采样 后得到的 数据
什么是 采样率 sample rate
采样率 是 指 一秒钟 从脉冲 信号 中 采样了 多少个 sample
举例: sample rate: 16000 HZ ,意思是一秒钟 从 脉冲信号中 采样16000个点(sample)
什么是比特率 bits per second
从字面定义,即:一秒钟的声音信号 占有的比特数。
简言之:比特率 表征 采样的 数据 的 信息逼真程度,比特率越高,数据的逼真程度越高。
使用 alsa sound 进行 pcm 数据的播放
关于alsa sound
从网上找了alsa sound的解释如下:ALSA(Advanced Linux Sound Architecture)是linux上主流的音频结构,在没有出现ALSA架构之前,一直使用的是OSS(Open Sound System)音频架构。
简单的说,alsa sound是linux下的音频框架,使用alsa sound的 接口,即可以播放pcm数据。这里,正好可以用这个接口,来体验pcm的声音效果,以便有个 真切的 将pcm传到 电脑喇叭的 声音 体验
使用 alsa soun 播放pcm
- 计算320ms的pcm数据长度,因为我的代码是每次播放320ms长度的sample数据,所以先计算出320ms的采样数据长度。
直接给出公式如下:
简单的说下:
sample_rate 标识1秒的采样的sample数,单声道的采样数=采样率,双声道的采样数=采样率*channel数。 320ms的采样数 = 1秒的采样数*320/1000 = 采样率*声道数*32/100
samples_per_320ms_ = header_.sample_rate*header_.channels*32/100;
wav格式
以.wav为后缀的文件就是wav格式的文件,先上百度百科的定义:是微软公司专门为Windows开发的一种标准数字音频文件,该文件能记录各种单声道或立体声的声音信息,并能保证声音不失真。
简单的说:WAV文件就是在PCM数据前加了个PCM的信息说明头,仅此而已
这个头部数据占有字节内容如下:
资料领取直通车:音视频开发&流媒体服务器资料文档+视频教程https://docs.qq.com/doc/DTm5idlJ1Y1dWZFZU
音视频学习直通车:【免费】FFmpeg/WebRTC/RTMP/NDK/Android音视频流媒体高级开发https://ke.qq.com/course/3202131?flowToken=1042584
RIFF 4个字节
UNKNOWN 4个字节,
WAVE 4 bytes
fmt 4bytes
UNKNOWN 4bytes
采样率、声道数、比特率、一个sample占的bit数 16bytes
extra 2bytes //根据chunk_size == 18才有
fact 4bytes
data 4bytes
UNKNOWN 4bytes
---------------
到这一步,就计算出接下来PCM数据的长度,接下来的位置就是PCM数据了
最后附播放alsa sound 播放pcm的源码
class WAVParser {
public:
typedef struct {
int format_tag;
int channels;
unsigned int sample_rate;
unsigned int bit_rate;
int block_align;
int bits_per_sample;
int data_pos;
int data_size;
}FrameHeader;
typedef struct {
int Init(const FrameHeader& header);
}FrameInfo;
static int GetFrame(const