音樂可以使用戶心情愉快,在合適的場合播放恰當的音樂能夠使程序員和他的VC
++程序煥發出光彩。
API 提供了三種方法來播放WAV 文件:
?。狿laySound()函數。它可以通過單行編碼來播放Wave
格式的聲音。此函數有兩個限制:必須將聲音數據完整地載入物理內存;數據格式必須被所配置的某一音頻驅動器支持。根據經驗,PlaySound()適用于100K
以下的文件。
?。狹CI(The Media Control Interface)。MCI 功能強大,不僅可以實現WAV
文件的播放,而且還可以播放MIDI 及CD 音頻。
?。图塛ave 音頻設備。用這些設備可以運行完全控制Wave
數據的應用文件。
前兩種方法使用簡單,但無法實現兩個及兩個以上的WAV
文件的播放;第三種方法實現起來非常復雜,非專業人員很難完成。DirectSound
可以實現八個及八個以上WAV
文件的同時播放,能使多媒體程序更加生動,而且簡單易用,但它僅適合于Windows
95 下的程序,也不支持WAV 文件的記錄及存儲--
這是唯一讓人遺憾的地方。
實現DirectSound 需要以下幾個步驟:
1. 創建及初始化DirectSound:
LPDIRECTSOUND m_pDirectObject;
if(DirectSoundCreate(NULL,
&m_pDirectObject,NULL)==DS_OK)
// 設定應用程序的聲音 設備優先
級別方式,一般為DSSCL_NORMAL
m_pDirectObject ->SetCooperativeLevel(this
?。?gt;m_hWnd,DSSCL_NORMAL);
else
AfxMessageBox("DirectSound Create failed");
2. 將WAV 文件讀入內存,找到格式塊、數據塊位置及數據長度:
m_pMemory,m_pFormat,m_pData,
m_dwSize 在頭文件中聲明。
BOOL CDirectWave::LoadFile (CString Filename){
CFile File;
DWORD dwSize;
if (!File.Open (Filename, CFile::modeRead
| CFile::shareDenyNone))
return FALSE;
dwSize = File.Seek (0, CFile::end);
File.Seek (0, CFile::begin);
//m_pMemory 內存存儲塊指針, 類型:LPVOID
m_pMemory = GlobalAlloc (GMEM_FIXED, dwSize);
if (File.ReadHuge (m_pMemory, dwSize) != dwSize){
File.Close ();
return FALSE;
}
File.Close ();
LPDWORD pdw,pdwEnd;
DWORD dwRiff,dwType, dwLength, dwLength;
if (m_pFormat) // 格式塊指針,
類型:LPWAVEFORMATEX
m_pFormat = NULL;
if (m_pData) // 數據塊指針,類型:LPBYTE
m_pData = NULL;
if (m_dwSize) // 數據長度,類型:DWORD
m_dwSize = 0;
pdw = (DWORD *) m_pMemory;
dwRiff = *pdw ++;
dwLength = *pdw ++;
dwType = *pdw ++;
if (dwRiff != mmioFOURCC ('R', 'I', 'F', 'F'))
return FALSE;
if (dwType != mmioFOURCC ('W', 'A', 'V', 'E'))
return FALSE;
// 尋找格式塊,數據塊位置及數據長度
pdwEnd = (DWORD *)((BYTE *)
pdw +dwLength -4);
while (pdw < pdwEnd){
dwType = *pdw ++;
dwLength = *pdw ++;
switch (dwType){
case mmioFOURCC('f', 'm', 't', ' '):
if (!m_pFormat){
if (dwLength < sizeof (WAVEFORMAT))
return FALSE;
m_pFormat = (LPWAVEFORMATEX) pdw;
if (m_pData &&m_dwSize)
return TRUE;
}
break;
case mmioFOURCC('d', 'a', 't', 'a'):
if (!m_pData || !m_dwSize){
m_pData = (LPBYTE) pdw;
m_dwSize = dwLength;
if (m_pFormat)
return TRUE;
}
break;
}
pdw = (DWORD *)((BYTE *) pdw
+((dwLength +1) &~1));
}
// 未找到,返回FALSE
return FALSE;
}
3. 創建聲音緩沖區:
DSBUFFERDESC BufferDesc;
memset ( &BufferDesc, 0, sizeof (BufferDesc));
BufferDesc.lpwfxFormat =
(LPWAVEFORMATEX) m_pFormat;
BufferDesc.dwSize = sizeof (DSBUFFERDESC);
BufferDesc.dwBufferBytes = m_dwSize;
BufferDesc.dwFlags = 0;
// 頭文件中聲明m_pDSoundBuffer,
類型:LPDIRECTSOUNDBUFFER
if (pDSoundObject ->CreateSoundBuffer
( &BufferDesc, &m_pDSoundBuffer, 0) != DS_OK)
return FALSE;
4. 載入聲音數據:
BOOL CDirectWave::LoadData (void){
LPVOID lpPtr1, lpPtr2;
DWORD dwLen1, dwLen2;
HRESULT hResult;
TryLoad:
hResult = m_pDSoundBuffer ->Lock
(0, m_dwSize, &lpPtr1, &dwLen1,
&lpPtr2, &dwLen2, 0);
if (hResult == DS_OK){
memcpy (lpPtr1, m_pData, dwLen1);
if (lpPtr2)
memcpy (lpPtr2, m_pData +dwLen1, dwLen2);
m_pDSoundBuffer ->Unlock
(lpPtr1, dwLen1, lpPtr2, dwLen2);
return TRUE;
}
else if (hResult == DSERR_BUFFERLOST){
hResult = m_pDSoundBuffer ->Restore ();
if (hResult == DS_OK)
goto TryLoad;
}
return FALSE;
}
5. 播放及停止:
void CDirectWave::Play (BOOL bLoop){
DWORD dwFlags = 0;//dwFlags=
DSBPLAY_LOOPING 可實現循環播放
TryPlay:
if (m_pDSoundBuffer ->Play
(0, 0, dwFlags) == DSERR_BUFFERLOST){
if (LoadData ())// 數據丟失,重新裝載
goto TryPlay;
}
}
void CDirectWave::Stop (void){
m_pDSoundBuffer ->Stop ();
}
6. 關閉、釋放內存塊、聲音緩沖區?!?/p>