一直不能开始录音,结束也结束不了,最后发现是把pWaveHdr2写成了pWaveHdr1,_(:з」∠)_
跟之前一样,要先Open设备,PrepareHeader,AddBuffer。结束要UnPrepareHeader,free缓冲区。
主要就是waveform的一些参数设置。
RECORD1.C
#include <Windows.h> #include "resource.h" #define INP_BUFFER_SIZE 16384 BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM); TCHAR szAppName[] = TEXT("Record1"); 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; } // 翻转BYTE数组 void ReverseMemory(BYTE *pBuffer, int iLength) { BYTE b; int i; for (i = 0; i < iLength / 2; i++) { b = pBuffer[i]; pBuffer[i] = pBuffer[iLength - i - 1]; pBuffer[iLength - i - 1] = b; } } BOOL CALLBACK DlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static BOOL bRecording, bPlaying, bReverse, bPaused, bEnding, bTerminating; static DWORD dwDataLength, dwRepetitions = 1; static HWAVEIN hWaveIn; static HWAVEOUT hWaveOut; static PBYTE pBuffer1, pBuffer2, pSaveBuffer, pNewBuffer; static PWAVEHDR pWaveHdr1, pWaveHdr2; static TCHAR szOpenError[] = TEXT("Error opening waveform audio!"); static TCHAR szMemError[] = TEXT("Error allocating memory!"); static WAVEFORMATEX waveform; switch (message) { case WM_INITDIALOG: pWaveHdr1 = malloc(sizeof(WAVEHDR)); pWaveHdr2 = malloc(sizeof(WAVEHDR)); pSaveBuffer = malloc(1); return TRUE; case WM_COMMAND: switch (LOWORD(wParam)) { // 开始录音 case ID_RECORD_BEG: // 两个缓冲区分配1.6KB内存 pBuffer1 = malloc(INP_BUFFER_SIZE); pBuffer2 = malloc(INP_BUFFER_SIZE); if (!pBuffer1 || !pBuffer2) { if (pBuffer1)free(pBuffer1); if (pBuffer2)free(pBuffer2); MessageBeep(MB_ICONEXCLAMATION); MessageBox(hwnd, szMemError, szAppName, MB_ICONEXCLAMATION | MB_OK); return TRUE; } // PCM格式 waveform.wFormatTag = WAVE_FORMAT_PCM; waveform.nChannels = 1; // 11025采样率 waveform.nSamplesPerSec = 11025; waveform.nAvgBytesPerSec = 11025; waveform.nBlockAlign = 1; waveform.wBitsPerSample = 8; waveform.cbSize = 0; // 把一个MM_WIM_OPEN给放入消息队列 // 成功返回0 if (waveInOpen(&hWaveIn, WAVE_MAPPER, &waveform, (DWORD)hwnd, 0, CALLBACK_WINDOW)) { free(pBuffer1); free(pBuffer2); MessageBeep(MB_ICONEXCLAMATION); MessageBox(hwnd, szOpenError, szAppName, MB_ICONEXCLAMATION | MB_OK); } // 准备缓存 pWaveHdr1->lpData = pBuffer1; pWaveHdr1->dwBufferLength = INP_BUFFER_SIZE; pWaveHdr1->dwBytesRecorded = 0; pWaveHdr1->dwUser = 0; pWaveHdr1->dwFlags = 0; pWaveHdr1->dwLoops = 1; pWaveHdr1->lpNext = NULL; pWaveHdr1->reserved = 0; waveInPrepareHeader(hWaveIn, pWaveHdr1, sizeof(WAVEHDR)); pWaveHdr2->lpData = pBuffer2; pWaveHdr2->dwBufferLength = INP_BUFFER_SIZE; pWaveHdr2->dwBytesRecorded = 0; pWaveHdr2->dwUser = 0; pWaveHdr2->dwFlags = 0; pWaveHdr2->dwLoops = 1; pWaveHdr2->lpNext = NULL; pWaveHdr2->reserved = 0; waveInPrepareHeader(hWaveIn, pWaveHdr2, sizeof(WAVEHDR)); return TRUE; // 停止录音 case ID_RECORD_END: bEnding = TRUE; // 将一个MM_WIM_DATA消息放入消息队列 waveInReset(hWaveIn); return TRUE; case ID_PLAY_BEG: waveform.wFormatTag = WAVE_FORMAT_PCM; waveform.nChannels = 1; waveform.nSamplesPerSec = 11025; waveform.nAvgBytesPerSec = 11025; waveform.nBlockAlign = 1; waveform.wBitsPerSample = 8; waveform.cbSize = 0; // 打开音频输出,成功返回0 // 发送一个MM_WOM_OPEN消息 if (waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveform, (DWORD)hwnd, 0, CALLBACK_WINDOW)) { MessageBeep(MB_ICONEXCLAMATION); MessageBox(hwnd, szOpenError, szAppName, MB_ICONEXCLAMATION | MB_OK); } return TRUE; // 暂停 case ID_PLAY_PAUSE: if (!bPaused) { waveOutPause(hWaveOut); SetDlgItemText(hwnd, ID_PLAY_PAUSE, TEXT("Resume")); bPaused = TRUE; } else { waveOutRestart(hWaveOut); SetDlgItemText(hwnd, ID_PLAY_PAUSE, TEXT("Pause")); bPaused = FALSE; } return TRUE; // 停止播放 case ID_PLAY_END: bEnding = TRUE; // 发送MM_WOM_CLOSE消息 waveOutReset(hWaveOut); return TRUE; // 倒放 case ID_PLAY_REV: bReverse = TRUE; ReverseMemory(pSaveBuffer, dwDataLength); SendMessage(hwnd, WM_COMMAND, ID_PLAY_BEG, 0); return TRUE; // 重复播放 case ID_PLAY_REP: // 重复标记 dwRepetitions = -1; SendMessage(hwnd, WM_COMMAND, ID_PLAY_BEG, 0); return TRUE; // 两倍采样频率、两倍每秒字节数播放 case ID_PLAY_SPEED: waveform.wFormatTag = WAVE_FORMAT_PCM; waveform.nChannels = 1; waveform.nSamplesPerSec = 22050; waveform.nAvgBytesPerSec = 22050; waveform.nBlockAlign = 1; waveform.wBitsPerSample = 8; waveform.cbSize = 0; if (waveOutOpen(&hWaveOut, 0, &waveform, (DWORD)hwnd, 0, CALLBACK_WINDOW)) { MessageBeep(MB_ICONEXCLAMATION); MessageBox(hwnd, szOpenError, szAppName, MB_ICONEXCLAMATION | MB_OK); } return TRUE; } break; case MM_WIM_OPEN: // realloc在此处与free+malloc功能类似 pSaveBuffer = realloc(pSaveBuffer, 1); // 启用禁用按钮 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); EnableWindow(GetDlgItem(hwnd, ID_PLAY_REV), FALSE); EnableWindow(GetDlgItem(hwnd, ID_PLAY_REP), FALSE); EnableWindow(GetDlgItem(hwnd, ID_PLAY_SPEED), FALSE); SetFocus(GetDlgItem(hwnd, ID_RECORD_END)); // 添加缓冲区 waveInAddBuffer(hWaveIn, pWaveHdr1, sizeof(WAVEHDR)); waveInAddBuffer(hWaveIn, pWaveHdr2, sizeof(WAVEHDR)); bRecording = TRUE; bEnding = FALSE; dwDataLength = 0; // 开始录音 waveInStart(hWaveIn); return TRUE; // WaveInReset或者缓冲区溢出(超过pBuffer的1.6K后)收到DATA消息 case MM_WIM_DATA: // 追加新录音的内存大小 pNewBuffer = realloc(pSaveBuffer, dwDataLength + ((PWAVEHDR)lParam)->dwBytesRecorded); // realloc失败(内存不足) if (pNewBuffer == NULL) { waveInClose(hWaveIn); MessageBeep(MB_ICONEXCLAMATION); MessageBox(hwnd, szMemError, szAppName, MB_ICONEXCLAMATION | MB_OK); return TRUE; } // realloc可能导致内存地址变化 // 使用pNewBuffer目的是失败后停止,保存之前成功的录音 pSaveBuffer = pNewBuffer; // 将新的录音追加到原来的录音后面 CopyMemory(pSaveBuffer + dwDataLength, ((PWAVEHDR)lParam)->lpData, ((PWAVEHDR)lParam)->dwBytesRecorded); // 计算新的长度 dwDataLength += ((PWAVEHDR)lParam)->dwBytesRecorded; if (bEnding) { waveInClose(hWaveIn); return TRUE; } // 使用完的缓冲区重新添回去 waveInAddBuffer(hWaveIn, (PWAVEHDR)lParam, sizeof(WAVEHDR)); return TRUE; // waveInClose发送消息 case MM_WIM_CLOSE: // 卸载缓冲区,释放缓冲区空间 waveInUnprepareHeader(hWaveIn, pWaveHdr1, sizeof(WAVEHDR)); waveInUnprepareHeader(hWaveIn, pWaveHdr2, sizeof(WAVEHDR)); free(pBuffer1); free(pBuffer2); EnableWindow(GetDlgItem(hwnd, ID_RECORD_BEG), TRUE); EnableWindow(GetDlgItem(hwnd, ID_RECORD_END), FALSE); SetFocus(GetDlgItem(hwnd, ID_RECORD_BEG)); // 检查是否有录音,调整UI if (dwDataLength > 0) { EnableWindow(GetDlgItem(hwnd, ID_PLAY_BEG), TRUE); EnableWindow(GetDlgItem(hwnd, ID_PLAY_PAUSE), FALSE); EnableWindow(GetDlgItem(hwnd, ID_PLAY_END), FALSE); EnableWindow(GetDlgItem(hwnd, ID_PLAY_REV), TRUE); EnableWindow(GetDlgItem(hwnd, ID_PLAY_REP), TRUE); EnableWindow(GetDlgItem(hwnd, ID_PLAY_SPEED), TRUE); SetFocus(GetDlgItem(hwnd, ID_PLAY_BEG)); } bRecording = FALSE; if (bTerminating) SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L); return TRUE; case MM_WOM_OPEN: 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); EnableWindow(GetDlgItem(hwnd, ID_PLAY_REV), FALSE); EnableWindow(GetDlgItem(hwnd, ID_PLAY_REP), FALSE); EnableWindow(GetDlgItem(hwnd, ID_PLAY_SPEED), FALSE); SetFocus(GetDlgItem(hwnd, ID_RECORD_END)); // 只有一段音频,不使用双缓冲 pWaveHdr1->lpData = pSaveBuffer; pWaveHdr1->dwBufferLength = dwDataLength; pWaveHdr1->dwBytesRecorded = 0; pWaveHdr1->dwUser = 0; pWaveHdr1->dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP; // 设置重复标记 pWaveHdr1->dwLoops = dwRepetitions; pWaveHdr1->lpNext = NULL; pWaveHdr1->reserved = 0; waveOutPrepareHeader(hWaveOut, pWaveHdr1, sizeof(WAVEHDR)); waveOutWrite(hWaveOut, pWaveHdr1, sizeof(WAVEHDR)); bEnding = FALSE; bPlaying = TRUE; return TRUE; // waveOutReset()或播放完毕触发 case MM_WOM_DONE: waveOutUnprepareHeader(hWaveOut, pWaveHdr1, sizeof(WAVEHDR)); waveOutClose(hWaveOut); return TRUE; case MM_WOM_CLOSE: EnableWindow(GetDlgItem(hwnd, ID_RECORD_BEG), TRUE); EnableWindow(GetDlgItem(hwnd, ID_RECORD_END), TRUE); EnableWindow(GetDlgItem(hwnd, ID_PLAY_BEG), TRUE); EnableWindow(GetDlgItem(hwnd, ID_PLAY_PAUSE), FALSE); EnableWindow(GetDlgItem(hwnd, ID_PLAY_END), FALSE); EnableWindow(GetDlgItem(hwnd, ID_PLAY_REV), TRUE); EnableWindow(GetDlgItem(hwnd, ID_PLAY_REP), TRUE); EnableWindow(GetDlgItem(hwnd, ID_PLAY_SPEED), TRUE); SetFocus(GetDlgItem(hwnd, ID_PLAY_BEG)); SetDlgItemText(hwnd, ID_PLAY_PAUSE, TEXT("Pause")); bPaused = FALSE; dwRepetitions = 1; bPlaying = FALSE; if (bReverse) { ReverseMemory(pSaveBuffer, dwDataLength); bReverse = FALSE; } // 播放没有影响 //if (bTerminating) // SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L); return TRUE; case WM_SYSCOMMAND: switch (LOWORD(wParam)) { // 关闭窗口 case SC_CLOSE: // 正在录音 if (bRecording) { // 关闭窗口标记 bTerminating = TRUE; bEnding = TRUE; // 尝试停止录音 waveOutReset(hWaveOut); return TRUE; } free(pWaveHdr1); free(pWaveHdr2); free(pSaveBuffer); EndDialog(hwnd, 0); return TRUE; } break; } return FALSE; }
resource.h
#define ID_RECORD_BEG 1000 #define ID_RECORD_END 1001 #define ID_PLAY_BEG 1002 #define ID_PLAY_PAUSE 1003 #define ID_PLAY_END 1004 #define ID_PLAY_REV 1005 #define ID_PLAY_REP 1006 #define ID_PLAY_SPEED 1007
RECORD1.RC
///////////////////////////////////////////////////////////////////////////// // // Dialog // RECORD DIALOGEX 100, 100, 152, 74 STYLE DS_SETFONT | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU CAPTION "Waveform Audio Recorder" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN PUSHBUTTON "Record",ID_RECORD_BEG,28,8,40,14 PUSHBUTTON "End",ID_RECORD_END,76,8,40,14,WS_DISABLED PUSHBUTTON "Play",ID_PLAY_BEG,8,30,40,14,WS_DISABLED PUSHBUTTON "Pause",ID_PLAY_PAUSE,56,30,40,14,WS_DISABLED PUSHBUTTON "End",ID_PLAY_END,104,30,40,14,WS_DISABLED PUSHBUTTON "Reverse",ID_PLAY_REV,8,52,40,14,WS_DISABLED PUSHBUTTON "Repeat",ID_PLAY_REP,56,52,40,14,WS_DISABLED PUSHBUTTON "Speedup",ID_PLAY_SPEED,104,52,40,14,WS_DISABLED END
欢迎转载,请保留出处与链接。Ocrosoft » [Win32]waveIn*/waveOut*录音和播放