dsnd.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. //#pragma warning (disable:4201)
  2. #include <stdlib.h>
  3. #define WIN32_LEAN_AND_MEAN
  4. #include <windows.h>
  5. #include <mmsystem.h>
  6. #include <dsound.h>
  7. #include "dsnd.h"
  8. #include "../common/lprintf.h"
  9. #define NSEGS 4
  10. #define RELEASE(x) if (x) x->Release(); x=NULL;
  11. static LPDIRECTSOUND DSound;
  12. static LPDIRECTSOUNDBUFFER LoopBuffer;
  13. static LPDIRECTSOUNDNOTIFY DSoundNotify;
  14. static HANDLE seg_played_event;
  15. static int LoopLen, LoopWrite, LoopSeg; // bytes
  16. static int LoopBlank(void)
  17. {
  18. void *mema=NULL,*memb=NULL;
  19. DWORD sizea=0,sizeb=0;
  20. LoopBuffer->Lock(0, LoopLen, &mema,&sizea, &memb,&sizeb, 0);
  21. if (mema) memset(mema,0,sizea);
  22. LoopBuffer->Unlock(mema,sizea, memb,sizeb);
  23. return 0;
  24. }
  25. int DSoundInit(HWND wnd_coop, int rate, int stereo, int seg_samples)
  26. {
  27. DSBUFFERDESC dsbd;
  28. WAVEFORMATEX wfx;
  29. DSBPOSITIONNOTIFY notifies[NSEGS];
  30. int i;
  31. memset(&dsbd,0,sizeof(dsbd));
  32. memset(&wfx,0,sizeof(wfx));
  33. // Make wave format:
  34. wfx.wFormatTag=WAVE_FORMAT_PCM;
  35. wfx.nChannels=stereo ? 2 : 1;
  36. wfx.nSamplesPerSec=rate;
  37. wfx.wBitsPerSample=16;
  38. wfx.nBlockAlign=(WORD)((wfx.nChannels*wfx.wBitsPerSample)>>3);
  39. wfx.nAvgBytesPerSec=wfx.nBlockAlign*wfx.nSamplesPerSec;
  40. // Create the DirectSound interface:
  41. DirectSoundCreate(NULL,&DSound,NULL);
  42. if (DSound==NULL) return 1;
  43. LoopSeg = seg_samples * 2;
  44. if (stereo)
  45. LoopSeg *= 2;
  46. LoopLen = LoopSeg * NSEGS;
  47. DSound->SetCooperativeLevel(wnd_coop, DSSCL_PRIORITY);
  48. dsbd.dwFlags=DSBCAPS_GLOBALFOCUS; // Play in background
  49. dsbd.dwFlags|=DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_CTRLPOSITIONNOTIFY;
  50. // Create the looping buffer:
  51. dsbd.dwSize=sizeof(dsbd);
  52. dsbd.dwBufferBytes=LoopLen;
  53. dsbd.lpwfxFormat=&wfx;
  54. DSound->CreateSoundBuffer(&dsbd,&LoopBuffer,NULL);
  55. if (LoopBuffer==NULL) return 1;
  56. LoopBuffer->QueryInterface(IID_IDirectSoundNotify, (LPVOID*)&DSoundNotify);
  57. if (DSoundNotify == NULL) {
  58. lprintf("QueryInterface(IID_IDirectSoundNotify) failed\n");
  59. goto out;
  60. }
  61. seg_played_event = CreateEvent(NULL, 0, 0, NULL);
  62. if (seg_played_event == NULL)
  63. goto out;
  64. for (i = 0; i < NSEGS; i++) {
  65. notifies[i].dwOffset = i * LoopSeg;
  66. notifies[i].hEventNotify = seg_played_event;
  67. }
  68. i = DSoundNotify->SetNotificationPositions(NSEGS, notifies);
  69. if (i != DS_OK) {
  70. lprintf("SetNotificationPositions failed\n");
  71. goto out;
  72. }
  73. out:
  74. LoopBlank();
  75. LoopBuffer->Play(0, 0, DSBPLAY_LOOPING);
  76. return 0;
  77. }
  78. void DSoundExit(void)
  79. {
  80. if (LoopBuffer)
  81. LoopBuffer->Stop();
  82. RELEASE(DSoundNotify);
  83. RELEASE(LoopBuffer)
  84. RELEASE(DSound)
  85. CloseHandle(seg_played_event);
  86. seg_played_event = NULL;
  87. }
  88. static int WriteSeg(const void *buff)
  89. {
  90. void *mema=NULL,*memb=NULL;
  91. DWORD sizea=0,sizeb=0;
  92. int ret;
  93. // Lock the segment at 'LoopWrite' and copy the next segment in
  94. ret = LoopBuffer->Lock(LoopWrite, LoopSeg, &mema, &sizea, &memb, &sizeb, 0);
  95. if (ret != DS_OK)
  96. lprintf("LoopBuffer->Lock() failed: %i\n", ret);
  97. if (mema) memcpy(mema,buff,sizea);
  98. // if (memb) memcpy(memb,DSoundNext+sizea,sizeb);
  99. if (sizeb != 0) lprintf("sizeb is not 0! (%i)\n", sizeb);
  100. ret = LoopBuffer->Unlock(mema,sizea, memb, sizeb);
  101. if (ret != DS_OK)
  102. lprintf("LoopBuffer->Unlock() failed: %i\n", ret);
  103. return 0;
  104. }
  105. int DSoundUpdate(const void *buff, int blocking)
  106. {
  107. DWORD play = 0;
  108. int pos;
  109. LoopBuffer->GetCurrentPosition(&play, NULL);
  110. pos = play;
  111. // 'LoopWrite' is the next seg in the loop that we want to write
  112. // First check that the sound 'play' pointer has moved out of it:
  113. if (blocking) {
  114. while (LoopWrite <= pos && pos < LoopWrite + LoopSeg) {
  115. WaitForSingleObject(seg_played_event, 5000);
  116. LoopBuffer->GetCurrentPosition(&play, NULL);
  117. pos = play;
  118. }
  119. }
  120. else {
  121. if (LoopWrite <= pos && pos < LoopWrite + LoopSeg)
  122. return 1;
  123. }
  124. WriteSeg(buff);
  125. // Advance LoopWrite to next seg:
  126. LoopWrite += LoopSeg;
  127. if (LoopWrite + LoopSeg > LoopLen)
  128. LoopWrite = 0;
  129. return 0;
  130. }