dsounddevice.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. // dsounddevice.cpp
  2. // changed to 4 x buffer spacing
  3. #include "freeaudio.h"
  4. #define WIN32_LEAN_AND_MEAN
  5. #include <windows.h>
  6. #include <objbase.h>
  7. #include <mmsystem.h>
  8. #include <stdio.h>
  9. #include "dsound.h"
  10. #define DSOUNDFRAG 2048
  11. extern "C" audiodevice *OpenDirectSoundDevice();
  12. struct dsounddevice:audiodevice{
  13. int running,playing; //threadsafe state machine
  14. int reset(){
  15. int res;
  16. running=1;
  17. playing=0;
  18. mix=new mixer(DSOUNDFRAG*6);
  19. mix->freq=44100;
  20. mix->channels=2;
  21. res=initdevice(DSOUNDFRAG);
  22. if (res) {
  23. running=0;
  24. }
  25. return res;
  26. }
  27. int close(){
  28. int timeout;
  29. if (running){
  30. //stop
  31. running=0;
  32. timeout=20; //100ms timeout
  33. while (timeout-- && playing) {
  34. Sleep(5);
  35. }
  36. freedevice();
  37. }
  38. return 0;
  39. }
  40. // private
  41. HINSTANCE dsoundlib;
  42. HRESULT WINAPI (*DirectSoundCreate)(LPGUID,LPDIRECTSOUND*,LPUNKNOWN);
  43. IDirectSound *directsound;
  44. IDirectSoundBuffer *primarybuffer;
  45. IDirectSoundBuffer *soundbuffer;
  46. IDirectSoundNotify *soundnotify;
  47. HANDLE soundevent;
  48. HANDLE soundthread;
  49. DWORD soundthreadid;
  50. int fragsize; //in bytes
  51. int buffersize; //4*fragsize
  52. int initdevice(int fragsamples){
  53. PCMWAVEFORMAT pcmwf;
  54. DSBUFFERDESC dsbdesc;
  55. DSCAPS dscaps;
  56. int res;
  57. // init device
  58. directsound=0;
  59. primarybuffer=0;
  60. soundbuffer=0;
  61. soundnotify=0;
  62. dsoundlib=LoadLibraryA("dsound");
  63. DirectSoundCreate=(HRESULT WINAPI (*)(LPGUID,LPDIRECTSOUND*,LPUNKNOWN))GetProcAddress(dsoundlib,"DirectSoundCreate");
  64. res=DirectSoundCreate(0,&directsound,0);
  65. if (res) return res;
  66. res=directsound->SetCooperativeLevel(GetDesktopWindow(),DSSCL_PRIORITY);
  67. if (res) return res;
  68. // printf("dsoundlib=%d soundcreate=%d res=%d\n",dsoundlib,(int)DirectSoundCreate,res);
  69. // fflush(stdout);
  70. dscaps.dwSize=sizeof(DSCAPS);
  71. res=directsound->GetCaps(&dscaps);
  72. if (res) return res;
  73. // set primary buffer format
  74. memset(&dsbdesc,0,sizeof(DSBUFFERDESC)); // Zero it out.
  75. dsbdesc.dwSize=sizeof(DSBUFFERDESC);
  76. dsbdesc.dwFlags=DSBCAPS_PRIMARYBUFFER;
  77. res=directsound->CreateSoundBuffer(&dsbdesc,&primarybuffer,0);
  78. if (res) return res;
  79. memset(&pcmwf, 0, sizeof(PCMWAVEFORMAT));
  80. pcmwf.wf.wFormatTag=WAVE_FORMAT_PCM;
  81. pcmwf.wf.nChannels=2;
  82. pcmwf.wf.nSamplesPerSec=44100;
  83. pcmwf.wBitsPerSample=16;
  84. pcmwf.wf.nBlockAlign=4;
  85. pcmwf.wf.nAvgBytesPerSec=pcmwf.wf.nSamplesPerSec * pcmwf.wf.nBlockAlign;
  86. res=primarybuffer->SetFormat((LPWAVEFORMATEX)&pcmwf);
  87. if (res) return res;
  88. // fragment size
  89. fragsize=fragsamples*4; //stereo 16bit=4 bytes per sample
  90. buffersize=fragsize*4; //quad buffered
  91. // format
  92. memset(&pcmwf, 0, sizeof(PCMWAVEFORMAT));
  93. pcmwf.wf.wFormatTag=WAVE_FORMAT_PCM;
  94. pcmwf.wf.nChannels=2;
  95. pcmwf.wf.nSamplesPerSec=44100;
  96. pcmwf.wf.nBlockAlign=4;
  97. pcmwf.wf.nAvgBytesPerSec=pcmwf.wf.nSamplesPerSec * pcmwf.wf.nBlockAlign;
  98. pcmwf.wBitsPerSample=16;
  99. // description
  100. memset(&dsbdesc,0,sizeof(DSBUFFERDESC)); // Zero it out.
  101. dsbdesc.dwSize=sizeof(DSBUFFERDESC);
  102. dsbdesc.dwBufferBytes=buffersize; //1 * pcmwf.wf.nAvgBytesPerSec;
  103. dsbdesc.lpwfxFormat=(LPWAVEFORMATEX)&pcmwf;
  104. dsbdesc.dwFlags=DSBCAPS_CTRLPOSITIONNOTIFY|DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_GLOBALFOCUS;
  105. // createbuffer
  106. res=directsound->CreateSoundBuffer(&dsbdesc,&soundbuffer,0);
  107. if (res) return res;
  108. // notifications
  109. soundevent=CreateEvent(0,0,0,"SOUNDEVENT");
  110. if (soundevent==0) return res;
  111. res=soundbuffer->QueryInterface(IID_IDirectSoundNotify,(void**)&soundnotify);
  112. if (res) return res;
  113. DSBPOSITIONNOTIFY notif[4];
  114. int n;
  115. for (n=0;n<4;n++){
  116. notif[n].dwOffset=n*fragsize;
  117. notif[n].hEventNotify=soundevent;
  118. }
  119. res=soundnotify->SetNotificationPositions(4,notif);
  120. if (res) return res;
  121. // thread
  122. soundthread=CreateThread(NULL,0,soundproc,this,REALTIME_PRIORITY_CLASS,&soundthreadid);
  123. return 0;
  124. }
  125. void freedevice(){
  126. int res;
  127. if (primarybuffer){
  128. res=primarybuffer->Release();
  129. primarybuffer=0;
  130. }
  131. if (soundbuffer){
  132. res=soundbuffer->Release();
  133. soundbuffer=0;
  134. }
  135. if(directsound) {
  136. res=directsound->Release();
  137. directsound=0;
  138. }
  139. }
  140. //thread entry point
  141. DWORD run(){
  142. DWORD read,write;
  143. int lastread,loopcount;
  144. void *mem1,*mem2;
  145. DWORD size1,size2;
  146. int readpos,writepos;
  147. int res;
  148. writepos=0;
  149. lastread=0;
  150. loopcount=0;
  151. res=soundbuffer->Lock(0,4*fragsize,&mem1,&size1,&mem2,&size2,0);
  152. if (res) return 0;
  153. // printf("mem1=%d size1=%d mem2=%d size2=%d total=%d\n",mem1,size1,mem2,size2,size1+size2);
  154. // fflush(stdout);
  155. if (size1) memset(mem1,0,size1);
  156. if (size2) memset(mem2,0,size2);
  157. res=soundbuffer->Unlock(mem1,size1,mem2,size2);
  158. if (res) return 0;
  159. // playsound
  160. soundbuffer->Play(0,0,DSBPLAY_LOOPING);
  161. playing=1;
  162. // printf("running=%d\n",running);
  163. // fflush(stdout);
  164. while (running){
  165. res=soundbuffer->GetCurrentPosition(&read,&write);
  166. if (read<lastread) loopcount++;
  167. lastread=read;
  168. readpos=loopcount*buffersize+read;
  169. int count=((readpos+fragsize*2-writepos)/fragsize);
  170. // printf("read=%d write=%d %d,%d count=%d\n",read,write,readpos,writepos,count);
  171. // fflush(stdout);
  172. if (count>0){
  173. if (count>2) count=2; //avoid overrun
  174. res=soundbuffer->Lock(writepos%buffersize,count*fragsize,&mem1,&size1,&mem2,&size2,0);
  175. if (res) break;
  176. // printf("mem1=%d size1=%d mem2=%d size2=%d total=%d\n",mem1,size1,mem2,size2,size1+size2);
  177. // fflush(stdout);
  178. if (size1) mix->mix16((short*)mem1,size1/2);
  179. if (size2) mix->mix16((short*)mem2,size2/2);
  180. res=soundbuffer->Unlock(mem1,size1,mem2,size2);
  181. if (res) break;
  182. writepos+=size1+size2;
  183. }
  184. res=WaitForSingleObject(soundevent,1000);
  185. if (res!=WAIT_OBJECT_0) break;
  186. }
  187. playing=0;
  188. soundbuffer->Stop();
  189. // printf("done...\n");
  190. // fflush(stdout);
  191. }
  192. static DWORD WINAPI soundproc(LPVOID lpParam){
  193. dsounddevice *dsd;
  194. dsd=(dsounddevice*)lpParam;
  195. return dsd->run();
  196. }
  197. };
  198. audiodevice *OpenDirectSoundDevice(){
  199. return new dsounddevice();
  200. }