windows api录音pcm

发布时间 2023-08-08 15:50:24作者: YiXiaoKezz

pcm.h

#pragma once
#include <cstdio>
#include <cstdint>
#include <Windows.h>
#pragma comment(lib,"winmm.lib")
class pcm
{
public:
	pcm();
	~pcm();

	void startRecording();
	void endRecording();

private:

	struct WavPCMFileHeader
	{
		struct RIFF
		{
			const    char rift[4] = { 'R','I', 'F', 'F' };
			uint32_t fileLength;
			const    char wave[4] = { 'W','A', 'V', 'E' };
		}riff;

		struct Format
		{
			const    char fmt[4] = { 'f','m', 't', ' ' };
			uint32_t blockSize = 16;
			uint16_t formatTag;
			uint16_t channels;
			uint32_t samplesPerSec;
			uint32_t avgBytesPerSec;
			uint16_t blockAlign;
			uint16_t  bitsPerSample;
		}format;

		struct  Data
		{
			const    char data[4] = { 'd','a', 't', 'a' };
			uint32_t dataLength;
		}data;

		WavPCMFileHeader() {}

		WavPCMFileHeader(int nCh, int  nSampleRate, int  bitsPerSample, int dataSize)
		{
			riff.fileLength = 36 + dataSize;
			format.formatTag = 1;
			format.channels = nCh;
			format.samplesPerSec = nSampleRate;
			format.avgBytesPerSec = nSampleRate * nCh * bitsPerSample / 8;
			format.blockAlign = nCh * bitsPerSample / 8;
			format.bitsPerSample = bitsPerSample;
			data.dataLength = dataSize;
		}
	};

	HWAVEIN         m_hWaveIn;		        //输入设备
	WAVEFORMATEX    m_waveform;	            //定义音频流格式
	BYTE*			m_pBuffer1;				//输入音频缓冲区(单声道)
	WAVEHDR         m_whdr_i1;				//输入音频头

	FILE*			m_pFile = nullptr;
	uint32_t		m_iTotalDataLength = 0;

	void initRecord();
};

pcm.cpp

#include "pcm.h"

pcm::pcm()
{
	initRecord();
}

void pcm::initRecord()
{
	// 设置音频流格式
	m_waveform.nSamplesPerSec = 16000;							// 采样率
	m_waveform.wBitsPerSample = 16;								// 采样精度
	m_waveform.nChannels = 1;									// 声道个数
	m_waveform.cbSize = 0;										// 额外空间	
	m_waveform.wFormatTag = WAVE_FORMAT_PCM;					// 音频格式
	m_waveform.nBlockAlign = 2;									// 块对齐
	m_waveform.nAvgBytesPerSec = 32000;							// 传输速率

	//最大60秒
	int buffer_len = 16000 * 16 * 60;

	m_pBuffer1 = new BYTE[buffer_len];
	memset(m_pBuffer1, 0, buffer_len);   // 内存置0

	// 设置音频头
	m_whdr_i1.lpData = (LPSTR)m_pBuffer1;			// 指向buffer
	m_whdr_i1.dwBufferLength = buffer_len;			// buffer大小
	m_whdr_i1.dwBytesRecorded = 0;					// buffer存放大小
	m_whdr_i1.dwUser = 0;
	m_whdr_i1.dwFlags = 0;
	m_whdr_i1.dwLoops = 1;
}

void pcm::startRecording()
{
	MMRESULT mRet = waveInOpen(&m_hWaveIn, WAVE_MAPPER, &m_waveform, (DWORD_PTR)nullptr, NULL, CALLBACK_FUNCTION);
	waveInPrepareHeader(m_hWaveIn, &m_whdr_i1, sizeof(WAVEHDR));//准备buffer
	waveInAddBuffer(m_hWaveIn, &m_whdr_i1, sizeof(WAVEHDR));    //添加buffer
	waveInStart(m_hWaveIn);
}

void pcm::endRecording()
{
	waveInReset(m_hWaveIn);
	waveInClose(m_hWaveIn);

	//创建时预留头部信息
	if (!m_pFile)
	{
		m_iTotalDataLength = 0;
		fopen_s(&m_pFile, "sound.pcm", "wb+");
		//预留头部位置
		fseek(static_cast<FILE*>(m_pFile), sizeof(WavPCMFileHeader), SEEK_SET);
	}

	//写入声音数据
	fwrite(m_pBuffer1, 1, m_whdr_i1.dwBytesRecorded, static_cast<FILE*>(m_pFile));
	m_iTotalDataLength += m_whdr_i1.dwBytesRecorded;


	//关闭时写入.wav文件头部信息
	if (m_pFile)
	{
		if (m_iTotalDataLength > 0)
		{
			fseek(static_cast<FILE*>(m_pFile), 0, SEEK_SET);
			WavPCMFileHeader h(1, 16000, 16, m_iTotalDataLength);
			fwrite(&h, 1, sizeof(h), static_cast<FILE*>(m_pFile));
		}
		fclose(static_cast<FILE*>(m_pFile));
		m_pFile = nullptr;
	}
}

pcm::~pcm()
{
	if (m_pFile != nullptr)
	{
		delete m_pFile;
	}
	if (m_pBuffer1 != nullptr)
	{
		delete[]m_pBuffer1;
	}
}

main函数调用:

#include <iostream>
#include "pcm.h"

int main()
{
	pcm* p = new pcm();
	int i;
	std::cin >> i;
	if (i == 1)
	{
		p->startRecording();
		getchar();
	}
	std::cin >> i;
	if (i == 2)
	{
		p->endRecording();
		getchar();
	}
}