mmdevice.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. // mmdevice.cpp
  2. // windows mediadevice version 2
  3. #include "freeaudio.h"
  4. #ifdef _WIN32
  5. #define WIN32_LEAN_AND_MEAN
  6. #include <windows.h>
  7. #include <mmsystem.h>
  8. #include <malloc.h>
  9. #include <stdio.h>
  10. extern "C" audiodevice *OpenMultiMediaDevice();
  11. static void __stdcall audioTimerProc( UINT id,UINT msg,DWORD user,DWORD u1,DWORD u2 );
  12. struct pcmsetting
  13. {
  14. WAVEFORMATEX wf;
  15. pcmsetting(int freq,int chan,int bits)
  16. {
  17. wf.wFormatTag=WAVE_FORMAT_PCM;
  18. wf.nChannels=chan;
  19. wf.nSamplesPerSec=freq;
  20. wf.nBlockAlign=chan*bits/8;
  21. wf.nAvgBytesPerSec=freq*wf.nBlockAlign;
  22. wf.wBitsPerSample=bits;
  23. wf.cbSize=0;
  24. }
  25. };
  26. struct abuffer {
  27. LPWAVEHDR hdr;
  28. u8 *data;
  29. int id;
  30. void init(HWAVEOUT device,int size,int n) {
  31. hdr=(LPWAVEHDR)malloc(sizeof(WAVEHDR));
  32. data=(u8*)calloc(size,1);
  33. id=n;
  34. hdr->lpData=(LPSTR)data;
  35. hdr->dwBufferLength=size;
  36. hdr->dwUser=(int)this;
  37. hdr->dwFlags=WHDR_BEGINLOOP|WHDR_ENDLOOP;
  38. hdr->dwLoops=0x7fffffff;
  39. waveOutPrepareHeader(device,hdr,sizeof(WAVEHDR));
  40. }
  41. void play(HWAVEOUT device) {
  42. if (waveOutWrite(device,hdr,sizeof(WAVEHDR))) {
  43. printf("waveOutWrite error\n");
  44. }
  45. }
  46. void finit(HWAVEOUT device) {
  47. waveOutUnprepareHeader(device,hdr,sizeof(WAVEHDR));
  48. free(data);data=0;
  49. free(hdr);hdr=0;
  50. }
  51. };
  52. struct winmmdevice:audiodevice {
  53. HWAVEOUT device;
  54. int buffersize;
  55. int samplesize; //1=8 bit 2=16bit
  56. abuffer buffer;
  57. int bnum;
  58. int mode; //0=8bit 1=16bit
  59. int playing;
  60. int timer;
  61. int playpos,mixpos;
  62. int timeout;
  63. int lagbuffers;
  64. int iswin98()
  65. {
  66. OSVERSIONINFO osinfo;
  67. osinfo.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
  68. if (GetVersionEx(&osinfo))
  69. {
  70. if
  71. (
  72. (osinfo.dwPlatformId==VER_PLATFORM_WIN32_WINDOWS) && (osinfo.dwMajorVersion>4)
  73. //((osinfo.dwMajorVersion>4)||((osinfo.dwMajorVersion==4)&&(osinfo.dwMinorVersion>0)))
  74. ) //osversion=1;
  75. return 0;
  76. if (osinfo.dwPlatformId==VER_PLATFORM_WIN32_NT) return 0;//osversion=2;
  77. }
  78. return 1;
  79. }
  80. int reset()
  81. {
  82. int sz=(iswin98())?2048:1024; //10ms fragment size 20ms for windows98
  83. mix=new mixer(sz);
  84. device=0;
  85. buffersize=0;
  86. bnum=0;
  87. mode=0;
  88. playing=0;
  89. timer=0;
  90. timeout=0;
  91. playpos=0;
  92. mixpos=0;
  93. return init(44100,2,16,sz);
  94. }
  95. int close()
  96. {
  97. playing=0;
  98. if (timer) timeKillEvent( timer );
  99. timer=0;
  100. mix->releaseall();
  101. if (device)
  102. {
  103. waveOutReset(device);
  104. buffer.finit(device);
  105. waveOutClose(device);
  106. }
  107. }
  108. int init(int freq,int channels,int bits,int size)
  109. {
  110. pcmsetting pcm(freq,channels,bits);
  111. if (bits==8) {mode=0;samplesize=1;} else {mode=1;samplesize=2;}
  112. if (waveOutOpen(&device,WAVE_MAPPER,&pcm.wf,0,(long)this,0)) return 1;
  113. buffersize=size;
  114. bnum=0;
  115. mix->freq=freq;
  116. mix->channels=channels;
  117. buffer.init(device,size*samplesize*32,0);
  118. timeSetEvent(5,5,audioTimerProc,(DWORD)this,TIME_ONESHOT);//PERIODIC );
  119. timeout=0;
  120. playing=1;
  121. lagbuffers=6;
  122. flip();
  123. buffer.play(device);
  124. return 0;
  125. }
  126. void flip()
  127. {
  128. MMTIME time;
  129. int err;
  130. if (playing==0) return;
  131. if (timeout)
  132. {
  133. if (--timeout) return;
  134. buffer.play(device);
  135. }
  136. memset(&time,0,sizeof(MMTIME));
  137. time.wType=TIME_BYTES;
  138. err=waveOutGetPosition(device,&time,sizeof(MMTIME));
  139. if (time.wType!=TIME_BYTES) err=-666;else if (time.u.cb>0x10000000) err=-6667;
  140. if (err) {
  141. // printf("waveOutGetPosition failed err=%d\n",err);fflush(stdout);
  142. waveOutReset(device);
  143. mixpos=0;
  144. memset(buffer.data,0,buffersize*samplesize*32);
  145. buffer.play(device);
  146. return;
  147. }
  148. int wavepos=time.u.cb/samplesize;
  149. int writeahead=buffersize*lagbuffers;
  150. if (wavepos && wavepos+buffersize*2>mixpos)
  151. {
  152. timeout=250;
  153. memset(buffer.data,0,buffersize*samplesize*32);
  154. waveOutReset(device);
  155. if (lagbuffers<10) lagbuffers+=2;
  156. mixpos=buffersize*lagbuffers*2;
  157. // printf("collision");fflush(stdout);
  158. return;
  159. }
  160. int seek=wavepos+writeahead;
  161. while (mixpos<seek)
  162. {
  163. int f=(mixpos/buffersize)&31;
  164. if (mode==0)
  165. {
  166. mix->mix8(buffer.data+f*buffersize);
  167. }
  168. else
  169. {
  170. mix->mix16((short *)buffer.data+f*buffersize);
  171. }
  172. mixpos+=buffersize;
  173. }
  174. }
  175. };
  176. static void __stdcall audioTimerProc( UINT id,UINT msg,DWORD user,DWORD u1,DWORD u2 ) {
  177. ((winmmdevice *)user)->flip();
  178. timeSetEvent(5,5,audioTimerProc,(DWORD)user,TIME_ONESHOT);
  179. }
  180. audiodevice *OpenMultiMediaDevice() {
  181. return new winmmdevice();
  182. }
  183. #endif