最近写了一个小的系统,在VS2022平台上做的,主要是通过调用Windows的API接口实现录音(PCM格式),播音(PCM、WAV、Mp3格式),PCM格式转WAV格式、遍历指定文件夹下的所有音频文件并播放。废话不多说,直接上演示功能截图和代码,其他的不懂的随便一查都很多。
在这里插入代码片
#record.h
#include<Windows.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include"mmsystem.h"
#pragma comment(lib, “winmm.lib”)
/*
int audioSec = 3;
int inputDevice = 0;
int inputChannel = 2;
int inputBits = 16;
unsigned long inputSample = 16000;
static char bufferOne[1024];
static char bufferTwo[1024];
char generateAudioFileName1[100] = “mic.pcm”;
char generateAudioFileName2[100] = “ref.pcm”;
int count;
int i;
HWAVEIN phwi;
WAVEFORMATEX pwfx;
WAVEINCAPS waveincaps;
WAVEHDR pwhOne;
WAVEHDR pwhTwo;
FILE* f = NULL;
FILE* f2 = NULL;
/
int audioSec;
int inputDevice;
int inputChannel;
int inputBits;
unsigned long inputSample;
static char bufferOne[1024];
static char bufferTwo[1024];
char generateAudioFileName1[100];
char generateAudioFileName2[100];
int count;
int i;
HWAVEIN phwi;
WAVEFORMATEX pwfx;
WAVEINCAPS waveincaps;
WAVEHDR pwhOne;
WAVEHDR pwhTwo;
FILE f = NULL;
FILE* f2 = NULL;
void inputSec()
{
/*
* int inputDevice, inputChannel, inputBits;
unsigned long inputSample;
*/
printf(“请输入预录音的文件名1:”);
scanf(“%s”, generateAudioFileName1);
printf(“\n”);
printf(“请输入预录音的文件名2:”);
scanf(“%s”, generateAudioFileName2);
printf(“\n”);
printf(“请输入要录音的设备:”);
scanf(“%d”, &inputDevice);
printf(“\n”);
printf(“请输入录音通道数:”);
scanf(“%d”, &inputChannel);
printf(“\n”);
printf(“请输入录音的采样率:”);
scanf(“%ld”, &inputSample);
printf(“\n”);
printf(“请输入录音的采样位数:”);
scanf(“%d”, &inputBits);
printf(“\n”);
printf(“请输入你要录制该音频的时长(单位/s):”);
int second;
scanf(“%d”, &second);
while (true)
{
if (second <= 0 || second > 100)
{
printf(“请按要求重新输入:”);
getchar();
scanf(“%d”, &second);
}
else {
break;
}
}
audioSec = second;
}
void stop()
{
MMRESULT mResult = waveInStop(phwi);
printf(“waveInStop value is: %d\n”, mResult);
//getchar();
system(“EXIT”);
mResult = waveInReset(phwi);
printf(“waveInReset value is: %d\n”, mResult);
//Sleep(1000);
mResult = waveInUnprepareHeader(phwi, &pwhOne, sizeof(WAVEHDR));
printf("waveInUnprepareHeader value is: %d", mResult);mResult = waveInUnprepareHeader(phwi, &pwhTwo, sizeof(WAVEHDR));
printf("waveInUnprepareHeader value is: %d", mResult);mResult = waveInClose(phwi);
//Sleep(1000);
printf("录音结束,返回值%d", mResult);
system("exit");
}
void PrintSign()
{
for (i = 0; i < audioSec; i++)
{
Sleep(1000);
count++;
system(“CLS”);
printf(“正在录音,%ds…\n”, i + 1);
}
if (count == audioSec)
{Sleep(1000);MMRESULT mResult;printf("时间已到,已停止录音,文件已保存到当前路径下!\n");stop();//printf("STOP函数已经运行!");//system("PAUSE");
}
}
void WaveForMatexInit(LPWAVEFORMATEX myWaveFormate, WORD nch, DWORD nSampleRate, WORD BitsPerSample, char* getFileName, char* filename2)
{
//printf("1\n");
f = fopen(getFileName, "wb");
//f = fopen("mic0.pcm", "wb");
//f2 = fopen("ref0.pcm", "wb");
#if 1
//printf(“2\n”);
if (f == NULL)
{
perror(“fopen”);
//return 1;
}
else
{f2 = fopen(filename2, "wb");
}
#endif
myWaveFormate->wFormatTag = WAVE_FORMAT_PCM;
//myWaveFormate->wFormatTag = WAVE_FORMAT_2M16;
//myWaveFormate->wFormatTag = 0x0006;
myWaveFormate->nChannels = nch;
myWaveFormate->nSamplesPerSec = nSampleRate;
myWaveFormate->wBitsPerSample = BitsPerSample;
myWaveFormate->cbSize = sizeof(WAVEFORMATEX);
//myWaveFormate->cbSize = 0;
myWaveFormate->nAvgBytesPerSec = nSampleRate * nch * BitsPerSample / 8;
myWaveFormate->nBlockAlign = myWaveFormate->nChannels * BitsPerSample / 8;
}
static short mic0[256] = { 0 };
static short ref0[256] = { 0 };
DWORD CALLBACK MicCallback(HWAVEIN hwavein, UINT uMsg, DWORD dwInstance, DWORD dwParamOne, DWORD dwParamTwo)
{
short* p_data = NULL;
switch (uMsg)
{
case WIM_OPEN:
printf(“The Device is already open!\n”);
break;
case WIM_DATA:
//fwrite((void*)((WAVEHDR*)dwParamOne)->lpData, 2 * i, 1, f);
//fwrite((void*)((WAVEHDR*)dwParamOne)->lpData, 2 * i + 1, 1, f2);
// short* p_data = (short )buffer[1024 bytes];
p_data = (short)(((WAVEHDR*)dwParamOne)->lpData);
//printf(“1:%p\n”, p_data);
//printf(“2:%p\n”, ((WAVEHDR*)dwParamOne)->lpData);
for (int j = 0; j < 256; j++) {
mic0[j] = p_data[2 * j];
ref0[j] = p_data[2 * j + 1];
}
fwrite(mic0, 256, 2, f);
fwrite(ref0, 256, 2, f2);
//fwrite((void*)((WAVEHDR*)dwParamOne)->lpData, 1024, 1, f2);waveInAddBuffer(hwavein, (LPWAVEHDR)dwParamOne, sizeof(WAVEHDR));break;
case WIM_CLOSE:printf("The Device is already close!\n");break;
default:break;
}
return 0;
}
void AudioControl()
{
inputSec();
//获得系统中就绪的波形声音输入设备的数量
int num = waveInGetNumDevs();
printf(“系统声音输入设备数量:%d\n”, num);
MMRESULT mResult = waveInGetDevCaps(inputDevice, &waveincaps, sizeof(WAVEINCAPS));if (mResult == MMSYSERR_NOERROR)
{printf("音频输入设备PID:%d\n", waveincaps.wPid);printf("音频输入设备wMID:%d\n", waveincaps.wMid);printf("该设备支持的声道数(waveincaps.wChannels):%d\n", waveincaps.wChannels);printf("音频输入设备支持的格式:%d\n", waveincaps.dwFormats);WaveForMatexInit(&pwfx, inputChannel, inputSample, inputBits, generateAudioFileName1, generateAudioFileName2);mResult = waveInOpen(&phwi, WAVE_MAPPER, &pwfx, (DWORD_PTR)(MicCallback), NULL, CALLBACK_FUNCTION);if (mResult == MMSYSERR_NOERROR){pwhOne.lpData = bufferOne;pwhOne.dwBufferLength = 1024;pwhOne.dwUser = 1;//用户数据pwhOne.dwFlags = 0;//提供缓冲区标示//为音频输入设备准备一个缓冲区mResult = waveInPrepareHeader(phwi, &pwhOne, sizeof(WAVEHDR));if (mResult == MMSYSERR_NOERROR){pwhTwo.lpData = bufferTwo;pwhTwo.dwBufferLength = 1024;pwhTwo.dwUser = 1;pwhTwo.dwFlags = 0;mResult = waveInPrepareHeader(phwi, &pwhTwo, sizeof(WAVEHDR));if (mResult == MMSYSERR_NOERROR){mResult = waveInAddBuffer(phwi, &pwhOne, sizeof(WAVEHDR));if (mResult == MMSYSERR_NOERROR){mResult = waveInAddBuffer(phwi, &pwhTwo, sizeof(WAVEHDR));if (mResult == MMSYSERR_NOERROR){printf("1秒后开始录音!\n", audioSec);//Sleep(1000);mResult = waveInStart(phwi);PrintSign();}}}}}
}
else
{system("CLS");printf("!!!!输入的设备有误,无法打开!!!!");Sleep(2000);return;
}
}
#playPCM.h
#include <stdio.h>
#include <conio.h>
#include <Windows.h>
#include"record.h"
#pragma comment(lib, “winmm.lib”)
#define DATASIZE 102432
FILE pcmfile;
HWAVEOUT hwo;
int cnt;
WAVEHDR wh1;
//WAVEHDR wh2;
WAVEFORMATEX wfx = { 0 };
int outSec = 0;
int outCount = 0;
void CALLBACK WaveCallback(HWAVEOUT hWave, UINT uMsg, DWORD dwInstance, DWORD paramOne, DWORD paramTwo)//回调函数
{
switch (uMsg)
{
case WOM_OPEN:
printf(“开始播放…\n”);
break;
case WOM_DONE:
{
LPWAVEHDR pWaveHeader = (LPWAVEHDR)paramOne;
pWaveHeader->dwBufferLength = fread(pWaveHeader->lpData, 1, DATASIZE, pcmfile);
if (pWaveHeader->dwBufferLength == 0)
{
break;
}
printf(“WOM_DONE %d\n”, pWaveHeader->dwBufferLength);
waveOutPrepareHeader(hwo, pWaveHeader, sizeof(WAVEHDR));
waveOutWrite(hwo, pWaveHeader, sizeof(WAVEHDR));
printf("WOM_DONE\n");break;
}
case WOM_CLOSE:printf("播放已完成!\n");
}
}
void play(char* filename)
{
//printf(“请输入你要播放的时间(单位/s):”);
//scanf(“%d”, &outSec);
//FILE* pcmfile;
char pathName[100] = “D:\Workspace_VS\2022\audioAPI\pcmfile\”;
//char finallyName[100];
strcat(pathName, filename);
Sleep(1000);
printf(“当前文件路径为:%s\n”, pathName);
pcmfile = fopen(pathName, “rb”);
if (pcmfile == NULL)
{
printf(“%s文件打开失败!\n”, filename);
//Sleep(1000);
system(“PAUSE”);
return;
}
wfx.wFormatTag = WAVE_FORMAT_PCM;
wfx.nChannels = 2;
wfx.nSamplesPerSec = 16000;
wfx.wBitsPerSample = 16;
wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
wfx.nBlockAlign = wfx.nChannels * wfx.wBitsPerSample / 8;
wfx.cbSize = 0;
waveOutOpen(&hwo, WAVE_MAPPER, &wfx, (DWORD)WaveCallback, 0L, CALLBACK_FUNCTION);wh1.dwLoops = 0L;
wh1.lpData = new char[DATASIZE];
wh1.dwBufferLength = DATASIZE;
fread(wh1.lpData, 1, DATASIZE, pcmfile);
wh1.dwFlags = 0L;
MMRESULT mResult;
mResult = waveOutPrepareHeader(hwo, &wh1, sizeof(WAVEHDR));
if (mResult == MMSYSERR_NOERROR)
{//printf("mResult=%d!", mResult);mResult = waveOutWrite(hwo, &wh1, sizeof(WAVEHDR));//AudioControl();//printf("mResult=%d!", mResult);while (wh1.dwBufferLength != 0){Sleep(500);}//Sleep(2000);mResult = waveOutUnprepareHeader(hwo, &wh1, sizeof(WAVEHDR));//printf("mResult=%d!", mResult);mResult = waveOutClose(hwo);//printf("mResult=%d!", mResult);delete[]wh1.lpData;fclose(pcmfile);//printf("OVER!");//_getch();Sleep(2000);//udgeOutTime();
}
//waveOutWrite(hwo, &wh1, sizeof(WAVEHDR));
return;
}
#findPCM.h
#include <stdio.h>
#include<io.h>
void findPcm()
{
/struct _finddata_t{
unsigned int attrib; //记录文件属性(隐藏、文件夹、只读等)
time_t time_create; //文件创建时间
time_t time_access; //文件最后被访问时间
time_t time_write; //文件最后被修改时间
_fsile_t size; //文件大小
char name[_MAX_FNAME]; //文件名
};/
//文件存信息结构体
struct _finddata_t file;
//保存文件句柄
long handl;
int count = 0;//long _findfirst(char * filespec , struct _finddata_t * fileinfo);
if ((handl = _findfirst("D:\\Workspace_VS\\2022\\audioAPI\\pcmfile\\*.pcm", &file)) == -1)
{printf("当前目录没有PCM文件\n");
}
else {do {count++;printf("*********************************\n");printf("第%d个文件:%s,文件大小:%d\n",count, file.name, file.size);Sleep(1000);play(file.name);printf("第%d个文件:%s播放结束!\n", count, file.name);Sleep(1000);} while (_findnext(handl, &file) == 0);//int _findnext( long handle, struct _finddata_t *fileinfo );
}
_findclose(handl);
printf("\n播放结束,该目录下共有%d文件!\n", count);
//stop();
}
主函数(audioAdmin.cpp)
#include<Windows.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<mmsystem.h>
#include “mmsystem.h”
#include “playPCM.h”
#include “findPCM.h”
#pragma comment(lib, “winmm.lib”)
//FILE* f = NULL;
//int count = 0;
char filename[50];
//Wav格式说明RIFF、FORMATE、DATA
//https://blog.csdn.net/weixin_48680270/article/details/123523517?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165830013416782425193967%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=165830013416782425193967&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~times_rank-3-123523517-null-null.142v32pc_search_v2,185v2control&utm_term=wav%E6%A0%BC%E5%BC%8F&spm=1018.2226.3001.4187
typedef struct {
char id[4];
unsigned long size;
char type[4];
}MYWAVERIFF;
typedef struct {
char id[4];
unsigned long size;
unsigned short audioFormat;
unsigned short numChannels;
unsigned long sampleRate;
unsigned long byteRate;
unsigned short blockAlign;
unsigned short bitsPerSample;
}MYWAVEFORMATE;
typedef struct {
char id[4];
unsigned long size;
}MYWAVEDATA;
long getSize()
{
FILE* f;
long size;
f = fopen(“audio.pcm”, “r”);
if (f == NULL)
{
printf(“文件打开失败!”);
}
fseek(f, 0, SEEK_END);
size = ftell(f);
printf(“源文件长度为:%d\n”, size);
fclose(f);
return size;
}
void convertWav(int channels, unsigned long sampleRate, int sampleBit)
{
MYWAVERIFF pcmRIFF;
MYWAVEFORMATE pcmFORMATE;
MYWAVEDATA pcmDATA;
FILE* f, * fpout;
long fileSize;
f = fopen(“audio.pcm”, “rb”);
if (f == NULL)
{
printf(“源文件打开失败!”);
return;
}
fpout = fopen(“audio.wav”, “wb”);
if (fpout == NULL)
{
printf(“文件打开错误!”);
return;
}
fileSize = getSize();
/*函数原型
void memcpy(void destin, void source, unsigned n);
参数
destin-- 指向用于存储复制内容的目标数组,类型强制转换为 void 指针。
source-- 指向要复制的数据源,类型强制转换为 void 指针。
n-- 要被复制的字节数。/
memcpy(pcmRIFF.id, “RIFF”, strlen(“RIFF”));
pcmRIFF.size = 36 + fileSize;
memcpy(pcmRIFF.type, “WAVE”, strlen(“WAVE”));
//fseek(fpout, sizeof(MYWAVERIFF), SEEK_CUR);int nriff = fwrite(&pcmRIFF, sizeof(pcmRIFF), 1, fpout);
printf("NRIFF: %d\n", nriff);pcmFORMATE.numChannels = inputChannel;
pcmFORMATE.sampleRate = inputSample;
pcmFORMATE.bitsPerSample = inputBits;
pcmFORMATE.byteRate = inputSample * inputChannel * inputBits / 8;
pcmFORMATE.blockAlign = inputChannel * inputBits / 8;
pcmFORMATE.size = 16;
pcmFORMATE.audioFormat = WAVE_FORMAT_PCM; //the value is 1
memcpy(pcmFORMATE.id, "fmt", strlen("fmt "));int nFormate = fwrite(&pcmFORMATE, sizeof(pcmFORMATE), 1, fpout);
printf("FORMATE: %d\n", nFormate);memcpy(pcmDATA.id, "data", strlen("data"));
pcmDATA.size = fileSize;
int nData = fwrite(&pcmDATA, sizeof(pcmDATA), 1, fpout);
printf("DATA: %d\n", nData);
//system("PAUSE");char* buffer = (char*)malloc(1024);
int ret;
while ((ret = fread(buffer, sizeof(char), 1024, f)) != 0)
{fwrite(buffer, sizeof(char), ret, fpout);printf("reading......\n");
}
free(buffer);fclose(f);
fclose(fpout);
printf("转换完成!\n");
}
/*
void inputSec()
{
int inputDevice, inputChannel, inputBits;
unsigned long inputSample;printf("请输入预录音的文件名(需加后缀名):");
scanf("%s", generateAudioFileName);
printf("\n");
printf("请输入要录音的设备:");
scanf("%d", &inputDevice);
printf("\n");
printf("请输入录音通道数:");
scanf("%d", &inputChannel);
printf("\n");
printf("请输入录音的采样率:");
scanf("%ld", &inputSample);
printf("\n");
printf("请输入录音的采样位数:");
scanf("%d", &inputBits);
printf("\n");
printf("请输入你要录制该音频的时长(单位/s):");
int second;
scanf("%d", &second);
while (true)
{if (second <= 0 || second > 100){printf("请按要求重新输入:");getchar();scanf("%d", &second);}else {break;}
}
audioSec = second;
}
*/
void playAudio()
{
//mciSendString()函数只能播放wav或mp3格式的音频
MMRESULT m = mciSendString(TEXT(“open yjm.mp3 alias bgm”), 0, 0, 0);
if (m == 0) {
printf(“正在播放Mp3的音频,按“p”暂停播放,“y”继续播放,“n”退出播放\n”);
m = mciSendString(TEXT(“play bgm”), NULL, 0, NULL);
//m = mciSendString(TEXT("pause bgm"), NULL, 0, NULL);char isResume;char s;//s = getchar();//printf("已暂停播放, 继续播放请按“y”,退出请按“n”:");while (true){scanf("%c", &isResume);switch (isResume){case 'y':m = mciSendString(TEXT("resume bgm"), 0, 0, 0);printf("继续播放!\n");break;case 'p':mciSendString(TEXT("pause bgm"), 0, 0, 0);printf("暂停播放!\n");break;case 'n':mciSendString(TEXT("close bgm"), 0, 0, 0);break;//system("EXIT");default:break;}if (isResume == 'n'){break;}}
}
else
{printf("打开文件失败,错误码:%x", m);Sleep(2000);
}
system("CLS");
getchar();
}
void menu()
{
printf(“基于WASAPI的音频系统\n”);
printf(“\n”);
printf(“1、录制音频\n”);
printf(“\n”);
printf(“2、播放PCM音频\n”);
printf(“\n”);
printf(“3、播放Mp3音频\n”);
printf(“\n”);
printf(“****4、文件格式转换\n”);
printf(“\n”);
printf("***5、多PCM文件播放\n");
printf(“\n”);
printf(“6、退出系统\n”);
//printf(“\n注(按“a”开始录音,“t”退出系统,“s”播放Mp3音频,“p”播放PCM音频,“c”格式转换)\n”);
}
void main(int argc, const char argv[])
{
/*
printf("argc:%d\n", argc);
printf("argv:%s\n", argv[1]);//拿到播放列表的文件名char* play_list = (char *)argv[1];
FILE* fp_play = fopen(play_list, "rb");
char buf[32];//获取这列表要播放的音频文件
fgets(buf, 32, fp_play);//readline
printf("读取的第一个文件为:%s\n", buf);
char str_pilt[4];
int ste_len = strlen(buf);//7
int fileLen = ste_len - 6;
strncpy(str_pilt, buf + fileLen + 1, 3);
//strncpy(audioName, buffer, fileLen);
str_pilt[3] = '\0';
printf("提取后的字符为:%s\n", str_pilt);if (strcmp(str_pilt, "wav") == 0) {//调用wav播放接口
}
else if (strcmp(str_pilt, "pcm") == 0) {//调用pcm播放接口
}
else if (strcmp(str_pilt, "mp3") == 0) {//调用mp3播放接口
}
*/int a, b;
bool flag = FALSE;while (1)
{menu();scanf("%d", &a);switch (int(a)){case 1:system("CLS");Sleep(250);printf("开始录制音频!\n");AudioControl();Sleep(2000);system("CLS");break;case 4:system("CLS");printf("正在将pcm格式音频转为wav格式!\n");convertWav(inputChannel, inputSample, inputBits);Sleep(1000);system("CLS");break;case 6:system("CLS");printf("退出系统!\n");break;case 3:system("CLS");playAudio();system("CLS");break;case 2:system("CLS");printf("请输入要播放的文件名:");scanf("%s", filename);play(filename);printf("播放结束!");system("CLS");break;case 5:system("CLS");findPcm();Sleep(2000);system("CLS");break;default:printf("输入有误,请按要求重新输入!");Sleep(1000);getchar();system("CLS");break;}if ((int)a == 6){break;flag = true;}
}
if (flag == true)
{system("EXIT");
}
}