Low-level audio functions Wavex play sound files in VC
Wang Ji Too 2004.08.08
-------------------------------------------------- -------------------------------------------------- -----------------
Abstract: This article discusses and implements methods of using low-level audio functions WAVEX playing sound files in VC .
-------------------------------------------------- -------------------------------------------------- -----------------
Windows uses advanced audio functions, media control interface MCI device drivers; low-level audio functions MIDI MAPPER, low-level audio device drivers, and DirectSound provide audio services, you can get audio streams from the sound card.
1. Other methods of playing sound files Before introducing the Wavex series, I will introduce several other ways to introduce:
1.1 MCI Method Introduction is convenient to use the MCI method, which is the same for media device control mainly through command interface functions MCISendCommand () or string interface function McISendString (). The two functions are the same. The command interface function is complicated than the command string, but it provides MCI with a more powerful control capability, the prototype of the two interface functions: McIDeRor McISendCommand (McIDEVICEID IDDEVICE, DWORD DWPARAM); McIrror McISendstring (LPCTSTR lpszCommand, LPTSTR lpszReturnString, UINT cchReturn, HANDLE hwndCallback); for example, to use mciSendCommand method, we first set the file to play in MCI_OPEN_PARMS and send MCI_OPEN command to open the sound device, sending MCI_PLAY command message playback, send MCI_STOP command after the close equipment. The specific use of them can be referred to MSDN.
1.2 PlaySound method BOOL sndPlaySound (LPCSTR lpszSound, UINT fuSound); BOOL PlaySound (LPCSTR pszSound, HMODULE hmod, DWORD fdwSound); wherein the path and file name parameter is required to play a sound lpszSound .WAV files, hmod here is NULL, fuSound Is the logo of playing sound, please refer to the help in VC for details. For example, playing c: /ason/music.wav can use SndPlaySound ("C: //Sound/Music.wav", SND_ASYNC), or Plays ("C: //Sound/Music.wav", NULL, SND_ASYNC | SND_NODEFAULT; if there is no Music.WAV file, the first format will play the system default sound, and the second format does not play the system default sound [1], which is the role of the SND_NODEFAULT flag. Of course, we can also use the sound file as a user-defined resource to join the program resource file. After the compilation connection generates an EXE file, you can realize the sound playback of the .wav file. It is also simple to use the above functions, as follows, iDR_Your_wave is the added WAVE file resource identifier: Plays (MakeintResource (NULL), GETMODULEHANDE (NULL), SND_RESOURCE); 2. Using the low-level audio function Wavex will enter the topic of the article below.
2.1 Overview
Low-level audio services and important data structural low-level audio services control different audio devices, including Wave, MIDI, and auxiliary audio equipment [2]. Low-level audio services include the following: (1) Query audio devices; (2) Open and close device drivers; (3) assign and prepare audio data blocks; (4) Manage audio data blocks; (5) Apply MMTIME structure; 6) Handling an error. 2.2 Important Messages and Data Structure Use the low-level audio function to operate to each sound data block, to be attributed to Windows message mapping, Windows will send the relevant message after collecting and playing a data block. The important message and trigger conditions involved in playing sound are as follows: mm_wom_close: When a waveform sound output device is turned off, the device handle is no longer effective mm_wom_done: When a given output cache is returned to the application, or call WaveoutReset The function stops playing and resets the manager mm_wom_open: When the given waveform sound output device is opened, MOM_CLOSE: When the MIDI output device is turned off, WOM_DONE: When the leaving buffer is played and is being returned, send it to the MIDI output callback function WOM_Open: When the MIDI output device is turned on
Important data structure: Waveform data format WAVEFORMAT / WAVEFORMATEX Waveform Data Buffer Format WaveHDR Audio Output Device Performance WaveoutCaps These contents are defined in MMSystem.h header files, see MSDN. 2.3 Wavex Play the rough process of the sound waveform file method
Common MMIO functions: mmioPen () opens a Riff file mmioDescend () into block mmioread (); should take the Riff file mmioascend (); jump out of the block mmioclose (); turn off the PIFF file For blocks, enter the block and jump out blocks are paired. . Read the WAV file reading process: mmioPen () Opens the file ↓ MmioDescend ("Wave") Enter "FMT" block ↓ mmioread () read WAVE file format information ↓ mmioascend () Jump out "FMT" block ↓ mmiodescend ("Data" ") Enter the" Data "block ↓ mmioread () read WAVE data information ↓ mmioclose () Close the file. The process of outputting the WAV file: Waveoutopen () Opens a output device ↓ WaveoutPrepareHeader () Prepare the Wave Data Head. WaveoutWrite () Write the data into the device and start playback ↓ WaveoutreSet () Stop play and reset the manager ↓ Waveoutclose () and close playback device ↓ WaveoutunpareHeader () Clean WaveoutPrepareHeader WWAVE 2.4 main program list
2.4.1 Playing section
void CPlayWaveDlg :: OnPlay () {LPSTR szFileName; // sound file name LPSTR szPathName; MMCKINFO mmckinfoParent; MMCKINFO mmckinfoSubChunk; DWORD dwFmtSize; DWORD m_WaveLong; WAVEFORMATEX * lpFormat; DWORD m_dwDataOffset; DWORD m_dwDataSize; WAVEOUTCAPS pwoc; LONG lSoundOffset; LONG lSoundLong;
CEDIT * PEDIT = (CEDIT *) Getdlgitem (IDC_FILE); PEDIT-> getWindowText (m_strfilename); if (m_strfilename == ") {showMSG (" Please select a Wave file to play! "); Return;}
Szpathname = m_strpathname.getBuffer (0); szfilename = m_strfilename.getBuffer (0);
// Open the waveform file if (! (M_hmmio = mmiopen (szpathname, null, mmio_read | mmio_allocbuff)) {/ * -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------- ----- Information Display Function Showmsg (): Void CPLAYWAVEDLG :: Showmsg (Char * SZMSG, ...) {VA_LIST VL; Char Szbuf [256]; VA_Start (VL, SZMSG); vsprintf (SZBUF, SZMSG, VL ); VA_END (VL); :: MessageBox (Null, Szbuf, "WavePlayer", MB_ok | MB_ICONEXCLAMATION);} ------------------------- -------------------------------------------------- ------ * / showmsg ("Failed to Open File:% S", SZFileName); Return;} // Enter block, check if the file is Wave file mmckinfoparent.fcctype = mmiofourcc ('w', 'a ',' V ',' e '); IF (MmioDescend (m_hmmckinfo) & mmckinfoparent, null, mmio_findriff) {Showmsg ("% s is an invalid wave!", Szfilename); mmioclose (m_hmmio, null Return;}
// Find 'fmt' block mmckinfoSubChunk.ckid = mmioFOURCC ( 'f', 'm', 't', ''); if (mmioDescend (m_hmmio, & mmckinfoSubChunk, & mmckinfoParent, MMIO_FINDCHUNK)) {ShowMsg ( "Can not find fmt chunk IN% s! ", szfilename); mmioclose (m_hmmio, null); return;}
// get 'fmt' block size, application memory dwFmtSize = mmckinfoSubChunk.cksize; m_hFormat = LocalAlloc (LMEM_MOVEABLE, LOWORD (dwFmtSize)); if (m_hFormat!) {ShowMsg ( "Alloc memory failed!"); Return;}
LPFORMAT = (Waveformatex *) locallock (m_hformat); if (! lpformat) {showmsg ("Lock Memory Failed!"); onStop (); Return;}
IF ((unsigned long) mmioread (m_hmmio, (hpstr) lpformat, dwfmtsize) {showmsg ("Read format chunk of% s failed!", szfilename); onstop (); return;} // Leave FMT block mmioAscend (m_hmmio, & mmckinfoSubChunk, 0); // find 'data' block mmckinfoSubChunk.ckid = mmioFOURCC ( 'd', 'a', 't', 'a'); if (mmioDescend (m_hmmio, & mmckinfoSubChunk, & mmckinfoParent, MMIO_FINDCHUNK )) {ShowMsg ( "Can not find data chunk in:% s", szFileName); OnStop (); return;} // get 'data' block size m_dwDataSize = mmckinfoSubChunk.cksize; m_dwDataOffset = mmckinfoSubChunk.dwDataOffset; if (m_dwDataSize == 0L) {ShowMSG ("% s HAS NO DATA!", SZFileName); onStop (); Return;} // Distributes memory LPDATA = New char [m_dwdatasize]; if (! Lpdata) {Showmsg (" Alloc Memory for Wave Data Failed! "); OnStop (); Return;}
lSoundOffset = m_dwDataOffset; LONG lSize = mmioSeek (m_hmmio, lSoundOffset, SEEK_SET); if (lSize <0) {ShowMsg ( "Seek data chunk of% s failed!", szFileName); OnStop (); return;} lSoundLong = m_dwDataSize; m_wavelong = mmioread (m_hmmio, lpdata, lsoundlong); if (M_Wavelong <0) {Showmsg ("Read Data Chunk Of% S Failed!", SZFileName); onStop (); return;} // Check audio device, return audio output Device Performance IF (WaveoutGetDevCaps (Wave_Mapper, & Pwoc, Sizeof (WaveoutCaps)))! = 0) {Showmsg ("WaveoutGetDevcaps () Failed!"); OnStop (); return;} // Check if audio output devices can play specified Audio file / * -------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------ WaveOutopen function The settings of the last three parameters have a decisive role in the message processing method. It is necessary to pay special attention. We typically use the following processing methods: 1. Use the window as the recipient of the message, then the fourth parameter is set to the handle of the window, then this Sub-playback information will enter the message queue of the window. At this time, the fifth parameter is NULL, the sixth parameter is callback_window, indicating that the message is processed by the window. 2. Directly use the callback function to handle the message, the fourth parameter is set to the pointer of the callback function, and the message related to this play will be processed by the function. At this time, the five parameters are the parameters of the function. , The sixth parameter is calledback_function, indicating that the message is processed by the specified function. 3. Use the new thread to process the message, then the fourth parameter is set to the pointer of the thread function, and the message related to this play will be processed by the thread. At this time, the fifth parameter is the parameter of the function. , The sixth parameter is Callback_thread, indicating that the message is processed by the thread. 4. If you don't need to process messages, the three parameters of this are null, null, callback_null --------------------------- -------------------------------------------------- --------------- * / if (Waveoutopen (& Hwaveout, Wave_Mapper, Lpformat, (Ulong) M_HWND, NULL, CALLBACK_WINDOW)! = 0) {Showmsg ("Open the Wave Out Devices Failed ! "); Onstop (); return;}
// prepare data to be played pWaveOutHdr.lpData = (HPSTR) lpData; pWaveOutHdr.dwBufferLength = m_WaveLong; pWaveOutHdr.dwFlags = 0; pWaveOutHdr.dwLoops = 5;! If (waveOutPrepareHeader (hWaveOut, & pWaveOutHdr, sizeof (WAVEHDR)) = 0 ) {ShowMSG ("Failed to Prepare THE WAVE DATA Buffer!"); OnStop ();} // Write the data into the device and start playing if (Waveoutwrite (Hwaveout, & PWaveoutdr, Sizeof (WaveHDR))! = 0) {ShowMSG ("Failed to Write the Wave Data Buffer"; onStop ();}} 2.4.2 Stop Playback
Void cpplaywavedlg :: onStop () {if (m_hmmio! = null) {mmioclose (m_hmmio, null);} // Stop playback and reset manager WaveoutReset (hWaveout); // Close play device Waveoutclose (hWaveout); // Clean WaveoutPrepareHeader prepared WaveoutPrepareHeader. Waveoutunpreparehead (Hwaveout, & PWaveouthDr, Sizeof (WaveHDR));
/ / Release memory IF (m_hformat! = Null) {localunlock (m_hformat); m_hformat = null;} if (m_hformat! = Null) {localfree (m_hformat); m_hformat = null;} if (lpdata! = Null) {Delete [ ] LPDATA; LPDATA = NULL;}}
2.4.3 Handling the message section:
Add message mapping: ON_MESSAGE (mm_wom_done, onmwomdone)
Void CPlaywavedlg :: OnMmWomdone (Uint WPARAM, Long LPARAM) {// Showmsg ("Play Finished!"); onstop ();
2.4.4 related header files
/ * ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------- --------------------- Description: The declaration of the operational function introduced in this article is included in the MMSystem.h header file, so you must use a #include "MMSystem in the program. H "statement is added to the header file. At the same time, you should add a dynamic connection to the library WinMM.LIB. There are two specific implementations: 1. Select Settings from the developer studio's Project menu, then add WinMM.LIB2 in the Object / Library Modules control on the Link tab. Add #pragma Comment (Lib, "Winmm.Lib") as shown below -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------- --------------------------------------- * / # include "mmsystem.h" #pragma Comment (Lib, "Winmm.Lib") Class CPLAYWAVEDLG: Public CDialog {
/ / Omission and play-independent part // ................
protected:
Handle M_HData; HWaveout Hwaveout; WaveHDR PWAveoutHdr; Handle M_HFormat; HPSTR LPDATA; / / Audio Data HMMIO M_HMMIO; // Audio File Handle
CString M_StrPathname; cstring m_strfilename;
Void Showmsg (Char * Szmsg, ...);
AFX_MSG void onplay (); afx_msg void onstop (); AFX_MSG Void OnMmWomdone (uint wparam, long lparam); DECLARE_MESSAGE_MAP ()};
The above code is passed on Visual C 6.0 Windows 2000 Pro.
3. Apply the low audio function to perform detail control of each sound data block in the memory, such as the screening of sound acquisition by detecting the amplitude intensity of the sound, or performs the shear merge of the sound file, this is a sound file. Flexible operations provide a good way; because it can operate sound data blocks, it can also provide effective ways for real-time transmission of sound. Reference: 1. Method for playing sound in Li Canwei VC 2. Li Bo Xuan Visuanl C 6.0 Multimedia Development Guide. Beijing: Tsinghua University Press, February 2000.71-75