标签:
22.2.4 数字录音机——WaveInXXX波形输入设备函数的使用
(1)录音常用的API
①waveInOpen(打开一个音频输入设备)
②waveInPrepareHeader(为一个即将在waveInAddBuffer中调用的输入缓冲区准备头部)
③waveInAddBuffer(添加一个输入用的数据缓冲区)
④waveInStart(开始录音)
⑤waveInReset(重置输入设备以便重新录音或关闭录音)
⑥waveInClose(关闭音频输入设备)等几个。
(2)windows waveform方式实现录音要通过这么几步:(注意顺序!!)
①打开录音设备——waveInOpen()函数
注意,调用之前要填写好wav头信息(包含采样率、采样位数等);还要设置好接收录音消息的窗口句柄。
②准备好录音缓存空间——waveInPrepareHeader()函数
这一步为了准备好将要送入录音设备的缓存,以便之后可以供之使用。一般至少需要准备两块缓存。因为录音不能间断,当一块填满时没有时间等待你去送入下一块缓存,所以必须提前就准备好。(注意这两个缓存使用的先后顺序遵循FIFO原则)
③将缓存送入录音设备——waveInAddBuffer()函数
将缓存送入录音设备,供之存入已录下的音频。开始录音时,应至少送入两块不同的缓存,即调用两次这个函数。之后为了不致录音产生间断,应保证至少有一块缓存在录音时为空,以备衔接。
④开始录音——waveInStart()函数
当以上的工作都准备好时,便可调用此函数开始录音了。一旦调用,录音设备便立即录音并存入已经送来的缓存块内,当被送来的有多个缓存块时,按照FIFO的原则向缓存块内存入录音数据。如果是在利用回调函数来接收录音消息时,此函数执行之后可以执行一个while()循环,来等待录音设备录音。为了减少CPU使用率,可以在循环中加人sleepex(x,TRUE),x单位ms,TRUE必须要有。每个缓冲块存满时,将发送一个MM_WIM_DATA消息。
⑤停止录音,关闭设备——依次调用以下这些函数,来结束录音。
waveInStop: 停止录音
waveInReset:复位。 //会发送MM_WIM_DATA消息
waveInClose:关闭设备(想结束录音时,最好在这函数前调用一下waveInReset)
(3)录音时的消息通知
①MM_WIM_OPEN
当执行waveInOpen函数时,并产生这个消息信号。代表录音设备已经打开。在这里可以自己设定一些操作,也可以没有操作。
②MM_WIM_DATA
当每块缓存块填满时或调用waveInReset函数时,产生这个消息,在这个消息中,应当完成这样的工作,以便录音连续进行:
A、将存满的缓存块处理,例如存入文件,或送入其他设备;
B、向录音设备送入新的缓存块;录音设备任何时刻应当拥有不少于2个的缓存块,以保证录音不间断性。
③MM_WIM_CLOSE
当调用waveInclose函数时,会产生这个消息,代表录音设备关闭成功。这次回调函数调用中,可以执行相应的一些关闭文件保存信息等等的操作,自定义。
【Record1程序】
/*---------------------------------------------------- RECORD1.C —— Waveform Audio Recorder (c) Charles Petzold,1998 ----------------------------------------------------*/ #include <Windows.h> #include "resource.h" #pragma comment(lib,"WINMM.LIB") #define INP_BUFFER_SIZE 16384 //16K,即16*1024 BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM); TCHAR szAppName[] = TEXT("Record1"); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInStance, PSTR szCmdLine, int iCmdShow) { if (-1 == DialogBox(hInstance,TEXT("Record"),NULL,DlgProc)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); } return 0; } void ReverseMemory(BYTE* pBuffer, int iLength) { BYTE b; int i; for (i = 0; i <iLength /2; i++) { b = pBuffer[i]; pBuffer[i] = pBuffer[iLength - 1 - i]; pBuffer[iLength - 1 - i] = b; } } BOOL CALLBACK DlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { RECT rect; static HWAVEIN hWaveIn; static HWAVEOUT hWaveOut; static PWAVEHDR pWaveHdr1, pWaveHdr2; static PBYTE pBuffer1, pBuffer2, pSaveBuffer,pNewBuffer; static TCHAR szMemError[] = TEXT("Error allocating memory!"); static TCHAR szOpenError[] = TEXT("Error opening waveform audio!"); static WAVEFORMATEX waveform; static BOOL bRecording, bPlaying, bReverse, bPaused,bEnding,bTerminating; static DWORD dwDataLength, dwRepetitions = 1; switch (message) { case WM_INITDIALOG: GetWindowRect(hwnd, &rect); SetWindowPos(hwnd, NULL, (GetSystemMetrics(SM_CXSCREEN) - rect.right + rect.left) / 2, (GetSystemMetrics(SM_CYSCREEN) - rect.bottom + rect.top) / 2, rect.right- rect.left,rect.bottom-rect.top,SWP_SHOWWINDOW); //分配两个波形头结构 pWaveHdr1 = malloc(sizeof(WAVEHDR)); //WaveIn(Out)PrepareHeader、WaveInAddBuffe等函数的参数 pWaveHdr2 = malloc(sizeof(WAVEHDR)); //分配“保存缓冲区”(用来保存声音数据的缓冲区) pSaveBuffer = malloc(1); //1个字节,以后可根据需要录制的声音长度重新realloc来改变缓冲区的大小 return TRUE; case WM_COMMAND: switch (LOWORD(wParam)) { /*-----------------------------录制按钮过程--------------------------------------*/ case IDC_RECORD_BEG: //分配16K的声音数据缓冲区 //一般至少需要准备两块缓存。因为录音不能间断,当一块填满时没有时间等待你去送入下一块缓存,所以必须提前就准备好 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; } //打开波形输入设备 waveform.wFormatTag = WAVE_FORMAT_PCM; waveform.nChannels = 1; waveform.nSamplesPerSec = 11025; //采样率:11025Hz waveform.nAvgBytesPerSec = 11025; //每秒数据传输的字节数=nBlockAlign*nSamplesPerSec waveform.nBlockAlign = 1; //块对齐 = nChannels*wBitsPerSample/8(字节) waveform.wBitsPerSample = 8; //采样大小,即声音的振幅(强度) waveform.cbSize = 0; //PCM,必须为0 if (MMSYSERR_NOERROR !=waveInOpen(&hWaveIn, WAVE_MAPPER, &waveform, (DWORD)hwnd, 0,CALLBACK_WINDOW)) //发送MM_WIM_OPEN消息 { free(pBuffer1); free(pBuffer2); MessageBeep(MB_ICONEXCLAMATION); MessageBox(hwnd, szOpenError, szAppName, MB_ICONEXCLAMATION | MB_OK); return TRUE; } //创建并准备波形头结构 pWaveHdr1->lpData = pBuffer1; pWaveHdr1->dwBufferLength = INP_BUFFER_SIZE; //缓冲区的大小,当该数据超过该值是会发送MM_WIM_DATA消息 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; //缓冲区的大小,当该数据超过该值是会发送MM_WIM_DATA消息 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 IDC_RECORD_END: //重置波形输入设备,所有等待录音的缓冲区标志为己完成,当前位置设为第0个缓冲区 //即清掉尚在等待录音的缓冲区,然后将正在录音的缓冲区中数据发送MM_WIM_DATA给用户处理 bEnding = TRUE; waveInReset(hWaveIn); //送MM_WIM_DATA消息 return TRUE; /*-----------------------------播放按钮过程--------------------------------------*/ case IDC_PLAY_BEG: //打开波形输出设备 waveform.wFormatTag = WAVE_FORMAT_PCM; waveform.nChannels = 1; waveform.nSamplesPerSec = 11025;//采样率:11025Hz waveform.nAvgBytesPerSec = 11025;//每秒数据传输的字节数=nBlockAlign*nSamplesPerSec waveform.nBlockAlign = 1; //块对齐 = nChannels*wBitsPerSample/8(字节) waveform.wBitsPerSample = 8; //采样大小,即声音的振幅(强度) waveform.cbSize = 0; //PCM,必须为0 if (MMSYSERR_NOERROR != waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveform, (DWORD)hwnd, 0, CALLBACK_WINDOW)) //发送MM_WOM_OPEN消息 { MessageBeep(MB_ICONEXCLAMATION); MessageBox(hwnd, szOpenError, szAppName, MB_ICONEXCLAMATION | MB_OK); } return TRUE; /*-----------------------------暂停按钮过程--------------------------------------*/ case IDC_PLAY_PAUSE: //暂停或重启音频输出设备 if (!bPaused) { waveOutPause(hWaveOut); SetDlgItemText(hwnd, IDC_PLAY_PAUSE, TEXT("Resume")); bPaused = TRUE; } else { waveOutRestart(hWaveOut); SetDlgItemText(hwnd, IDC_PLAY_PAUSE, TEXT("Pause")); bPaused = FALSE; } return TRUE; /*----------------------------停止播放按钮过程------------------------------------*/ case IDC_PLAY_END: //复位音频输出设备,为关闭做准备 bEnding = TRUE; waveOutReset(hWaveOut); //会发送MM_WOM_DONE消息 return TRUE; /*----------------------------反转播放按钮过程------------------------------------*/ case IDC_PLAY_REV: //反转“保存缓冲区”中的数据,并倒播音频 bReverse = TRUE; ReverseMemory(pSaveBuffer, dwDataLength); SendMessage(hwnd, WM_COMMAND, IDC_PLAY_BEG, 0); //发送消息,开始播放 return TRUE; /*----------------------------重复播放按钮过程------------------------------------*/ case IDC_PLAY_REP: //将播放次数设备为无限次数 dwRepetitions = -1; SendMessage(hwnd, WM_COMMAND, IDC_PLAY_BEG, 0); //发送消息,开始播放 return TRUE; /*----------------------------快进播放按钮过程------------------------------------*/ case IDC_PLAY_SPEED: //打开音频输出设备,并快播(2倍速度) waveform.wFormatTag = WAVE_FORMAT_PCM; waveform.nChannels = 1; waveform.nSamplesPerSec = 22050;//2倍的录音时的采样率(11025Hz) waveform.nAvgBytesPerSec = 22050;//每秒数据传输的字节数=nBlockAlign*nSamplesPerSec waveform.nBlockAlign = 1; //块对齐 = nChannels*wBitsPerSample/8(字节) waveform.wBitsPerSample = 8; //采样大小,即声音的振幅(强度) waveform.cbSize = 0; //PCM,必须为0 if (MMSYSERR_NOERROR != waveOutOpen(&hWaveOut, 0, &waveform, (DWORD)hwnd, 0, CALLBACK_WINDOW)) { MessageBeep(MB_ICONEXCLAMATION); MessageBox(hwnd, szOpenError, szAppName, MB_ICONEXCLAMATION | MB_OK); } return TRUE; } break; /*----------录制函数的消息,共3个(MM_WIM_OPEN、MM_WIM_DATA、MM_WIM_CLOSE)------------*/ case MM_WIM_OPEN: //将“保存缓冲区”缩小为1个字节 pSaveBuffer = realloc(pSaveBuffer, 1); //启动或禁用按钮组 EnableWindow(GetDlgItem(hwnd, IDC_RECORD_BEG), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_RECORD_END), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_BEG), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_PAUSE), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_END), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_REV), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_REP), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_SPEED), FALSE); SetFocus(GetDlgItem(hwnd, IDC_RECORD_END)); //向波形输入设备增加缓冲区 waveInAddBuffer(hWaveIn, pWaveHdr1, sizeof(WAVEHDR)); waveInAddBuffer(hWaveIn, pWaveHdr2, sizeof(WAVEHDR)); //开始采样 bRecording = TRUE; bEnding = FALSE; dwDataLength = 0; //录音开始,录音设备便立即录音并存入已经送来的缓存块内,当被送来的有多个缓存块时, //按照FIFO的原则向缓存块内存入录音数据 waveInStart(hWaveIn); return TRUE; case MM_WIM_DATA: //当指定16K缓冲区满时会收到该消息 //新“保存缓冲区”大小 = 原大小+新录制的大小 pNewBuffer = realloc(pSaveBuffer, dwDataLength + ((PWAVEHDR)lParam)->dwBytesRecorded); if (pNewBuffer == NULL) { waveInClose(hWaveIn); //发送MM_WIM_CLOSE消息 MessageBeep(MB_ICONEXCLAMATION); MessageBox(hwnd, szMemError, szAppName, MB_ICONEXCLAMATION | MB_OK); return TRUE; } pSaveBuffer = pNewBuffer; //将新录制的声音数据拷贝到新缓冲区后面。注意上面的realloc会保存原有的数据 CopyMemory(pSaveBuffer + dwDataLength, ((PWAVEHDR)lParam)->lpData, ((PWAVEHDR)lParam)->dwBytesRecorded); dwDataLength += ((PWAVEHDR)lParam)->dwBytesRecorded; if (bEnding) //按了“End”按钮来结束录制时 { waveInClose(hWaveIn); return TRUE; } //将当前使用的缓冲区作为新的缓冲区,发送给输入设备(该缓冲区将被重新覆盖录音) //注意即使不发送新的缓冲区给输入设备,录音也还在进行,只是数据被丢弃了。 waveInAddBuffer(hWaveIn, (PWAVEHDR)lParam, sizeof(WAVEHDR)); return TRUE; case MM_WIM_CLOSE: //释放缓冲区 waveInUnprepareHeader(hWaveIn, pWaveHdr1, sizeof(WAVEHDR)); waveInUnprepareHeader(hWaveIn, pWaveHdr2, sizeof(WAVEHDR)); free(pBuffer1); free(pBuffer2); //启用或禁用相关的按钮 EnableWindow(GetDlgItem(hwnd, IDC_RECORD_BEG), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_RECORD_END), FALSE); SetFocus(GetDlgItem(hwnd, IDC_RECORD_BEG)); if (dwDataLength>0) { EnableWindow(GetDlgItem(hwnd, IDC_PLAY_BEG), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_PAUSE), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_END), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_REV), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_REP), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_SPEED), TRUE); } bRecording = FALSE; if (bTerminating) //如果是按下了关闭按钮 SendMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0L); return TRUE; /*----------播放函数的消息,共3个(MM_WOM_OPEN、MM_WOM_DONE、MM_WOM_CLOSE)------------*/ case MM_WOM_OPEN: //启用或禁用相应按钮 EnableWindow(GetDlgItem(hwnd, IDC_RECORD_BEG), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_RECORD_END), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_BEG), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_PAUSE), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_END), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_REV), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_REP), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_SPEED), FALSE); SetFocus(GetDlgItem(hwnd, IDC_PLAY_END)); //设置wav头信息 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; //准备并写入输出设备,播放完会发送MM_WOM_DONE消息 waveOutPrepareHeader(hWaveOut, pWaveHdr1, sizeof(WAVEHDR)); waveOutWrite(hWaveOut, pWaveHdr1, sizeof(WAVEHDR)); //播放开始 bEnding = FALSE; bPlaying = TRUE; return TRUE; case MM_WOM_DONE: waveOutUnprepareHeader(hWaveOut, pWaveHdr1, sizeof(WAVEHDR)); waveOutClose(hWaveOut); //发送MM_WOM_CLOSE消息 return TRUE; case MM_WOM_CLOSE: //启用或禁用相应按钮 EnableWindow(GetDlgItem(hwnd, IDC_RECORD_BEG), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_RECORD_END), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_BEG), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_PAUSE), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_END), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_REV), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_REP), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_SPEED), TRUE); SetFocus(GetDlgItem(hwnd, IDC_PLAY_BEG)); SetDlgItemText(hwnd, IDC_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; waveInReset(hWaveIn); //发送MM_WIM_DATA消息 return TRUE; } if (bPlaying) { bTerminating = TRUE; bEnding = TRUE; waveOutReset(hWaveOut); //发送MM_WOM_CLOSE消息 return TRUE; } if (pWaveHdr1) free(pWaveHdr1); if (pWaveHdr2) free(pWaveHdr2); if(pSaveBuffer) free(pSaveBuffer); EndDialog(hwnd, 0); return TRUE; } break; } return FALSE; }
//resource.h
//{{NO_DEPENDENCIES}} // Microsoft Visual C++ 生成的包含文件。 // 供 Record1.rc 使用 // #define IDC_RECORD_BEG 1001 #define IDC_RECORD_END 1002 #define IDC_PLAY_BEG 1003 #define IDC_PLAY_PAUSE 1004 #define IDC_PLAY_END 1005 #define IDC_PLAY_REV 1006 #define IDC_PLAY_REP 1007 #define IDC_PLAY_SPEED 1008 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 102 #define _APS_NEXT_COMMAND_VALUE 40001 #define _APS_NEXT_CONTROL_VALUE 1002 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif
//record.rc
// Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "winres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // 中文(简体,中国) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS) LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""winres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Dialog // RECORD DIALOGEX 0, 0, 181, 96 STYLE DS_SETFONT | DS_MODALFRAME | 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",IDC_RECORD_BEG,43,17,37,16 PUSHBUTTON "End",IDC_RECORD_END,97,17,37,16 PUSHBUTTON "Play",IDC_PLAY_BEG,20,43,37,16 PUSHBUTTON "Pause",IDC_PLAY_PAUSE,72,43,37,16 PUSHBUTTON "End",IDC_PLAY_END,124,43,37,16 PUSHBUTTON "Reverse",IDC_PLAY_REV,20,66,37,16 PUSHBUTTON "Repeat",IDC_PLAY_REP,72,66,37,16 PUSHBUTTON "SpeedUp",IDC_PLAY_SPEED,124,66,37,16 END ///////////////////////////////////////////////////////////////////////////// // // DESIGNINFO // #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO BEGIN "RECORD", DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 174 TOPMARGIN, 7 BOTTOMMARGIN, 89 END END #endif // APSTUDIO_INVOKED #endif // 中文(简体,中国) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED
22.2.5 使用MCI的录音机
(1)MciSendCommand函数
参数 |
说明 |
MCIDEVICEID IDDevice |
接受命令的设备ID,则MCI_OPEN命令的wDeviceID变量返回 |
UINT uMsg |
//指定如何控制设备,详细请查阅“MCI指令”列表 |
DWORD fdwCommand |
Flags列表区,一般都与dwParam中的相关成配合使用 |
DWORD dwParam |
一般是一个数据结构,程序在使用mciSendCommand命令访问MCI时需要的或者是返回的一些信息 |
(2)MCI命令列表——详细请看这里《MciSendCommand用法详解》
①MCI_OPEN命令——打开当前设备,并返回设备ID(保存在MCI_OPEN_PARMS结构体中)
★★★★MCI_OPEN_PARMS结构体★★★
字段 |
说明 |
dwCallback |
低位字为MCI_NOTIFY flag 指定一个窗口句柄 |
wDeviceID |
成功打开的文件返回设备的标识符。(注意MCI_OPEN命令中的第1个参数为NULL,返回的ID将保存在该字段中) |
lpstrDeviceType |
设备类型的名字或常量标识。 MCI_ALL_DEVICE_ID——所有设备 MCI_DEVTYPE_ANIMATION——动画设备(Animation) MCI_DEVTYPE_CD_AUDIO——CD音频(cdaudio) MCI_DEVTYPE_DAT——数字音频(dat) MCI_DEVTYPE_DIGITAL_VIDEO——数字视频(digitalvideo) MCI_DEVTYPE_OTHER——未定义设备(other) MCI_DEVTYPE_OVERLAY——重叠视频(overlay) MCI_DEVTYPE_SCANNER——扫描仪(scanner) MCI_DEVTYPE_SEQUENCER——序列器(sequencer MIDI) MCI_DEVTYPE_VCR——合式录像机(vcr) MCI_DEVTYPE_VIDEODISC——激光视盘(videodisc) MCI_DEVTYPE_WAVEFORM_AUDIO——音频(waveaudioWave) |
lpstrElementName |
设备元素 (通常是打开的文件全路径). |
lpstrAlias |
可选别名. |
★★★★MCI_OPEN中可用的FLAGS★★★
适用范围 |
Flags |
说明 |
通用 |
MCI_OPEN_ALIAS |
对应 MCI_OPEN_PARMS结构中的 LPCSTR lpstrAlias 成员变量,为打开的设备起个别名 |
MCI_OPEN_SHAREABLE |
将设备或文件以共享的方式打开 |
|
MCI_OPEN_TYPE |
对应 MCI_OPEN_PARMS结构中的 LPCSTR lpstrDeviceType 成员变量,设备类型的名字或常量标识. (设备名可以从注册表或者 SYSTEM.INI 文件中获得) |
|
MCI_OPEN_TYPE_ID |
和 MCI_OPEN_TYPE flag 一起使用后,我们可以在 MCI_OPEN_PARMS结构中的 lpstrDeviceType 成员变量的低字中得到一个标准的MCI 设备的类型ID,同时在高字中指出该设备ID 此时在系统里的顺序索引号。 |
|
compound devices |
MCI_OPEN_ELEMENT |
对应 MCI_OPEN_PARMS结构中的 LPCSTR lpstrElementName 成员变量,设备元素 (通常是打开的文件全路径). |
MCI_OPEN_ELEMENT_ID |
和 MCI_OPEN_ELEMENT flag 一起使用后,我们可以将 MCI_OPEN_PARMS结构中的 lpstrElementName 成员变量看成是一个doubleword value,表示一个内部的设备。 |
|
数字视频 |
MCI_DGV_OPEN_NOSTATIC、MCI_DGV_OPEN_PARENT、 MCI_DGV_OPEN_WS、 MCI_DGV_OPEN_16BIT、MCI_DGV_OPEN_32BIT |
|
重叠视频 |
MCI_OVLY_OPEN_PARENT、MCI_OVLY_OPEN_WS |
|
音频设备 |
MCI_WAVE_OPEN_BUFFER |
对应 MCI_WAVE_OPEN_PARMS、(替代了MCI_OPEN_PARMS)结构中的 DWORD dwBufferSeconds 成员变量,用来设置读写音频的数据缓冲长度。 |
②MCI_SAVE:保存当前文件。在保存文件操作之前,设备可以修改当前打开的文件,但不会影响到原来保存在磁盘上的原文件
★★★★MCI_SAVE_PARMS结构体★★★
字段 |
含义 |
dwCallback |
目标窗口句柄或回调函数 |
lpfilename |
指出存盘目标文件名 |
★★★★MCI_SAVE中可用的FLAGS标志★★★
MCI_SAVE_FILE |
应用于所有设备。在MCI_SAVE_PARMS结构体中的 lpfilename 成员指出存盘目标文件名 |
③MCI_PLAY:播放当前的声音文件
★★★★MCI_PLAY_PARMS结构体★★★
字段 |
含义 |
dwCallback |
低位字为MCI_NOTIFY标志,指定一个窗口句柄. |
dwFrom |
播放起始点 |
dwTo |
播放结束点 |
★★★★MCI_PLAY中可用的FLAGS标志★★★
FLAGS |
说明 |
MCI_FROM |
让MCI_PLAY 使用上面结构中dwFrom。可以使用 MCI_SET 命令的MCI_SET_TIME_FORMAT标志设定时间格式。缺省播放会从当前位置开始 |
MCI_TO |
用法和MCI_FROM 相同,播放结束于dwTo。缺省停止位置是媒体的结束位置 |
④MCI_RECORD:从当前位置开始或在一个指定区段中录音
★★★★MCI_RECORD_PARMS结构体★★★
字段 |
含义 |
dwCallback |
低位字为MCI_NOTIFY标志,指定一个窗口句柄. |
dwFrom |
播放起始点 |
dwTo |
播放结束点 |
★★★★MCI_RECORD中可用的FLAGS标志★★★
FLAGS |
说明 |
MCI_FROM|MCI_TO |
使MCI_RECORD_PARMS结构体中的dwFrom,dwTo起作用。如果没有使用这两个标志,MCI_RECORD缺省的起始录音位置是当前位置;缺省的结束位置 |
MCI_RECORD_INSERT |
最新的录音会被插入或粘贴到当前的wave文件中。这是MCI_RECORD命令缺省设置,但有些设备可能不支持此标志。 |
MCI_RECORD_OVERWRITE |
最新录音将覆盖现存打开的文件。MCIWAVE.DRV 设备返回MCIERR_UNSUPPORTED_FUNCTION 响应这个标志。 |
⑤MCI_SET:设置设备信息(设置时间格式及播放速度等)
★★★★MCI_SET_PARMS结构体★★★
字段 |
含义 |
dwCallback |
低位字为MCI_NOTIFY标志,指定一个窗口句柄. |
dwTimeFormat |
设置时间格式 时间格式常量: MCI_FORMAT_BYTES 比特(使用 脉冲编码调制[PCM]格式的waveaudio 类型文件) MCI_FORMAT_MILLISECONDS 设置时间单位为毫秒 MCI_FORMAT_MSF (分 / 秒 / 帧)Minute / second / frame MCI_FORMAT_SAMPLES 采样 Samples MCI_FORMAT_SMPTE_24 SMPTE(电影与电视工程师学会[美]), 24 帧 MCI_FORMAT_SMPTE_25 SMPTE, 25 帧 MCI_FORMAT_SMPTE_30 SMPTE, 30 帧 MCI_FORMAT_SMPTE_30DROP SMPTE, 30 frame drop MCI_FORMAT_TMSF Track / minute / second / frame MCI_SEQ_FORMAT_SONGPTR MIDI song pointer |
dwAudio |
音频输出声道编号(相关FLAG:MCI_SET_AUDIO) |
注意:对于waveform-audio设备,使用的是MCI_WAVE_SET_PARMS结构体 |
★★★★MCI_SET中可用的FLAGS标志★★★
FLAGS |
说明 |
MCI_SET_AUDIO |
使 dwAudio 成员起作用。该flag必须配合MCI_SET_ON 或 MCI_SET_OFF使用 |
MCI_SET_AUDIO_ALL、 MCI_SET_AUDIO_LEFT、 MCI_SET_AUDIO_RIGHT |
所有声道、左声道、右声道 |
MCI_SET_DOOR_CLOSED、 MCI_SET_DOOR_OPEN |
关闭、打开设备面版(一般用在CD设备) |
MCI_SET_OFF、MCI_SET_ON |
设置视频信号(video signal)开关状态,与MCI_SET_VIDEO标志一起使用。 |
MCI_SET_TIME_FORMAT |
设置时间格式 |
MCI_FORMAT_HMS |
格式:时 / 分 / 秒 |
【Record2程序】
1、效果图:与 Record1一样,但Reverse、Repeat、SpeedUp等“特效”按钮不可用
2、Resource.h和record.rc文件与Record1相同
/*---------------------------------------------------- RECORD2.C —— Waveform Audio Recorder (c) Charles Petzold,1998 ----------------------------------------------------*/ #include <Windows.h> #include "resource.h" #pragma comment(lib,"WINMM.LIB") #define INP_BUFFER_SIZE 16384 //16K,即16*1024 BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM); TCHAR szAppName[] = TEXT("Record2"); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInStance, PSTR szCmdLine, int iCmdShow) { if (-1 == DialogBox(hInstance,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; //一般的结构体,只有dwCallback字段 MCI_OPEN_PARMS mciOpen; MCI_PLAY_PARMS mciPlay; MCI_RECORD_PARMS mciRecord; MCI_SAVE_PARMS mciSave; RECT rect; switch (message) { case WM_INITDIALOG: GetWindowRect(hwnd, &rect); SetWindowPos(hwnd, NULL, (GetSystemMetrics(SM_CXSCREEN) - rect.right + rect.left) / 2, (GetSystemMetrics(SM_CYSCREEN) - rect.bottom + rect.top) / 2, rect.right- rect.left,rect.bottom-rect.top,SWP_SHOWWINDOW); return TRUE; case WM_COMMAND: switch (LOWORD(wParam)) { /*-----------------------------录制按钮过程--------------------------------------*/ case IDC_RECORD_BEG: //删除己经存在的音频文件 DeleteFile(szFileName); //打开音频输入设备 mciOpen.dwCallback = 0; mciOpen.wDeviceID = 0; mciOpen.lpstrDeviceType = TEXT("waveaudio"); //设备类型的名字或常量标识,标志位为MCI_OPEN_TYPE mciOpen.lpstrElementName = TEXT(""); //要设置为长度为0的字符串。但在播放时,可指定要播放的文件名。 mciOpen.lpstrAlias = NULL; //打开设备时,第1个参数为0,函数返回时,会自动填充mciOpen结构体的wDeviceID字段 // MCI_WAIT 等待,直到输入设备完成所要求的行动才返回控制权 // MCI_OPEN_TYPE 表示要使用MCI_OPEN_PARMS结构中的LpstrDiviceType参数 // MCI_OPEN_ELEMENT 表示LpstrDeviceType参数中的是设备表述字符串 // 还可以使用 MCI_OPEN_TYPE_ID 表示LpstrDeviceType参数中的是设备标识 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; // MCI_NOTIFY 标志导致录音结束后系统向mciRecord.dwCallback元素中 //指定的窗口句柄发送一条MM_MCINOTIFY通知消息,如使用MCI_STOP或MCI_PAUSE //或录制时磁盘空间不足时会发送MM_MCINOTIFY消息。本例没有使用MCI_FROM和 //MCI_TO标志,每次录制时新的声音数据都会被插入到文件开始的地方 mciSendCommand(wDeviceID, MCI_RECORD, MCI_NOTIFY, (DWORD)(LPMCI_RECORD_PARMS)&mciRecord); //启用或禁用相关按钮 EnableWindow(GetDlgItem(hwnd, IDC_RECORD_BEG), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_RECORD_END), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_BEG), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_END), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_PAUSE), FALSE); SetFocus(GetDlgItem(hwnd, IDC_RECORD_END)); bRecording = TRUE; return TRUE; /*---------------------------录制结束按钮过程------------------------------------*/ case IDC_RECORD_END: //停止录音 mciGeneric.dwCallback = 0; // MCI_STOP 命令消息用于停止当前的录音 mciSendCommand(wDeviceID, MCI_STOP, MCI_WAIT, (DWORD)(LPMCI_GENERIC_PARMS)&mciGeneric); //保存声音数据到指定的文件中 mciSave.dwCallback = 0; mciSave.lpfilename = szFileName; //MCI_SAVE对当前录制在临时文件中的声音进行保持 //MCI_SAVE_FILE标志指出保存的文件名在mciSave.lpfileName字段指定中 mciSendCommand(wDeviceID, MCI_SAVE, MCI_WAIT | MCI_SAVE_FILE, (DWORD)(LPMCI_SAVE_PARMS)&mciSave); //MCI_CLOSE用于删除所有的临时文件,释放己经建立的内存块,并关闭输入设备 mciSendCommand(wDeviceID, MCI_CLOSE, MCI_WAIT, (DWORD)(LPMCI_GENERIC_PARMS)&mciGeneric); //启用或禁用相应的按钮 EnableWindow(GetDlgItem(hwnd, IDC_RECORD_BEG), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_RECORD_END), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_BEG), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_END), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_PAUSE), FALSE); SetFocus(GetDlgItem(hwnd, IDC_PLAY_BEG)); //录音结束标志 bRecording = FALSE; return TRUE; /*-----------------------------播放按钮过程--------------------------------------*/ case IDC_PLAY_BEG: //打开音频设备 mciOpen.dwCallback = 0; mciOpen.wDeviceID = 0; mciOpen.lpstrDeviceType = NULL; mciOpen.lpstrElementName = szFileName; //要播放的文件名 mciOpen.lpstrAlias = NULL; dwError = mciSendCommand(0, MCI_OPEN, MCI_WAIT | MCI_OPEN_ELEMENT, (DWORD)(LPMCI_OPEN_PARMS)&mciOpen); if (dwError !=0) { ShowError(hwnd, dwError); return TRUE; } //保存设备ID wDeviceID = mciOpen.wDeviceID; //开始播放声音 mciPlay.dwCallback = (DWORD)hwnd; //播放结束会发送MM_MCINOTIFY消息 mciPlay.dwFrom = 0; mciPlay.dwTo = 0; mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY, (DWORD)(LPMCI_PLAY_PARMS)&mciPlay); //启用或禁用相关的按钮 EnableWindow(GetDlgItem(hwnd, IDC_RECORD_BEG), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_RECORD_END), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_BEG), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_END), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_PAUSE), TRUE); SetFocus(GetDlgItem(hwnd, IDC_PLAY_END)); bPlaying = TRUE; return TRUE; /*-----------------------------暂停播放按钮过程--------------------------------------*/ case IDC_PLAY_PAUSE: if (!bPaused) { //暂停 mciGeneric.dwCallback = 0; mciSendCommand(wDeviceID, MCI_PAUSE, MCI_WAIT, //会发送MM_MCINOTIFY消息 (DWORD)(LPMCI_GENERIC_PARMS)&mciGeneric); SetDlgItemText(hwnd, IDC_PLAY_PAUSE, TEXT("Resume")); bPaused = TRUE; } else { mciPlay.dwCallback = (DWORD)hwnd; mciPlay.dwFrom = 0; mciPlay.dwTo = 0; //没指定MCI_FROM和MCI_TO标志,默认会从当前位置开始 mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY, (DWORD)(LPMCI_PLAY_PARMS)&mciPlay); SetDlgItemText(hwnd, IDC_PLAY_PAUSE, TEXT("Pause")); bPaused = FALSE; } return TRUE; /*----------------------------停止播放按钮过程------------------------------------*/ case IDC_PLAY_END: //停止播放 mciGeneric.dwCallback = 0; mciSendCommand(wDeviceID, MCI_STOP, MCI_WAIT, //会发送MM_MCINOTIFY消息 (DWORD)(LPMCI_GENERIC_PARMS)&mciGeneric); //关闭音频设备 mciSendCommand(wDeviceID, MCI_CLOSE, MCI_WAIT, (DWORD)(LPMCI_GENERIC_PARMS)&mciGeneric); EnableWindow(GetDlgItem(hwnd, IDC_RECORD_BEG), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_RECORD_END), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_BEG), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_PAUSE), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_END), FALSE); SetFocus(GetDlgItem(hwnd, IDC_PLAY_BEG)); bPlaying = FALSE; bPaused = FALSE; return TRUE; /*----------------------------反转播放按钮过程------------------------------------*/ case IDC_PLAY_REV: return TRUE; /*----------------------------重复播放按钮过程------------------------------------*/ case IDC_PLAY_REP: return TRUE; /*----------------------------快进播放按钮过程------------------------------------*/ case IDC_PLAY_SPEED: return TRUE; } break; /*----------录制或磁盘己满、停止播放或暂停播放或播放结束会产生该消息------------*/ //MCI_STOP、MCI_PAUSE——当按下End或Pause按钮时,wParam为MCI_NOTIFY_ABORTED,己经在相应的按 // 钮过程中处理了相关的逻辑,在本消息中可以忽略。 //MCI_PLAY——当声音播放完,wParam为MCI_NOTIFY_SUCCESSFUL. //MCI_RECORD——当磁盘空间不足时,wParam为MCI_NOTIFY_SUCCESSFUL。(严格来讲是不成功的) case MM_MCINOTIFY: switch (wParam) { case MCI_NOTIFY_SUCCESSFUL: if (bPlaying) //当播放完,会收到该消息 SendMessage(hwnd, WM_COMMAND, IDC_PLAY_END, 0); if (bRecording) //磁盘空间不足时 SendMessage(hwnd, WM_COMMAND, IDC_RECORD_END, 0); return TRUE; } break; case WM_SYSCOMMAND: switch (LOWORD(wParam)) { case SC_CLOSE: //当关闭按钮时 if (bRecording) //正在录制时,则停止录制 SendMessage(hwnd, WM_COMMAND, IDC_RECORD_END, 0); if (bPlaying) //如果正在播放时,则停止播放 SendMessage(hwnd, WM_COMMAND, IDC_PLAY_END, 0); EndDialog(hwnd, 0); return TRUE; } break; } return FALSE; }
22.2.6 用MCI命令字符串的方法
(1)此例是基于文本的MCI接口中,与上例基于消息的MCI接口程序的结构上对应很很好。其实MCI就是把命令串翻译成对应的命令消息和数据结构。
(2)本例没有使用MM_MCINOTIFY消息(可以实现)。导致程序不知道什么时候波形文件播放结束(必手动按下End按钮)
(3)MCI的open命令中用到alias关键词。这个关键词允许所有随后的MCI命令使用别名来指明设备。
【Record3程序】
/*---------------------------------------------------- RECORD3.C —— Waveform Audio Recorder (c) Charles Petzold,1998 ----------------------------------------------------*/ #include <Windows.h> #include "..\\Record1\\resource.h" //Record1程序中的资源头文件 //同时要导入Record.rc文件,方法:资源文件-》添加-》现有项 #pragma comment(lib,"WINMM.LIB") BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM); TCHAR szAppName[] = TEXT("Record3"); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInStance, PSTR szCmdLine, int iCmdShow) { if (-1 == DialogBox(hInstance,TEXT("Record"),NULL,DlgProc)) { MessageBox(NULL, TEXT("This program requires Windows NT!"), szAppName, MB_ICONERROR); } return 0; } BOOL mciExecute(LPCTSTR szCommand) { MCIERROR error; TCHAR szErrorStr[1024]; //mciSendString返回0时表示成功。 if (error = mciSendString(szCommand,NULL,0,NULL)) { mciGetErrorString(error, szErrorStr, sizeof(szErrorStr) / sizeof(TCHAR)); MessageBeep(MB_ICONEXCLAMATION); MessageBox(NULL, szErrorStr, szAppName, MB_OK | MB_ICONEXCLAMATION); } return error == 0; } BOOL CALLBACK DlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static BOOL bRecording, bPlaying, bPaused; TCHAR szFileName[] = TEXT("record3.wav"); RECT rect; switch (message) { case WM_INITDIALOG: GetWindowRect(hwnd, &rect); SetWindowPos(hwnd, NULL, (GetSystemMetrics(SM_CXSCREEN) - rect.right + rect.left) / 2, (GetSystemMetrics(SM_CYSCREEN) - rect.bottom + rect.top) / 2, rect.right- rect.left,rect.bottom-rect.top,SWP_SHOWWINDOW); return TRUE; case WM_COMMAND: switch (LOWORD(wParam)) { /*-----------------------------录制按钮过程--------------------------------------*/ case IDC_RECORD_BEG: //删除己经存在的音频文件 DeleteFile(szFileName); //打开音频输入设备 //alias指定音频设备别名为mysound,以后可以直接用这个别名来使用该设备 if (!mciExecute(TEXT("open new type waveaudio alias mysound"))) return TRUE; //录制音频 mciExecute(TEXT("record mysound")); //启用或禁用相关按钮 EnableWindow(GetDlgItem(hwnd, IDC_RECORD_BEG), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_RECORD_END), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_BEG), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_END), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_PAUSE), FALSE); SetFocus(GetDlgItem(hwnd, IDC_RECORD_END)); bRecording = TRUE; return TRUE; /*---------------------------录制结束按钮过程------------------------------------*/ case IDC_RECORD_END: //停止录音 mciExecute(TEXT("stop mysound")); mciExecute(TEXT("save mysound record3.wav")); mciExecute(TEXT("close mysound")); //启用或禁用相应的按钮 EnableWindow(GetDlgItem(hwnd, IDC_RECORD_BEG), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_RECORD_END), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_BEG), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_END), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_PAUSE), FALSE); SetFocus(GetDlgItem(hwnd, IDC_PLAY_BEG)); //录音结束标志 bRecording = FALSE; return TRUE; /*-----------------------------播放按钮过程--------------------------------------*/ case IDC_PLAY_BEG: //打开音频设备 if (!mciExecute(TEXT("open record3.wav alias mysound"))) return TRUE; //开始播放声音 mciExecute(TEXT("play mysound")); //启用或禁用相关的按钮 EnableWindow(GetDlgItem(hwnd, IDC_RECORD_BEG), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_RECORD_END), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_BEG), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_END), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_PAUSE), TRUE); SetFocus(GetDlgItem(hwnd, IDC_PLAY_END)); bPlaying = TRUE; return TRUE; /*-----------------------------暂停播放按钮过程--------------------------------------*/ case IDC_PLAY_PAUSE: if (!bPaused) { //暂停 mciExecute(TEXT("pause mysound")); SetDlgItemText(hwnd, IDC_PLAY_PAUSE, TEXT("Resume")); bPaused = TRUE; } else { mciExecute(TEXT("play mysound")); SetDlgItemText(hwnd, IDC_PLAY_PAUSE, TEXT("Pause")); bPaused = FALSE; } return TRUE; /*----------------------------停止播放按钮过程------------------------------------*/ case IDC_PLAY_END: //停止播放 mciExecute(TEXT("stop mysound")); //关闭音频设备 mciExecute(TEXT("close mysound")); EnableWindow(GetDlgItem(hwnd, IDC_RECORD_BEG), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_RECORD_END), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_BEG), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_PAUSE), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_PLAY_END), FALSE); SetFocus(GetDlgItem(hwnd, IDC_PLAY_BEG)); bPlaying = FALSE; bPaused = FALSE; return TRUE; /*----------------------------反转播放按钮过程------------------------------------*/ case IDC_PLAY_REV: return TRUE; /*----------------------------重复播放按钮过程------------------------------------*/ case IDC_PLAY_REP: return TRUE; /*----------------------------快进播放按钮过程------------------------------------*/ case IDC_PLAY_SPEED: return TRUE; } break; case WM_SYSCOMMAND: switch (LOWORD(wParam)) { case SC_CLOSE: //当关闭按钮时 if (bRecording) //正在录制时,则停止录制 SendMessage(hwnd, WM_COMMAND, IDC_RECORD_END, 0); if (bPlaying) //如果正在播放时,则停止播放 SendMessage(hwnd, WM_COMMAND, IDC_PLAY_END, 0); EndDialog(hwnd, 0); return TRUE; } break; } return FALSE; }
标签:
原文地址:http://www.cnblogs.com/5iedu/p/4715214.html