DirectSound.cpp
上传用户:hygd004
上传日期:2022-02-04
资源大小:1841k
文件大小:15k
源码类别:

DirextX编程

开发平台:

Visual C++

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Copyright (C) 1998 by J鰎g K鰊ig
  3. // All rights reserved
  4. //
  5. // This file is part of the completely free tetris clone "CGTetris".
  6. //
  7. // This is free software.
  8. // You may redistribute it by any means providing it is not sold for profit
  9. // without the authors written consent.
  10. //
  11. // No warrantee of any kind, expressed or implied, is included with this
  12. // software; use at your own risk, responsibility for damages (if any) to
  13. // anyone resulting from the use of this software rests entirely with the
  14. // user.
  15. //
  16. // Send bug reports, bug fixes, enhancements, requests, flames, etc., and
  17. // I'll try to keep a version up to date.  I can be reached as follows:
  18. //    J.Koenig@adg.de                 (company site)
  19. //    Joerg.Koenig@rhein-neckar.de    (private site)
  20. /////////////////////////////////////////////////////////////////////////////
  21. // DirectSound.cpp: implementation of the CDirectSound class.
  22. //
  23. //////////////////////////////////////////////////////////////////////
  24. #include "stdafx.h"
  25. #include "DirectSound.h"
  26. #include "INITGUID.h"
  27. #include "TKCore.h"
  28. #include "process.h"
  29. // The following macro is defined since DirectX 5, but will work with
  30. // older versions too.
  31. #ifndef DSBLOCK_ENTIREBUFFER
  32. #define DSBLOCK_ENTIREBUFFER        0x00000002
  33. #endif
  34. #ifdef _DEBUG
  35. #undef THIS_FILE
  36. static char THIS_FILE[]=__FILE__;
  37. #define new DEBUG_NEW
  38. #endif
  39. static void DSError( HRESULT hRes ) {
  40. switch(hRes) {
  41. case DS_OK: TKL_Trace("NO ERRORn"); break;
  42. case DSERR_ALLOCATED: TKL_Trace("ALLOCATEDn"); break;
  43. case DSERR_INVALIDPARAM: TKL_Trace("INVALIDPARAMn"); break;
  44. case DSERR_OUTOFMEMORY: TKL_Trace("OUTOFMEMORYn"); break;
  45. case DSERR_UNSUPPORTED: TKL_Trace("UNSUPPORTEDn"); break;
  46. case DSERR_NOAGGREGATION: TKL_Trace("NOAGGREGATIONn"); break;
  47. case DSERR_UNINITIALIZED: TKL_Trace("UNINITIALIZEDn"); break;
  48. case DSERR_BADFORMAT: TKL_Trace("BADFORMATn"); break;
  49. case DSERR_ALREADYINITIALIZED: TKL_Trace("ALREADYINITIALIZEDn"); break;
  50. case DSERR_BUFFERLOST: TKL_Trace("BUFFERLOSTn"); break;
  51. case DSERR_CONTROLUNAVAIL: TKL_Trace("CONTROLUNAVAILn"); break;
  52. case DSERR_GENERIC: TKL_Trace("GENERICn"); break;
  53. case DSERR_INVALIDCALL: TKL_Trace("INVALIDCALLn"); break;
  54. case DSERR_OTHERAPPHASPRIO: TKL_Trace("OTHERAPPHASPRIOn"); break;
  55. case DSERR_PRIOLEVELNEEDED: TKL_Trace("PRIOLEVELNEEDEDn"); break;
  56. default: TKL_Trace("%lun",hRes);break;
  57. }
  58. }
  59. //////////////////////////////////////////////////////////////////////
  60. // Construction/Destruction
  61. //////////////////////////////////////////////////////////////////////
  62. LPDIRECTSOUND CDirectSound::m_lpDirectSound;
  63. LPDIRECTSOUNDBUFFER  CDirectSound::m_pDsb;
  64. LPDIRECTSOUNDNOTIFY  CDirectSound::m_pDsNotify; 
  65. DWORD CDirectSound::m_dwInstances;
  66. CDirectSound::CDirectSound()
  67. {
  68. ::ZeroMemory(&m_config,sizeof(AUDIO_CONFIG));
  69. m_pDsNotify = 0;
  70. m_bFir = 1; 
  71. m_lpDirectSound = 0;
  72. m_pDsb = 0;
  73. m_pTheSound = 0;
  74. m_dwTheSound = 0;
  75. m_bEnabled = TRUE;
  76. m_bPlay = 0;
  77. ++m_dwInstances;
  78. m_hPlayThread = 0;
  79. m_dwBufNum = 4;
  80. m_dwBufLen = 8192;
  81. m_dwOffset = 0;
  82. m_dwBufSize = 0;
  83. m_bStop = 0;
  84. m_pTheSound = (BYTE*)malloc(BUFSIZE);
  85. // m_pTheSound = new BYTE[BUFSIZE];
  86. m_sysncObj = CreateMutex(0,0,0);
  87. }
  88. CDirectSound::~CDirectSound()
  89. {
  90. if(m_hPlayThread)
  91. {
  92. WaitForSingleObject(m_hPlayThread,2000);
  93. CloseHandle(m_hPlayThread);
  94. m_hPlayThread = NULL;
  95. }
  96. free(m_pTheSound);
  97. if(m_pDsNotify)
  98. {
  99. m_pDsNotify->Release();
  100. m_pDsNotify = NULL;
  101. }
  102. if(m_pDsb)
  103. {
  104. m_pDsb->Release();
  105. m_pDsb = NULL;
  106. }
  107. if( !--m_dwInstances && m_lpDirectSound ) {
  108. m_lpDirectSound->Release();
  109. m_lpDirectSound = 0;
  110. }
  111. if(m_sysncObj)
  112. {
  113. CloseHandle(m_sysncObj);
  114. m_sysncObj = NULL;
  115. }
  116. // free(m_pTheSound);
  117. // ::delete[] m_pTheSound;
  118. }
  119. unsigned int WINAPI PlaySoundProc(LPVOID pOwner)
  120. {
  121. CDirectSound* pThis = (CDirectSound*) pOwner;
  122. pThis->WriteToBuf();
  123. return 1;
  124. }
  125. int CDirectSound::WriteDataToBuf(BYTE* pBuf,DWORD dwLen)
  126. {
  127. if(m_dwBufSize + dwLen > BUFSIZE)
  128. return -1;
  129. // GENRS_AutoLock lock(m_sysncObj);
  130. WaitForSingleObject(m_sysncObj,2000);
  131. {
  132. memcpy(m_pTheSound+m_dwBufSize,pBuf,dwLen); 
  133. m_dwBufSize += dwLen;
  134. ReleaseMutex(m_sysncObj);
  135. }
  136. return 1;
  137. }
  138. BOOL CDirectSound::SetPlaySpeed(float fSpeed)
  139. {
  140. // AUDIO_CONFIG lc_config;
  141. m_fRate = fSpeed;
  142. m_config.nSamplesPerSec = m_nSamplesPerSec*fSpeed;
  143. m_config.nAvgBytesPerSec = m_nAvgBytesPerSec*fSpeed;
  144. Stop();
  145. if(!CreateDSound(&m_config,m_dwBufLen))
  146. return FALSE;
  147. Play();
  148. return TRUE;
  149. }
  150. /*
  151. void CDirectSound::SetHWnd(HWND hWnd)
  152. {
  153. m_hWnd = hWnd;
  154. }*/
  155. BOOL CDirectSound :: CreateDSound(AUDIO_CONFIG* WaveHead,DWORD dwHeadLen)
  156. {
  157. if(m_config.nSamplesPerSec == NULL)
  158. {
  159. m_fRate = 1.0;
  160. m_config = *WaveHead;
  161. m_nAvgBytesPerSec = m_config.nAvgBytesPerSec;
  162. m_nSamplesPerSec  = m_config.nSamplesPerSec;
  163. }
  164. m_dwBufLen = dwHeadLen ;
  165. if(m_lpDirectSound)
  166. {
  167. return TRUE;
  168. }
  169. HRESULT hRes = DS_OK;
  170. short nRes = 0;
  171. do {
  172. if( nRes )
  173. ::Sleep(500);
  174. hRes = ::DirectSoundCreate(0, &m_lpDirectSound, 0);
  175. ++nRes;
  176. while( nRes < 10 && (hRes == DSERR_ALLOCATED || hRes == DSERR_NODRIVER) );
  177. if( hRes != DS_OK )
  178. return FALSE;
  179. m_lpDirectSound->SetCooperativeLevel(/*m_hWnd*/::GetDesktopWindow(), DSSCL_NORMAL);
  180. // WAVEFORMATEX * pcmwf;
  181. // DWORD dwHeadLen = 1000;
  182. // if(!GetWaveData(pHeader, pcmwf, m_dwTheSound) )
  183. // return FALSE;
  184. m_rate = WaveHead->nAvgBytesPerSec;
  185. if(!CreateSoundBuffer((WAVEFORMATEX*)(&m_config)))
  186. return FALSE;
  187. // SetSoundData(0,m_pTheSound, m_dwTheSound);
  188. // m_bPlay = TRUE;
  189. // dwHeadLen = m_dwTheSound;
  190. m_bStop = 0;
  191. m_dwBufSize = 0;
  192. unsigned int dwID;
  193. // m_hPlayThread = CreateThread(0,0,PlaySoundProc,this,0,&dwID);
  194. m_hPlayThread = (HANDLE)_beginthreadex(0,0,PlaySoundProc,this,0,&dwID);
  195. return TRUE;
  196. }
  197. BOOL CDirectSound :: GetWaveData(void * pRes, WAVEFORMATEX * & pWaveHeader, 
  198.  void * & pbWaveData, DWORD & cbWaveSize
  199.  )
  200. {
  201. pWaveHeader = 0;
  202. pbWaveData = 0;
  203. cbWaveSize = 0;
  204. DWORD * pdw = (DWORD *)pRes;
  205. DWORD dwRiff = *pdw++;
  206. DWORD dwLength = *pdw++;
  207. DWORD dwType = *pdw++;
  208. if( dwRiff != mmioFOURCC('R', 'I', 'F', 'F') )
  209. return FALSE;      // not even RIFF
  210. if( dwType != mmioFOURCC('W', 'A', 'V', 'E') )
  211. return FALSE;      // not a WAV
  212. DWORD * pdwEnd = (DWORD *)((BYTE *)pdw + 1000-4);
  213. while( pdw < pdwEnd ) {
  214. dwType = *pdw++;
  215. dwLength = *pdw++;
  216. switch( dwType ) {
  217. case mmioFOURCC('f', 'm', 't', ' '):
  218. if( !pWaveHeader ) {
  219. if( dwLength < sizeof(WAVEFORMAT) )
  220. return FALSE;      // not a WAV
  221. pWaveHeader = (WAVEFORMATEX *)pdw;
  222. if( pbWaveData && cbWaveSize )
  223. return TRUE;
  224. }
  225. break;
  226. case mmioFOURCC('d', 'a', 't', 'a'):
  227. pbWaveData = LPVOID(pdw);
  228. cbWaveSize = dwLength;
  229. if( pWaveHeader )
  230. return TRUE;
  231. break;
  232. }
  233. pdw = (DWORD *)((BYTE *)pdw + ((dwLength+1)&~1));
  234. }
  235. return FALSE;
  236. }
  237. BOOL CDirectSound :: GetWaveData(void * pHeader, WAVEFORMATEX * & pWaveHeader,
  238.   DWORD & dwHeadSize)
  239. {
  240. dwHeadSize  = 0;
  241. pWaveHeader = 0;
  242. DWORD * pdw = (DWORD *)pHeader;
  243. DWORD dwRiff = *pdw++;
  244. DWORD dwLength = *pdw++;
  245. DWORD dwType = *pdw++;
  246. m_dwTotalSize = dwLength;
  247. if( dwRiff != mmioFOURCC('R', 'I', 'F', 'F') )
  248. return FALSE;      // not even RIFF
  249. if( dwType != mmioFOURCC('W', 'A', 'V', 'E') )
  250. return FALSE;      // not a WAV
  251. dwType = *pdw++;
  252. dwLength = *pdw++;
  253. if(dwType!= mmioFOURCC('f', 'm', 't', ' '))
  254. return FALSE;
  255. if( !pWaveHeader )
  256. {
  257. if( dwLength < sizeof(WAVEFORMAT) )
  258. return FALSE;      // not a WAV
  259. pWaveHeader = (WAVEFORMATEX *)pdw;
  260. }
  261. dwHeadSize += 5*sizeof(DWORD);
  262. return TRUE;
  263. }
  264. BOOL CDirectSound::WriteToBuf()
  265. {
  266. // m_bPlay = TRUE;
  267. if( !SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_ABOVE_NORMAL ))
  268. {
  269. return FALSE;
  270. };
  271. while (!m_bStop)
  272. {
  273. if(m_bFir)
  274. {
  275. //ParseBuffer();
  276. //GENRS_AutoLock lock(m_sysncObj);
  277. while (m_dwBufSize < 3*m_dwBufLen)
  278. {
  279. if(m_bStop)
  280. break;
  281. Sleep(10);
  282. }
  283. WaitForSingleObject(m_sysncObj,20000);
  284. {
  285. SetSoundData( m_pTheSound, 3*m_dwBufLen);
  286. if(m_dwBufSize > 3*m_dwBufLen)
  287. memcpy(m_pTheSound,m_pTheSound+3*m_dwBufLen,m_dwBufSize - 3*m_dwBufLen);
  288. m_dwBufSize -= 3*m_dwBufLen;
  289. ReleaseMutex(m_sysncObj);
  290. }
  291. // m_pDsb->Play(0,0,1);
  292. m_bFir = 0;
  293. }
  294. else
  295. {
  296. int id = WaitForMultipleObjects(m_dwBufNum,notify_events,0,INFINITE);
  297. //ParseBuffer();
  298. //GENRS_AutoLock lock(m_sysncObj);
  299. while (m_dwBufSize < m_dwBufLen)
  300. {
  301. if(m_bStop)
  302. break;
  303. Sleep(10);
  304. }
  305. WaitForSingleObject(m_sysncObj,2000);
  306. {
  307. TKL_Trace("ID = %d",id);
  308. if(id == 0)
  309. m_dwOffset = 3*m_dwBufLen;
  310. else
  311. m_dwOffset = (id-1)*m_dwBufLen;
  312. SetSoundData( m_dwOffset,m_pTheSound, m_dwBufLen);
  313. if(m_dwBufSize > m_dwBufLen)
  314. memcpy(m_pTheSound,m_pTheSound+m_dwBufLen,m_dwBufSize - m_dwBufLen);
  315. m_dwBufSize -= m_dwBufLen;
  316. ReleaseMutex(m_sysncObj);
  317. }
  318. }
  319. }
  320. return TRUE;
  321. // SetSoundData(m_pSoundBuf,dwSoundSize);
  322. }
  323. BOOL CDirectSound::CreateSoundBuffer(WAVEFORMATEX * pcmwf)
  324. {
  325. DSBUFFERDESC dsbdesc;
  326. // Set up DSBUFFERDESC structure.
  327. memset(&dsbdesc, 0, sizeof(DSBUFFERDESC)); // Zero it out.
  328. dsbdesc.dwSize = sizeof(DSBUFFERDESC);
  329. // Need no controls (pan, volume, frequency).
  330. dsbdesc.dwFlags =  dsbdesc.dwFlags = 
  331.    DSBCAPS_GETCURRENTPOSITION2/* Better position accuracy */
  332.    | DSBCAPS_CTRLPOSITIONNOTIFY     /* We need notification */
  333.    | DSBCAPS_GLOBALFOCUS;      /* Allows background playing *///DSBCAPS_STATIC; // assumes that the sound is played often
  334. dsbdesc.dwBufferBytes =m_dwBufNum*m_dwBufLen;// m_dwTheSound;
  335. dsbdesc.lpwfxFormat = pcmwf;    // Create buffer.
  336. HRESULT hRes;
  337. if( DS_OK != (hRes = m_lpDirectSound->CreateSoundBuffer(&dsbdesc, &m_pDsb, 0)) ) {
  338. // Failed.
  339. DSError(hRes);
  340. m_pDsb = 0;
  341. return FALSE;
  342. }
  343. for (int i=0;i<m_dwBufNum;i++)
  344. {
  345. //create dsound buffer notify points
  346. //Auto reset event
  347. m_hEvent=CreateEvent( NULL, FALSE, FALSE, NULL );
  348. DSNotify[i].hEventNotify=m_hEvent; 
  349. DSNotify[i].dwOffset=i*(m_dwBufLen);//NOTIFYNUM);
  350. }
  351. hRes = m_pDsb->QueryInterface(IID_IDirectSoundNotify,(void **)&m_pDsNotify); 
  352.     if (FAILED(hRes)) //SUCCEEDED
  353. {
  354.           return FALSE;
  355. }
  356. //NOTIFYNUM notify point
  357. hRes=m_pDsNotify->SetNotificationPositions(m_dwBufNum,DSNotify); 
  358. if (FAILED(hRes)) //SUCCEEDED
  359. {
  360.      
  361.  return FALSE;
  362. }
  363. for (int n=0;n< m_dwBufNum;n++)
  364. {
  365. notify_events[n]=DSNotify[n].hEventNotify;
  366. ResetEvent(notify_events[n]); 
  367. }
  368. return TRUE;
  369. }
  370. BOOL CDirectSound::SetSoundData(void * pSoundData,DWORD SoundSize)
  371. {
  372. LPVOID lpvPtr1;
  373. DWORD dwBytes1;
  374. if (!pSoundData) return FALSE;
  375. // ASSERT(SoundSize<=DDSOUNDBUFLEN);
  376. // Obtain write pointer.
  377. HRESULT hr = m_pDsb->Lock(0, SoundSize, &lpvPtr1, &dwBytes1, 0, 0, DSBLOCK_ENTIREBUFFER);    
  378.     // If DSERR_BUFFERLOST is returned, restore and retry lock.
  379. if(DSERR_BUFFERLOST == hr) {
  380. m_pDsb->Restore();
  381. hr = m_pDsb->Lock(0, SoundSize, &lpvPtr1, &dwBytes1, 0, 0, DSBLOCK_ENTIREBUFFER);
  382. }
  383. if(DS_OK == hr) {
  384. // Write to pointers.
  385. ::CopyMemory(lpvPtr1, pSoundData, SoundSize);
  386. // Release the data back to DirectSound.
  387. hr = m_pDsb->Unlock(lpvPtr1, dwBytes1, 0, 0);
  388. if(DS_OK == hr)
  389.             return TRUE;
  390. }
  391. // Lock, Unlock, or Restore failed.
  392. return FALSE;
  393. }
  394. BOOL CDirectSound::SetSoundData(DWORD Offset,void * pSoundData, DWORD dwSoundSize)
  395. {
  396. LPVOID lpPart1;
  397.     LPVOID lpPart2;
  398.     DWORD  Part1Len,Part2Len;
  399. DWORD off_read,off_write;
  400.     //char buf[128];
  401.     m_pDsb->GetCurrentPosition(&off_read,&off_write);
  402. TKL_Trace("offset = %d,off_read=%d off_write=%dn",Offset,off_read,off_write);
  403. // Obtain write pointer.
  404. HRESULT hr = m_pDsb->Lock(Offset, dwSoundSize, &lpPart1, &Part1Len, &lpPart2, &Part2Len, 0);    
  405.     // If DSERR_BUFFERLOST is returned, restore and retry lock.
  406. if(DSERR_BUFFERLOST == hr) {
  407. m_pDsb->Restore();
  408. hr = m_pDsb->Lock(Offset, dwSoundSize, &lpPart1, &Part1Len, &lpPart2, &Part2Len, 0);
  409. }
  410. if(DS_OK == hr) {
  411. // Write to pointers.
  412. ::CopyMemory(lpPart1, pSoundData, Part1Len);
  413. if (lpPart2)
  414. {
  415. ::CopyMemory(lpPart2, (BYTE*)pSoundData+Part1Len, Part2Len);
  416. }
  417. // Release the data back to DirectSound.
  418. hr = m_pDsb->Unlock(lpPart1, Part1Len, lpPart2, Part2Len);
  419. }
  420. // Lock, Unlock, or Restore failed.
  421. return FALSE;
  422. }
  423. void CDirectSound::Play(INT nTime, BOOL bLoop)
  424. {
  425. if( ! IsValid() /*|| ! IsEnabled()*/ )
  426. return; // no chance to play the sound ...
  427. DWORD dwPlayCursor;
  428. DWORD dwWriteCursor;
  429. m_pDsb->GetCurrentPosition(&dwPlayCursor, &dwWriteCursor);
  430. int offByte = nTime*m_rate/1000;
  431. if(dwPlayCursor >0)
  432. {
  433. if( dwPlayCursor > m_dwBufLen* m_dwBufNum )
  434. dwPlayCursor = m_dwBufLen* m_dwBufNum;
  435. }
  436. if(dwPlayCursor > offByte)
  437. {
  438. if(dwPlayCursor  < -offByte)
  439. {
  440. dwPlayCursor = 0;
  441. }
  442. else
  443. {
  444. dwPlayCursor += offByte;
  445. }
  446. }
  447. else
  448. dwPlayCursor = m_dwBufLen* m_dwBufNum;
  449. m_pDsb->SetCurrentPosition(dwPlayCursor);
  450. if( DSERR_BUFFERLOST == m_pDsb->Play(0, 0, 1) ) 
  451. {
  452. // another application had stolen our buffer
  453. // Note that a "Restore()" is not enough, because
  454. // the sound data is invalid after Restore().
  455. SetSoundData(m_pTheSound, m_dwBufLen);
  456. // Try playing again
  457. m_pDsb->Play(0, 0, 1);
  458. }
  459. }
  460. void CDirectSound::Stop()
  461. {
  462. m_bStop = 1;
  463. if(m_hPlayThread)
  464. {
  465. WaitForSingleObject(m_hPlayThread,2000);
  466. CloseHandle(m_hPlayThread);
  467. m_hPlayThread = NULL;
  468. }
  469. if( IsValid() )
  470. m_pDsb->Stop();
  471. for (int i=0;i<m_dwBufNum;i++)
  472. {
  473. //create dsound buffer notify points
  474. //Auto reset event
  475. ResetEvent(notify_events[i]);
  476. CloseHandle(notify_events[i]);//=m_hEvent; 
  477. }
  478. if(m_pDsNotify)
  479. {
  480. m_pDsNotify->Release();
  481. m_pDsNotify = NULL;
  482. }
  483. if(m_pDsb)
  484. {
  485. m_pDsb->Release();
  486. m_pDsb = NULL;
  487. }
  488. if(m_lpDirectSound)
  489. {
  490. m_lpDirectSound->Release();
  491. m_lpDirectSound = NULL;
  492. }
  493. m_bFir = 1;
  494. m_dwBufSize = 0;
  495. }
  496. void CDirectSound::Pause()
  497. {
  498. if( IsValid() )
  499. m_pDsb->Stop();
  500. }
  501. void CDirectSound::Continue()
  502. {
  503. if( IsValid() ) {
  504. DWORD dwPlayCursor, dwWriteCursor;
  505. m_pDsb->GetCurrentPosition(&dwPlayCursor, &dwWriteCursor);
  506. Play(dwPlayCursor);
  507. }
  508. }
  509. BOOL CDirectSound::IsValid() const
  510. {
  511. return (m_lpDirectSound && m_pDsb ) ? TRUE : FALSE;
  512. }