音频编码方式采用G711(应该是a-law,不确认),音频需要16位量化,8位量化编码音频失真。
#include <stdio.h>
#include <Windows.h>
#pragma comment(lib, "winmm.lib")
#define MAX (32635)
unsigned char encode(short pcm)
{
int sign = (pcm & 0x8000) >> 8;
if (sign != 0)
pcm = -pcm;
if (pcm > MAX) pcm = MAX;
int exponent = 7;
int expMask;
for (expMask = 0x4000; (pcm & expMask) == 0
&& exponent>0; exponent--, expMask >>= 1) { }
int mantissa = (pcm >> ((exponent == 0) ? 4 : (exponent + 3))) & 0x0f;
unsigned char alaw = (unsigned char)(sign | exponent << 4 | mantissa);
return (unsigned char)(alaw^0xD5);
}
short decode(unsigned char alaw)
{
alaw ^= 0xD5;
int sign = alaw & 0x80;
int exponent = (alaw & 0x70) >> 4;
int data = alaw & 0x0f;
data <<= 4;
data += 8;
if (exponent != 0)
data += 0x100;
if (exponent > 1)
data <<= (exponent - 1);
return (short)(sign == 0 ? data : -data);
}
//编码
int G711_EnCode(unsigned char* pCodecBits, const unsigned char* pBuffer, int nBufferSize)
{
short* buffer = (short*)pBuffer;
for(int i=0; i<nBufferSize/2; i++)
{
pCodecBits[i] = encode(buffer[i]);
}
return nBufferSize/2;
}
//解码
int G711_Decode(unsigned char* pRawData, const unsigned char* pBuffer, int nBufferSize)
{
short *out_data = (short*)pRawData;
for(int i=0; i<nBufferSize; i++)
{
out_data[i] = decode(pBuffer[i]);
}
return nBufferSize*2;
}
HWAVEIN hWaveIn; //输入设备
WAVEFORMATEX waveform; //采集音频的格式,结构体
BYTE *pBuffer1;//采集音频时的数据缓存
WAVEHDR wHdr1; //采集音频时包含数据缓存的结构体
FILE *pf;
int main(int argc, char * argv[])
{
HANDLE wait;
waveform.wFormatTag = WAVE_FORMAT_PCM;//声音格式为PCM
waveform.nSamplesPerSec = 8000;//采样率,16000次/秒
waveform.wBitsPerSample = 16;//采样比特,16bits/次
waveform.nChannels = 1;//采样声道数,1为单声道,2为双声道
waveform.nAvgBytesPerSec = 16000;//每秒的数据率,就是每秒能采集多少字节的数据
waveform.nBlockAlign = 2;//一个块的大小,采样bit的字节数乘以声道数 再除以8
waveform.cbSize = 0;//一般为0
wait = CreateEvent(NULL, 0, 0, NULL);
//使用waveInOpen函数开启音频采集
MMRESULT Result = waveInOpen(&hWaveIn, WAVE_MAPPER, &waveform,(DWORD)wait, 0L, CALLBACK_EVENT);
if (MMSYSERR_NOERROR == Result)
{
printf("Open Wave Success!\n");
}
else if (MMSYSERR_INVALHANDLE == Result)
{
printf("Get MMSYSERR_INVALHANDLE Error\n");
return 0;
}
else if (MMSYSERR_NODRIVER == Result)
{
printf("No Driver!\n");
return 0;
}
else if (MMSYSERR_NOMEM == Result)
{
printf("No Mem!\n");
return 0;
}
//建立两个数组(这里可以建立多个数组)用来缓冲音频数据
DWORD bufsize = 1024*1000;//每次开辟10k的缓存存储录音数据
int i = 20;
pf= fopen("录音测试.pcm", "wb");
FILE *pfEn = fopen("编码.pcm", "wb");
FILE *pfDe = fopen("解码.pcm", "wb");
while (i--)//录制20左右秒声音,结合音频解码和网络传输可以修改为实时录音播放的机制以实现对讲功能
{
pBuffer1 = new BYTE[bufsize];
wHdr1.lpData = (LPSTR)pBuffer1;
wHdr1.dwBufferLength = bufsize;
wHdr1.dwBytesRecorded = 0;
wHdr1.dwUser = 0;
wHdr1.dwFlags = 0;
wHdr1.dwLoops = 1;
waveInPrepareHeader(hWaveIn, &wHdr1, sizeof(WAVEHDR));//准备一个波形数据块头用于录音
waveInAddBuffer(hWaveIn, &wHdr1, sizeof (WAVEHDR));//指定波形数据块为录音输入缓存
waveInStart(hWaveIn);//开始录音
Sleep(1000);//等待声音录制1s
waveInReset(hWaveIn);//停止录音
unsigned char *pData = new unsigned char[bufsize];
unsigned char *pDataDe = new unsigned char[bufsize];
memset(pData,0, sizeof(pData));
int nRet = G711_EnCode(pData, pBuffer1, wHdr1.dwBytesRecorded);
fwrite(pBuffer1, 1, wHdr1.dwBytesRecorded, pf);
fwrite(pData, 1, nRet, pfEn);
int nTemp = nRet;
nRet = G711_Decode(pDataDe, pData, nTemp);
fwrite(pDataDe, 1, nRet, pfDe);
delete pBuffer1;
delete pData;
delete pDataDe;
printf("%ds ", i);
}
fclose(pf);
waveInClose(hWaveIn);
return 0;
}