There are many ways to read PCM data from a microphone on the Internet. I just released a directsound microphone PCM Data Collection class I wrote here. Through this class, we can easily use directsound technology to collect microphone data, developers do not have to worry too much about whether they will program directsound. They can easily concentrate on the program itself rather than the details. This is the header file: # pragma once # Ifndef _ capture_sound_h _ # DEFINE _ capture_sound_h _ # Include <mmsystem. h> # Include <dsound. h> # define num_rec_configurications 16 class cadoframehandler { Public: Virtual void adoframedata (byte * pbuffer, long lbuffersize) = 0; }; Class ccaptureaudio { Public: Bool m_brecording; // recording now? Also used by event Recv thread protected: Lpdirectsoundcapture8 m_pcapdev; // capture device PTR Lpdirectsoundcapturebuffer m_pcapbuf; // capture loop buffer PTR Lpdirectsoundpolicy8 m_pnotify; // capture auto-inform y Event Callback handler PTR guid m_guidcapdevid; // capture device ID Waveformatex m_wfxinput; // input wave format description struct dsbpositiony y m_aposnotify [num_rec_configurications + 1]; // notify flag Array Handle m_hpolicyevent; // handle Y event Bool m_abinputfmtsupported [20]; DWORD m_dwcapbufsize; // capture loop buffer size DWORD m_dwnextcapoffset; // offset in loop buffer DWORD m_dwpolicysize; // adjust y POS when loop buffer need to emit the event cadoframehandler * m_frame_handler; // outer frame data dealer PTR Public: // callback func to add Enum devices string name Static bool callback enum_dev_proc (lpguid, lpctstr lpszdesc, Lpctstr lpszdrvname, lpvoid lpcontext); static uint policy_capture_thd (lpvoid data); protected: Hresult initdirectsound (guid dev_id = guid_null ); Hresult freedirectsound (); Hresult initnotifications (); Hresult createcapturebuffer (waveformatex * WFX ); Hresult startorstoprecord (bool bstartrec ); Hresult recordcaptureddata (); Void setwavformat (waveformatex * WFX); public: Ccaptureaudio (void ); ~ Ccaptureaudio (void ); Bool enumdevices (hwnd hlist ); Bool open (void ); Bool close (); Void grabaudioframes (bool bgrabaudioframes, cadoframehandler * frame_handler ); }; # Below endif is the CPP file: # include "stdafx. H" # Include "./captureaudio. H" # Include <mmsystem. h> # Include <dsound. h> # ifndef safe_delete # Define safe_delete (p) {If (p) {Delete (p); (p) = NULL ;}} # Endif # ifndef safe_release # Define safe_release (p) {If (p) {(P)-> release (); (p) = NULL ;}} # Endif # ifndef Max # Define max (A, B) (a)> (B )? (A): (B )) # Endif ccaptureaudio: ccaptureaudio (void) { If (failed (coinitialize (null)/*, coinit_apartmentthreaded )))*/ { Afxmessagebox ("ccaptureaudio coinitialize failed! /R/N "); Return; } M_pcapdev = NULL; M_pcapbuf = NULL; M_pnotify = NULL; // set default wave format PCM Zeromemory (& m_wfxinput, sizeof (m_wfxinput )); M_wfxinput.wformattag = wave_format_pcm; m_guidcapdevid = guid_null; M_brecording = false; M_hpolicyevent = NULL; } Ccaptureaudio ::~ Ccaptureaudio (void) { Couninitialize (); } Bool callback ccaptureaudio: enum_dev_proc (lpguid, lpctstr lpszdesc, Lpctstr lpszdrvname, lpvoid lpcontext) { Hwnd hlist = (hwnd) lpcontext; If (! Hlist) return false; Lpguid lptemp = NULL; If (lpguid! = NULL ){ // Null only for "primary sound driver ". If (lptemp = (lpguid) malloc (sizeof (guid) = NULL) Return (true ); Memcpy (lptemp, lpguid, sizeof (guid )); } : Sendmessage (hlist, cb_addstring, 0, (lparam) lpszdesc ); : Sendmessage (hlist, lb_setitemdata, 0, (lparam) lptemp ); Free (lptemp ); Return (true ); } Uint ccaptureaudio: notify_capture_thd (lpvoid data) { Ccaptureaudio * pado = static_cast <ccaptureaudio *> (data ); MSG; Hresult hr; DWORD dwresult; While (pado-> m_brecording ){ Dwresult = msgwaitformultipleobjects (1, & (pado-> m_hpolicyevent), false, infinite, qs_allevents ); Switch (dwresult ){ Case wait_object_0 + 0: // G_hnotificationevents [0] is signaled // This means that directsound just finished playing // A piece of the buffer, so we need to fill the Circular // Buffer with new sound from the wav file if (failed (hR = pado-> recordcaptureddata ())){ Afxmessagebox ("error handling directsound events ."); Pado-> m_brecording = false; } Break; Case wait_object_0 + 1: // Windows messages are available While (peekmessage (& MSG, null, 0, 0, pm_remove )){ Translatemessage (& MSG ); Dispatchmessage (& MSG ); If (msg. Message = wm_quit) pado-> m_brecording = false; } Break; } } Afxendthread (0, true ); Return 0; } Bool ccaptureaudio: enumdevices (hwnd hlist) { If (failed (directsoundcaptureenumerate ( (Lpdsenumcallback) (ccaptureaudio: enum_dev_proc ), (Void *) & hlist ))) { Return (false ); } Return (true ); } Bool ccaptureaudio: open (void) { Hresult hr; If (! M_brecording ){ HR = initdirectsound (); } Return (failed (HR ))? False: true; } Bool ccaptureaudio: Close () { Hresult hr; HR = freedirectsound (); Closehandle (m_hpolicyevent ); Return (failed (HR ))? False: true; } Hresult ccaptureaudio: initdirectsound (guid dev_id) { Hresult hr; M_guidcapdevid = dev_id; zeromemory (& m_aposnotify, sizeof (dsbpositionications y) * (num_rec_ications ications + 1 )); M_dwcapbufsize = 0; M_dwpolicysize = 0; // create idirectsoundcapture using the preferred capture device HR = directsoundcapturecreate (& m_guidcapdevid, & m_pcapdev, null); // init wave format Setwavformat (& m_wfxinput); Return (failed (HR ))? S_false: s_ OK; } Hresult ccaptureaudio: freedirectsound () { // Release directsound Interfaces Safe_release (m_pnotify ); Safe_release (m_pcapbuf ); Safe_release (m_pcapdev ); Return s_ OK; } Hresult ccaptureaudio: createcapturebuffer (waveformatex * WFX) { Hresult hr; Dscbufferdesc dscbd; safe_release (m_p1_y ); Safe_release (m_pcapbuf); // set the notification size M_dwpolicysize = max (1024, WFX-> navgbytespersec/8 ); M_dwpolicysize-= m_dwpolicysize % WFX-> nblockalign; // set the Buffer Sizes M_dwcapbufsize = m_dwpolicysize * num_rec_configurications; safe_release (m_pnotify ); Safe_release (m_pcapbuf); // create the capture Buffer Zeromemory (& dscbd, sizeof (dscbd )); Dscbd. dwsize = sizeof (dscbd ); Dscbd. dwbufferbytes = m_dwcapbufsize; Dscbd. lpwfxformat = WFX; // set the format during creatation if (failed (hR = m_pcapdev-> createcapturebuffer (& dscbd, & m_pcapbuf, null ))) Return s_false; m_dwnextcapoffset = 0; If (failed (hR = initnotifications ())) Return s_false; return s_ OK; } Hresult ccaptureaudio: initnotifications () { Hresult hr; Int I; If (null = m_pcapbuf) Return s_false; // create auto scaling y event M_hpolicyevent = createevent (null, false, false, null); // create a notification event, for when the sound stops playing If (failed (hR = m_pcapbuf-> QueryInterface (iid_idirectsoundnotify, (void **) & m_pnotify ))) Return s_false; // setup the notification positions For (I = 0; I <num_rec_ications ications; I ++ ){ M_aposnotify [I]. dwoffset = (m_dwpolicysize * I) + m_dwpolicysize-1; M_aposnotify [I]. heventpolicy = m_hpolicyevent; } // Tell directsound when to notify y us. The notification will come in the from // Of signaled events that are handled in winmain () If (failed (hR = m_pnotify-> setnotifposipositions (num_rec_ications ications, m_aposnotify ))) Return s_false; return s_ OK; } Hresult ccaptureaudio: startorstoprecord (bool bstartrec) { Hresult hr; If (bstartrec ){ // Create a capture buffer, and tell the capture // Buffer to start recording If (failed (hR = createcapturebuffer (& m_wfxinput ))) Return s_false; If (failed (hR = m_pcapbuf-> Start (dscbstart_looping ))) Return s_false; // create your y event Recv thread Afxbeginthread (ccaptureaudio: notify_capture_thd, (lpvoid) (this )); } Else { // Stop the capture and read any data that // Was not caught by a notification If (null = m_pcapbuf) Return s_ OK; // Wait until the policy_event_thd thread exit and release the resources. Sleep (500); // stop the buffer, and read any data that was not // Caught by a notification If (failed (hR = m_pcapbuf-> stop ())) Return s_ OK; If (failed (hR = recordcaptureddata ())) Return s_false; } Return s_ OK; } Hresult ccaptureaudio: recordcaptureddata () { Hresult hr; Void * pbcapturedata = NULL; DWORD dwcapturelength; Void * pbcapturedata2 = NULL; DWORD dwcaptureleng2; DWORD dwreadpos; DWORD dwcapturepos; Long llocksize; If (null = m_pcapbuf) Return s_false; If (failed (hR = m_pcapbuf-> getcurrentposition (& dwcapturepos, & dwreadpos ))) Return s_false; llocksize = dwreadpos-m_dwnextcapoffset; If (llocksize <0) Llocksize + = m_dwcapbufsize; // block align lock size so that we are always write on a boundary Llocksize-= (llocksize % m_dwpolicysize); If (llocksize = 0) Return s_false; // lock the capture buffer down If (failed (hR = m_pcapbuf-> lock (m_dwnextcapoffset, llocksize, & Pbcapturedata, & dwcapturelength, & Pbcapturedata2, & dwcaptureleng2, 0l ))) Return s_false; // call the outer Data Handler If (m_frame_handler ){ M_frame_handler-> adoframedata (byte *) pbcapturedata, dwcapturelength ); } // Move the capture offset along M_dwnextcapoffset + = dwcapturelength; M_dwnextcapoffset % = m_dwcapbufsize; // circular buffer if (pbcapturedata2! = NULL ){ // Call the outer Data Handler If (m_frame_handler ){ M_frame_handler-> adoframedata (byte *) pbcapturedata, dwcapturelength ); } // Move the capture offset along M_dwnextcapoffset + = dwcaptureleng2; M_dwnextcapoffset % = m_dwcapbufsize; // circular buffer } // Unlock the capture Buffer M_pcapbuf-> unlock (pbcapturedata, dwcapturelength, pbcapturedata2, dwcaptureleng22.); Return s_ OK; } Void ccaptureaudio: setwavformat (waveformatex * WFX) { // Get the default capture wave Formate Zeromemory (WFX, sizeof (waveformatex )); WFX-> wformattag = wave_format_pcm; // 8 kHz, 16 bits PCM, Mono WFX-> nsamplespersec = 8000; WFX-> wbitspersample = 16; WFX-> nchannels = 1; WFX-> nblockalign = WFX-> nchannels * (WFX-> wbitspersample/8 ); WFX-> navgbytespersec = WFX-> nblockalign * WFX-> nsamplespersec; } Void ccaptureaudio: grabaudioframes (bool bgrabaudioframes, cadoframehandler * frame_handler) { M_frame_handler = frame_handler; M_brecording = bgrabaudioframes; Startorstoprecord (m_brecording ); } It is also very simple to use. Here I declare a pure virtual class cadoframehandler. This class is specifically used to let users reload its pure virtual function. As long as it is reloaded, after the settings are correct, you can automatically start collecting audio data. Note that in this class, I use 8 kHz, 16 bits, and mono single-channel PCM data collection. First: # include "captureaudio. H" and then: Class cmyclass: Public cadoframehandler {... public: // override the cadoframehandler Void adoframedata (byte * pbuffer, long lbuffersize); // This class can be reloaded to collect protected: ccaptureaudio m_cap_ado; // This object is used to collect audio data }; in the oninitdialog class, we can use the following initialization method: open mic and initialize directsound: m_cap_ado.open (); start to collect sound: m_cap_ado.grabaudioframes (true, this); after calling it, as long as you reload the function above, directsound periodically collects data from the microphone and calls the function. To stop audio collection, set m_cap_ado.grabaudioframes (false, null) to disable MIC and release directsound: m_cap_ado.close (). In just a few steps, you can complete audio data collection for the microphone. If you have any questions, please contact us. |
|