#define _CRT_SECURE_NO_WARNINGS //避免时间函数报错
#include "CAdd_Recording.h" //系统自动生成的,啥内容都没有,空的。
#include <iostream>
#include <windows.h>
#include <ctime>
#pragma comment(lib, "winmm.lib")
time_t t = time(0);
static DWORD hasRecorded = 0; //记录已录入的数据大小
static BYTE* file = (BYTE*)malloc(sizeof(BYTE) * 512);
static FILE* f;
static BOOL flgRecored=TRUE; //true:继续录制,false:停止录制
class MyClass
{
public:
MyClass();
~MyClass();
std::string strDataName="ICBC";
int data=666;
private:
};
MyClass::MyClass()
{}
MyClass::~MyClass()
{}
//声明回调函数
void CALLBACK waveInProc(HWAVEIN hwi, // 设备句柄
UINT uMsg, // 消息
DWORD_PTR dwInstance, // 对象
DWORD_PTR dwParam1, // 参数1
DWORD_PTR dwParam2); // 参数2
//声明存储函数
void SaveRecord();
char* WideCharToMultiByte(wchar_t* pWCStrKey)//2023.04.27 新增WChar*转char*
{
//第一次调用确认转换后单字节字符串的长度,用于开辟空间
int pSize = WideCharToMultiByte(CP_OEMCP, 0, pWCStrKey, wcslen(pWCStrKey), NULL, 0, NULL, NULL);
char* pCStrKey = new char[pSize + 1];
//第二次调用将双字节字符串转换成单字节字符串
WideCharToMultiByte(CP_OEMCP, 0, pWCStrKey, wcslen(pWCStrKey), pCStrKey, pSize, NULL, NULL);
pCStrKey[pSize] = '\0';
return pCStrKey;
//如果想要转换成string,直接赋值即可
//string pKey = pCStrKey;
}//定义回调函数 //何时回调此函数(过程)? void CALLBACK waveInProc(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { MyClass* user = (MyClass*)dwInstance; WAVEHDR* head_L = (WAVEHDR*)dwParam1; switch (uMsg) { case WIM_CLOSE: printf("停止录音..\n"); SaveRecord(); break; case WIM_DATA: //缓冲区满的时候,触发 {//1.Sent when the device driver is finished with a data block //2.sent using the waveInAddBuffer function. printf("缓存区已满!\n"); //printf("用户数据:(%s,%d)\n", user->strDataName, user->data); std::cout << "用户数据:" <<"名字 " +user->strDataName << ",代号 "<<user->data << std::endl; //缓存池信息 DWORD bufLength = head_L->dwBufferLength; DWORD bytesReced = head_L->dwBytesRecorded; //已录入的数据的大小 hasRecorded += bytesReced; //存储.pcm方法 No.1: if (f) { fwrite(head_L->lpData, head_L->dwBytesRecorded, 1, f); } //扩充缓存 //malloc函数对没有分配过的内存块直接进行分配(初始化内存)。 //realloc函数是在已经分配好的内存块重新进行分配(格式化内存)。 file = (BYTE*)realloc(file, hasRecorded * sizeof(BYTE)); if (file) { memcpy(&file[hasRecorded - bytesReced], head_L->lpData, bytesReced); struct tm* now = localtime(&t); printf("简报:%d:%d:%d", now->tm_hour, now->tm_min, now->tm_sec); printf("已储存:%d byte \n", hasRecorded); } if (flgRecored) {//若继续录制,则增添缓存 waveInAddBuffer(hwi, head_L, sizeof(WAVEHDR)); struct tm* now = localtime(&t); printf("addBuf:%d:%d:%d \n", now->tm_hour, now->tm_min, now->tm_sec); } }//C++中的case里,若要初始化变量,必须使用{} break;
case WIM_OPEN:
printf("成功打开录音设备\n");
break;
default:
break;
}
}
//将数据写入指定的文件或输入/输出 (I/O) 设备。
//BOOL WriteFile(
// [in] HANDLE hFile,
// [in] LPCVOID lpBuffer,
// [in] DWORD nNumberOfBytesToWrite,
// [out, optional] LPDWORD lpNumberOfBytesWritten,
// [in, out, optional] LPOVERLAPPED lpOverlapped
//);
//实现存储函数
void SaveRecord()
{//存储为.pcm
if (file)
{ //或者存储方法 No.2:
//fwrite(file, hasRecorded, 1, f);
}
}
int main()
{
f=fopen("audio.pcm", "wb");
HWAVEIN hWaveIn; //device:input
HWAVEOUT hWaveOut; //deveice:output
WAVEFORMATEX waveform;
byte* pBuffer_Left, * pBuffer_Right;
WAVEHDR head_L, head_R,head_Out;
MyClass *user=new MyClass();
#pragma region Init_WaveDriver
///音频设备由设备标识符标识。 设备标识符是从系统中存在的设备数隐式确定的。
//设备标识符的范围从零到一个小于存在的设备数。 例如,如果系统中有两个波形音频输出设备,则有效的设备标识符为 0 和 1。
//疑惑:每次运行时,下面的MID、PID和设备设备DriverVersion等都是固定不变的,除了设备名称会变!
int count = waveInGetNumDevs();
printf("音频输入数量:%d\n", count);
WAVEINCAPS waveIncaps;
MMRESULT mmResult = waveInGetDevCaps(0, &waveIncaps, sizeof(WAVEINCAPS));
std::cout << "输入设备描述:"<<std::endl;
std::cout << "设备MID(VID):" << waveIncaps.wMid << std::endl;
std::cout << "设备PID:" << waveIncaps.wPid << std::endl;
//std::cout << "设备DriverVersion:" << waveIncaps.vDriverVersion << std::endl;
std::cout << "设备名称:" << WideCharToMultiByte(waveIncaps.szPname )<< std::endl;
//std::cout << "设备支持的标准格式:" << waveIncaps.dwFormats << std::endl;
//std::cout << "设备支持的声道(单声道1,立体声2):" << waveIncaps.wChannels << std::endl<<std::endl;
count = waveOutGetNumDevs();
printf("\n音频输出数量:%d\n", count);
WAVEOUTCAPS waveOutcaps, waveOutcaps2;
mmResult = waveOutGetDevCaps(0, &waveOutcaps, sizeof(WAVEOUTCAPS));
std::cout << "输出设备描述:" << std::endl;
std::cout << "设备MID(VID):" << waveOutcaps.wMid << std::endl;
std::cout << "设备PID:" << waveOutcaps.wPid << std::endl;
//std::cout << "设备DriverVersion:" << waveOutcaps.vDriverVersion << std::endl;
std::cout << "设备名称:" << WideCharToMultiByte(waveOutcaps.szPname) << std::endl;
//std::cout << "设备支持的标准格式:" << waveOutcaps.dwFormats << std::endl;
//std::cout << "设备支持的声道(单声道1,立体声2):" << waveOutcaps.wChannels << std::endl;
//std::cout << "设备支持的可选功能:" << waveOutcaps.dwSupport << std::endl<<std::endl;
mmResult = waveOutGetDevCaps(1, &waveOutcaps2, sizeof(WAVEOUTCAPS));
std::cout << "\n设备MID(VID):" << waveOutcaps2.wMid << std::endl;
std::cout << "设备PID:" << waveOutcaps2.wPid << std::endl;
//std::cout << "设备DriverVersion:" << waveOutcaps2.vDriverVersion << std::endl;
std::cout << "设备名称:" <<WideCharToMultiByte(waveOutcaps2.szPname) << std::endl;
//std::cout << "设备支持的标准格式:" << waveOutcaps2.dwFormats << std::endl;
//std::cout << "设备支持的声道(单声道1,立体声2):" << waveOutcaps2.wChannels << std::endl;
//std::cout << "设备支持的可选功能:" << waveOutcaps2.dwSupport << std::endl;
#pragma endregion
//注意初始化的顺序!!!
waveform.wFormatTag = WAVE_FORMAT_PCM;
waveform.nChannels = 2;
waveform.nSamplesPerSec = 44100;
waveform.wBitsPerSample = 16; //采样精度
waveform.nBlockAlign = (waveform.wBitsPerSample * waveform.nChannels) / 8; //块对齐
waveform.nAvgBytesPerSec = waveform.nBlockAlign * waveform.nSamplesPerSec; //平均传输速率:块*频率
waveform.cbSize = 0; //额外空间
pBuffer_Left = new BYTE[1024 * 10000];
pBuffer_Right = new BYTE[1024 * 10000];
memset(pBuffer_Left, 0, 1024 * 10000); //内存置为0;
memset(pBuffer_Right, 0, 1024 * 10000); //内存置为0;
head_L.lpData =(LPSTR) pBuffer_Left;
head_L.dwBufferLength = 1024 * 10000;
head_L.dwBytesRecorded = 0;
head_L.dwUser = 0;
head_L.dwFlags = 0;
head_L.dwLoops = 1; //循环的次数
head_R.lpData = (LPSTR)pBuffer_Right;
head_R.dwBufferLength = 1024 * 10000;
head_R.dwBytesRecorded = 0;
head_R.dwUser = 0;
head_R.dwFlags = 0;
head_R.dwLoops = 1; //循环的次数
//开始录音
MMRESULT mRet = waveInOpen(&hWaveIn, WAVE_MAPPER, &waveform, (DWORD_PTR)waveInProc, (DWORD_PTR)user, CALLBACK_FUNCTION);
waveInPrepareHeader(hWaveIn, &head_L, sizeof(WAVEHDR));
waveInPrepareHeader(hWaveIn, &head_R, sizeof(WAVEHDR));
waveInAddBuffer(hWaveIn, &head_L, sizeof(WAVEHDR));
waveInAddBuffer(hWaveIn, &head_R, sizeof(WAVEHDR));
waveInStart(hWaveIn);
//结束录音
getchar();
flgRecored = FALSE;
waveInReset(hWaveIn);
Sleep(500);
waveInClose(hWaveIn);
fclose(f);
//播放
HANDLE wait = CreateEvent(NULL, 0, 0, NULL);
waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveform, (DWORD_PTR)wait, 0L, CALLBACK_EVENT);
// 播放录音
head_Out.lpData = (LPSTR)file; // 指向buffer
head_Out.dwBufferLength = hasRecorded; // buffer大小
head_Out.dwBytesRecorded = hasRecorded;
head_Out.dwFlags = 0;
head_Out.dwLoops = 1;
ResetEvent(wait);
waveOutPrepareHeader(hWaveOut, &head_Out, sizeof(WAVEHDR));
waveOutWrite(hWaveOut, &head_Out, sizeof(WAVEHDR));
/*Sleep(5000);*/
DWORD dw = WaitForSingleObject(wait, INFINITE);
if (dw == WAIT_OBJECT_0)
{
std::cout << "jieshu" << std::endl;
return 0;
}
system("pause");
return 0;
}