浙江财经大学
信工学院ACM集训队

[Win32]mci*高级音频API实现录音播放

本文由 Ocrosoft 于 2018-07-07 21:58:03 发表

mci提供的API使操作简单的不少,但是功能相比低级API少。

mci不需要准备、处理缓冲区,且使用文件保存音频,而低级API保存在内存中,容量相差不少,一般来说使用mci比较简单方便。

图片同上篇,resource.h、RC文件同上篇。

RECORD2.C

#include <Windows.h>
#include "resource.h"

BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);
TCHAR szAppName[] = TEXT("Record2");

int WINAPI WinMain(HINSTANCE hInstace, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
{
	// 使用DIALOG作为主窗体
	if (-1 == DialogBox(hInstace, TEXT("Record"), NULL, DlgProc))
	{
		MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR);
	}

	return 0;
}

void ShowError(HWND hwnd, DWORD dwError)
{
	TCHAR szErrorStr[1024];
	mciGetErrorString(dwError, szErrorStr, sizeof(szErrorStr) / sizeof(TCHAR));

	MessageBeep(MB_ICONEXCLAMATION);
	MessageBox(hwnd, szErrorStr, szAppName, MB_OK | MB_ICONEXCLAMATION);
}

BOOL CALLBACK DlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	static BOOL bRecording, bPlaying, bPaused;
	static TCHAR szFileName[] = TEXT("record2.wav");
	static WORD wDeviceID;
	DWORD dwError;
	
	MCI_GENERIC_PARMS mciGeneric;
	MCI_OPEN_PARMS mciOpen;
	MCI_PLAY_PARMS mciPlay;
	MCI_RECORD_PARMS mciRecord;
	MCI_SAVE_PARMS mciSave;

	switch (message)
	{
	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case ID_RECORD_BEG:
			DeleteFile(szFileName);

			mciOpen.dwCallback = 0;
			mciOpen.wDeviceID = 0;
			mciOpen.lpstrDeviceType = TEXT("waveaudio");
			mciOpen.lpstrElementName = TEXT("");
			mciOpen.lpstrAlias = NULL;
			// 打开默认录音设备
			// 传入的参数mciOpen保存录音设备的ID
			// MCI_WAIT导致程序阻塞
			// MCI_NOTIFY则异步
			dwError = mciSendCommand(0, MCI_OPEN, MCI_WAIT | MCI_OPEN_TYPE | MCI_OPEN_ELEMENT, (DWORD)(LPMCI_OPEN_PARMS)&mciOpen);

			if (dwError != 0)
			{
				ShowError(hwnd, dwError);
				return TRUE;
			}

			// 保存设备ID
			wDeviceID = mciOpen.wDeviceID;

			mciRecord.dwCallback = (DWORD)hwnd;
			mciRecord.dwFrom = 0;
			mciRecord.dwTo = 0;

			// 开始录音
			mciSendCommand(wDeviceID, MCI_RECORD, MCI_NOTIFY, (DWORD)(LPMCI_RECORD_PARMS)&mciRecord);

			EnableWindow(GetDlgItem(hwnd, ID_RECORD_BEG), FALSE);
			EnableWindow(GetDlgItem(hwnd, ID_RECORD_END), TRUE);
			EnableWindow(GetDlgItem(hwnd, ID_PLAY_BEG), FALSE);
			EnableWindow(GetDlgItem(hwnd, ID_PLAY_PAUSE), FALSE);
			EnableWindow(GetDlgItem(hwnd, ID_PLAY_END), FALSE);
			SetFocus(GetDlgItem(hwnd, ID_RECORD_END));

			bRecording = TRUE;

			return TRUE;

		case ID_RECORD_END:
			mciGeneric.dwCallback = 0;

			// 停止录音
			mciSendCommand(wDeviceID, MCI_STOP, MCI_WAIT, (DWORD)(LPMCI_GENERIC_PARMS)&mciGeneric);

			mciSave.dwCallback = 0;
			mciSave.lpfilename = szFileName;

			// 保存到文件
			mciSendCommand(wDeviceID, MCI_SAVE, MCI_WAIT | MCI_SAVE_FILE, (DWORD)(LPMCI_SAVE_PARMS)&mciSave);

			// 清理临时文件
			mciSendCommand(wDeviceID, MCI_CLOSE, MCI_WAIT, (DWORD)(LPMCI_GENERIC_PARMS)&mciGeneric);

			EnableWindow(GetDlgItem(hwnd, ID_RECORD_BEG), TRUE);
			EnableWindow(GetDlgItem(hwnd, ID_RECORD_END), FALSE);
			EnableWindow(GetDlgItem(hwnd, ID_PLAY_BEG), TRUE);
			EnableWindow(GetDlgItem(hwnd, ID_PLAY_PAUSE), FALSE);
			EnableWindow(GetDlgItem(hwnd, ID_PLAY_END), FALSE);
			SetFocus(GetDlgItem(hwnd, ID_PLAY_BEG));

			bRecording = FALSE;

			return TRUE;

		case ID_PLAY_BEG:
			mciOpen.dwCallback = 0;
			mciOpen.wDeviceID = 0;
			mciOpen.lpstrDeviceType = NULL;
			mciOpen.lpstrElementName = szFileName;
			mciOpen.lpstrAlias = NULL;

			// 打开播放设备
			// 保存设备ID到mciOpen中
			dwError = mciSendCommand(0, MCI_OPEN, MCI_WAIT | MCI_OPEN_ELEMENT, (DWORD)(LPMCI_OPEN_PARMS)&mciOpen);

			if (dwError != 0)
			{
				ShowError(hwnd, dwError);
				return TRUE;
			}

			wDeviceID = mciOpen.wDeviceID;

			mciPlay.dwCallback = (DWORD)hwnd;
			mciPlay.dwFrom = 0;
			mciPlay.dwTo = 0;

			// 播放
			mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY, (DWORD)(LPMCI_PLAY_PARMS)&mciPlay);

			EnableWindow(GetDlgItem(hwnd, ID_RECORD_BEG), FALSE);
			EnableWindow(GetDlgItem(hwnd, ID_RECORD_END), FALSE);
			EnableWindow(GetDlgItem(hwnd, ID_PLAY_BEG), FALSE);
			EnableWindow(GetDlgItem(hwnd, ID_PLAY_PAUSE), TRUE);
			EnableWindow(GetDlgItem(hwnd, ID_PLAY_END), TRUE);
			SetFocus(GetDlgItem(hwnd, ID_PLAY_END));

			bPlaying = TRUE;

			return TRUE;

		case ID_PLAY_PAUSE:
			if (!bPaused)
			{
				mciGeneric.dwCallback = 0;

				// 暂停
				mciSendCommand(wDeviceID, MCI_PAUSE, MCI_WAIT, (DWORD)(LPMCI_GENERIC_PARMS)&mciGeneric);

				SetDlgItemText(hwnd, ID_PLAY_PAUSE, TEXT("Resume"));
				bPaused = TRUE;
			}
			else
			{
				mciPlay.dwCallback = (DWORD)hwnd;
				mciPlay.dwFrom = 0;
				mciPlay.dwTo = 0;

				// 播放
				mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY, (DWORD)(LPMCI_PLAY_PARMS)&mciPlay);
				SetDlgItemText(hwnd, ID_PLAY_PAUSE, TEXT("Pause"));
				bPaused = FALSE;
			}

			return TRUE;

		case ID_PLAY_END:
			mciGeneric.dwCallback = 0;

			// 停止播放,清理临时文件
			mciSendCommand(wDeviceID, MCI_STOP, MCI_WAIT, (DWORD)(LPMCI_PLAY_PARMS)&mciGeneric);
			mciSendCommand(wDeviceID, MCI_CLOSE, MCI_WAIT, (DWORD)(LPMCI_PLAY_PARMS)&mciGeneric);

			EnableWindow(GetDlgItem(hwnd, ID_RECORD_BEG), TRUE);
			EnableWindow(GetDlgItem(hwnd, ID_RECORD_END), FALSE);
			EnableWindow(GetDlgItem(hwnd, ID_PLAY_BEG), TRUE);
			EnableWindow(GetDlgItem(hwnd, ID_PLAY_PAUSE), FALSE);
			EnableWindow(GetDlgItem(hwnd, ID_PLAY_END), FALSE);
			SetFocus(GetDlgItem(hwnd, ID_PLAY_BEG));

			bPlaying = FALSE;
			bPaused = FALSE;

			return TRUE;
		}
		break;

	case MM_MCINOTIFY:
		switch (wParam)
		{
		case MCI_NOTIFY_SUCCESSFUL:
			// 播放完成
			if (bPlaying)
				SendMessage(hwnd, WM_COMMAND, ID_PLAY_END, 0);

			// 录音结束(缓冲区溢出)
			if (bRecording)
				SendMessage(hwnd, WM_COMMAND, ID_RECORD_END, 0);

			return TRUE;
		}
		break;

	case WM_SYSCOMMAND:
		switch (LOWORD(wParam))
		{
		case SC_CLOSE:
			if (bRecording)
				SendMessage(hwnd, WM_COMMAND, ID_RECORD_END, 0);

			if (bPlaying)
				SendMessage(hwnd, WM_COMMAND, ID_PLAY_END, 0);

			EndDialog(hwnd, 0);
			return TRUE;
		}
		break;
	}
	return FALSE;
}

欢迎转载,请保留出处与链接。Ocrosoft » [Win32]mci*高级音频API实现录音播放

点赞 (1)or拍砖 (1)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址