音频参数
经常见到这样的描述: 44100HZ 16bit stereo 或者 22050HZ 8bit mono 等等.
- 44100HZ 16bit stereo:
每秒钟有 44100 次采样, 采样数据用 16 位(2字节)记录, 双声道(立体声);
- 22050HZ 8bit mono:
每秒钟有 22050 次采样, 采样数据用 8 位(1字节)记录, 单声道;
什么是PCM音频数据
PCM(Pulse Code Modulation)也被称为脉冲编码调制。
PCM音频数据是未经压缩的音频采样数据裸流,它是由模拟信号经过采样、量化、编码转换成的标准的数字音频数据。
PCM数据存储格式
PCM数据存储格式
本文中声音样值的采样频率一律是44100Hz,采样格式一律为16LE。
“16”代表采样位数是16bit。由于1Byte=8bit,所以一个声道的一个采样值占用2Byte。
“LE”代表Little Endian,代表2 Byte采样值的存储方式为高位存在高地址中。
立体声的左右声道的数据是一样的吗?
原来一直理解立体声的左右声道是一样的,但是通过查看实际的数据,发现并不一样。比如:
从以上可以看出,刚开始的4个字节是同一个采样点,其中0x04e8是左声道,0x01c9是右声道,发现是不一样的。
通过cool edit pro查看波形:
可以看出左右声道,虽然波形相似,但是的确存在不同。
PCM Examples
以下代码可读取pcm文件,并演示了打印采样点的值和将立体声分离成左声道和右声道。
#include "stdafx.h"
#include <fstream>
#include <iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
// Read file to buffer
char szFileName[256] = {0};
sprintf_s(szFileName, ".\\44100_stereo_s16le.pcm");
ifstream inFile(szFileName, ios::in | ios::binary | ios::ate);
long nFileSizeInBytes = inFile.tellg();
char *pszPCMBuffer = new char[nFileSizeInBytes];
inFile.seekg(0, ios::beg);
inFile.read(pszPCMBuffer, nFileSizeInBytes);
inFile.close();
cout<<"FileName: " << szFileName <<", nFileSizeInBytes: " << nFileSizeInBytes <<endl;
cout << "Read file to a buffer Done!!!\n\n";
// 从文件中读取采样点并打印
short szItem[1024] = {0};
memcpy(szItem, pszPCMBuffer, 256);
for (int i = 0; i < 128; i++)
{
printf("%6d ", szItem[i]);
if ((i + 1) % 8 == 0)
{
cout<<endl;
}
}
// 将双声道分离成左声道和右声道
FILE *fpLeft = fopen("44100_mono_s16le_l.pcm","wb+");
FILE *fpRight = fopen("44100_mono_s16le_r.pcm","wb+");
printf("\n Split stereo to left and right ...\n");
for (int nPos = 0; nPos < nFileSizeInBytes; )
{
if ((nPos / 2) % 2 == 0) // 偶数
{
if (fpLeft)
{
fwrite(pszPCMBuffer + nPos, 1, 2, fpLeft);
}
}
else
{
if (fpRight)
{
fwrite(pszPCMBuffer + nPos, 1, 2, fpRight);
}
}
nPos += 2;
}
if (fpLeft)
{
fclose(fpLeft);
fpLeft = NULL;
}
if (fpRight)
{
fclose(fpRight);
fpRight = NULL;
}
printf("\n Split stereo to left and right Done. \n");
if (pszPCMBuffer)
{
delete [] pszPCMBuffer;
pszPCMBuffer = NULL;
}
getchar();
return 0;
}
References:
http://blog.csdn.net/ownwell/article/details/8114121
http://blog.csdn.net/leixiaohua1020/article/details/50534316
https://www.cnblogs.com/CoderTian/p/6657844.html