#include "stdafx.h"
#include <time.h>
#include <windows.h>
#include<mmsystem.h>
#include<mmreg.h>
#pragma comment(lib, "winmm.lib")
struct RIFF_HEADER//文件类型
{
char szRiffID[4]; // 'R','I','F','F'
DWORD dwRiffSize;//DWORD最大可容纳4GB的文件大小=FILE_LENGTH-8(即减去此数据结构大小)
char szRiffFormat[4]; // 'W','A','V','E'
};
struct WAVE_FORMAT
{
WORD wFormatTag;
WORD wChannels;
DWORD dwSamplesPerSec;
DWORD dwAvgBytesPerSec;
WORD wBlockAlign;
WORD wBitsPerSample;
};
struct FMT_BLOCK
{
char szFmtID[4]; // 'f','m','t',' '
DWORD dwFmtSize;
WAVE_FORMAT wavFormat;
};
struct DATA_BLOCK
{
char szDataID[4]; // 'd','a','t','a'
DWORD dwDataSize;
};
//struct FACT_BLOCK//可先项 一般可不用
//{
// char szFactID[4]; // 'f','a','c','t'
// DWORD dwFactSize;
//};
WAVEFORMATEX pwfx; //声音格式
#define MAX_RUN_COUNT 4
#define BUFFER_COUNT 4
#define MAX_BUFF_SOUNDSIZE 10240
FILE *fptmp;
CHAR m_cBufferIn[BUFFER_COUNT][MAX_BUFF_SOUNDSIZE];
WAVEHDR m_pWaveHdrIn[BUFFER_COUNT];
HWAVEIN phwi; //设备句柄
bool is_stop = false;
void WaveInitFormat(LPWAVEFORMATEX m_WaveFormat, WORD nCh, DWORD nSampleRate, WORD BitsPerSample)
{
m_WaveFormat->wFormatTag = WAVE_FORMAT_PCM;
m_WaveFormat->nChannels = nCh;
m_WaveFormat->nSamplesPerSec = nSampleRate;
m_WaveFormat->nAvgBytesPerSec = nSampleRate * nCh * BitsPerSample / 8;
m_WaveFormat->nBlockAlign = m_WaveFormat->nChannels * BitsPerSample / 8;
m_WaveFormat->wBitsPerSample = BitsPerSample;
m_WaveFormat->cbSize = 0;
}
DWORD CALLBACK MicCallback(HWAVEIN hwavein, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
switch (uMsg)
{
case WIM_OPEN: //打开设备时消息,在此期间我们可以进行一些初始化工作
printf("\n设备已经打开...\n");
break;
case WIM_DATA: //当缓存已满或者停止录音时的消息,处理这个消息可以对缓存进行重新分配,实现不限长度录音
{
WAVEHDR*p = ((PWAVEHDR)dwParam1); // 这就是采集到的数据指针
DWORD len = p->dwBytesRecorded; // 这就是采集到的数据长度
int i = p->dwUser;
if (is_stop) //停止
{
waveInUnprepareHeader(phwi, p, sizeof(WAVEHDR)); //释放
return 0;
}
printf("\n缓冲区%d存满...\n", p->dwUser);
fwrite(&m_cBufferIn[i], 1, p->dwBytesRecorded, fptmp);
waveInUnprepareHeader(phwi, p, sizeof(WAVEHDR)); //释放
p->lpData = m_cBufferIn[i];
p->dwBufferLength = MAX_BUFF_SOUNDSIZE;
p->dwBytesRecorded = 0;
p->dwUser = i;
p->dwFlags = 0;
waveInPrepareHeader(phwi, p, sizeof(WAVEHDR)); //准备内存块录音
waveInAddBuffer(phwi, p, sizeof(WAVEHDR)); //增加内存块
break;
}
case WIM_CLOSE: //关闭录音设备时的消息
printf("\n设备已经关闭...\n");
break;
default:
break;
}
return 0;
}
//录音函数
void Start()
{
//获取声卡数
int count = waveInGetNumDevs();//1
printf("\n音频输入数量:%d\n", count);
//获取声音输入设备
WAVEINCAPS waveIncaps;
MMRESULT mmResult = waveInGetDevCaps(0, &waveIncaps, sizeof(WAVEINCAPS));//2
printf("\n音频输入设备:%s\n", waveIncaps.szPname);
//如果正确获取到输入设备
if (MMSYSERR_NOERROR == mmResult)
{
/// HWAVEIN phwi; //设备句柄
// WAVEFORMATEX pwfx;
WaveInitFormat(&pwfx, 1, 8000, 8);
printf("\n请求打开音频输入设备");
printf("\n采样参数:单声道 8kHz 8bit\n");
//打开录音设备
mmResult = waveInOpen(&phwi, WAVE_MAPPER, &pwfx, (DWORD)(MicCallback), NULL, CALLBACK_FUNCTION);//3
//如果正确打开了设备
if (MMSYSERR_NOERROR == mmResult)
{
for (int i = 0; i < BUFFER_COUNT; i++)
{
m_pWaveHdrIn[i].lpData = m_cBufferIn[i];
m_pWaveHdrIn[i].dwBufferLength = MAX_BUFF_SOUNDSIZE;
m_pWaveHdrIn[i].dwBytesRecorded = 0;
m_pWaveHdrIn[i].dwUser = i;
m_pWaveHdrIn[i].dwFlags = 0;
mmResult = waveInPrepareHeader(phwi, &m_pWaveHdrIn[i], sizeof(WAVEHDR));//4
printf("\n准备缓冲区%d\n", i + 1);
}
//数据头准备完成
if (MMSYSERR_NOERROR == mmResult)
{
for (int i = 0; i < BUFFER_COUNT; i++)
{
mmResult = waveInAddBuffer(phwi, &m_pWaveHdrIn[i], sizeof(WAVEHDR));//5
printf("\n将缓冲区%d加入音频输入设备\n", i + 1);
}
//数据块准备完成
if (MMSYSERR_NOERROR == mmResult)
{
//开始录音
mmResult = waveInStart(phwi);//6
printf("\n请求开始录音\n");
}
}
}
}
}
void Stop()
{
is_stop = true;
Sleep(3000); //等待录音完成
printf("Start Stop\n");
waveInStop(phwi);
printf("Start Reset\n");
waveInReset(phwi);
printf("Start Close\n");
waveInClose(phwi);
fclose(fptmp);
}
void Save()
{
long len = 0;
char *buf = NULL;
FILE *fp;
if (fopen_s(&fp, "temp.dat", "rb") == 0)
{
fseek(fp, 0, SEEK_END);;
len = ftell(fp);
fseek(fp, 0, SEEK_SET);
buf = new char[len + 1];
memset(buf, 0, sizeof(char)*(len + 1));
fread(buf, len, 1, fp);
fclose(fp);
}
if (buf == NULL)
{
printf("save error\n");
return;
}
if (fopen_s(&fp, "output.wav", "wb") == 0)
{
RIFF_HEADER riff;
WAVE_FORMAT wform;
FMT_BLOCK fmt;
//FACT_BLOCK fact;
DATA_BLOCK data;
memset(&riff, 0, sizeof(RIFF_HEADER));
memset(&wform, 0, sizeof(WAVE_FORMAT));
memset(&fmt, 0, sizeof(FMT_BLOCK));
//memset(&fact, 0, sizeof(FACT_BLOCK));
memset(&data, 0, sizeof(DATA_BLOCK));
fmt.wavFormat.wFormatTag = WAVE_FORMAT_PCM;//1
fmt.wavFormat.dwAvgBytesPerSec = pwfx.nAvgBytesPerSec;
fmt.wavFormat.dwSamplesPerSec = pwfx.nSamplesPerSec;
fmt.wavFormat.wBitsPerSample = pwfx.wBitsPerSample;
fmt.wavFormat.wBlockAlign = pwfx.nBlockAlign;
fmt.wavFormat.wChannels = pwfx.nChannels;
memcpy(fmt.szFmtID, "fmt ", 4);
fmt.dwFmtSize = 16;//一般情况下为16,如有附加信息为18
memcpy(data.szDataID, "data", 4);
data.dwDataSize = len;
riff.dwRiffSize = (len + sizeof(FMT_BLOCK) + sizeof(DATA_BLOCK));
memcpy(riff.szRiffFormat, "WAVE", 4);
memcpy(riff.szRiffID, "RIFF", 4);
fwrite(&riff, sizeof(RIFF_HEADER), 1, fp);//写RIFF_HEADER
fwrite(&fmt, sizeof(FMT_BLOCK), 1, fp);//写FMT_BLOCK
fwrite(&data, sizeof(DATA_BLOCK), 1, fp);//写数据头 DATA_BLOCK
fwrite(buf, len, 1, fp);
fclose(fp);
}
}
DWORD WINAPI TimeThread(LPVOID wPame)
{
Sleep(10000);
return 0;
}
int main(void)
{
errno_t errno;
errno = fopen_s(&fptmp, "temp.dat", "wb");
if (errno != 0)
{
printf("临时文件创建失败..\n");
return 0;
}
Start();
HANDLE hThread = CreateThread(NULL, NULL, TimeThread, NULL, NULL, NULL);
WaitForSingleObject(hThread, INFINITE); //等待计时线程执行完成
Stop();
Save();
system("pause");
return 0;
}