audiostub.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  1. #include <windows.h>
  2. #include "audiostub.h"
  3. #define CAPTION "NSV Player Sound Output Error"
  4. #define MAX(x,y) (( y ) < ( x ) ? ( x ) : ( y ))
  5. #define MIN(x,y) (( x ) < ( y ) ? ( x ) : ( y ))
  6. #define S_MINSIZE (1<<28)
  7. #define MAX_NUM_BLOCKS 8
  8. #define NUM_BLOCKS 8
  9. #define BUFSIZE_MS 1500
  10. #define BLOCKSIZE_MAX 32768
  11. #define BLOCKSIZE_MIN 8192
  12. int g_audio_use_mixer=0;
  13. class PCM_AudioOut : public IAudioOutput
  14. {
  15. public:
  16. PCM_AudioOut(int samplerate, int numchannels, int bitspersamp);
  17. ~PCM_AudioOut();
  18. int canwrite(); // returns bytes writeable
  19. void write(void *_buf, int len);
  20. unsigned int getpos();
  21. unsigned int getwritepos();
  22. void flush(unsigned int time_ms);
  23. void pause(int pause);
  24. int isplaying(void);
  25. void setvolume(int volume);
  26. void setpan(int pan);
  27. int open_success() { return init; }
  28. void getdescstr(char *buf)
  29. {
  30. *buf=0;
  31. if (g_srate && g_nch) wsprintf(buf,"%dkHz %s",g_srate/1000,g_nch==2?"stereo":"mono");
  32. }
  33. private:
  34. DWORD ThreadP();
  35. void _setvol(void);
  36. static DWORD WINAPI _threadproc(LPVOID p);
  37. static void CALLBACK cbFunc(HWAVEOUT hwo,UINT uMsg,DWORD dwInstance,DWORD dwParam1,DWORD dwParam2)
  38. {
  39. if (uMsg == WOM_DONE) { ReleaseSemaphore((HANDLE)dwInstance,1,NULL);}
  40. }
  41. void do_set_blocksizes(void);
  42. void do_samples_altvol(char *in, int blen);
  43. int init;
  44. int min_blocksize;
  45. int max_blocksize;
  46. int ispcnt;
  47. int num_blocks;
  48. char *g_buffer, *g_buffer_write, *g_buffer_read;
  49. int g_buffer_length, g_buffer_valid,g_buffer_inlength;
  50. HWAVEOUT g_hWaveOut;
  51. WAVEHDR g_wave_headers[MAX_NUM_BLOCKS];
  52. int g_bps,g_nch,g_srate;
  53. volatile int g_pause, g_wavecnt, g_prebuf,g_writeall, g_quit_flag,g_writetime_bytes, g_outtime_bytes, g_outtime_interp;
  54. HANDLE g_hSem,g_hEvent, g_hThread;
  55. CRITICAL_SECTION g_cs;
  56. int g_bytes_per_sec;
  57. int a_v,a_p;
  58. unsigned char *g_vol_table;
  59. };
  60. PCM_AudioOut::PCM_AudioOut(int samplerate, int numchannels, int bitspersamp)
  61. {
  62. init=0;
  63. a_v=255;
  64. a_p=0;
  65. num_blocks=0;
  66. g_buffer_valid=g_buffer_inlength=0;
  67. g_hWaveOut=NULL;
  68. memset(g_wave_headers,0,sizeof(g_wave_headers));
  69. g_hSem=g_hEvent=g_hThread=0;
  70. int x;
  71. DWORD id;
  72. MMRESULT res;
  73. WAVEFORMATEX wfx={WAVE_FORMAT_PCM,numchannels,samplerate,samplerate*numchannels*(bitspersamp/8),
  74. numchannels*(bitspersamp/8),bitspersamp};
  75. g_bps=bitspersamp;
  76. g_nch=numchannels;
  77. g_srate=samplerate;
  78. g_bytes_per_sec=wfx.nAvgBytesPerSec;
  79. {
  80. char *p=(char*)g_wave_headers;
  81. int n=sizeof(g_wave_headers);
  82. while (n--) *p++=0;
  83. }
  84. g_buffer_length = MulDiv(g_bytes_per_sec, BUFSIZE_MS, 1000);
  85. g_buffer_length &= ~1023;
  86. if (g_buffer_length < 4096) g_buffer_length=4096;
  87. g_buffer=(char *)GlobalAlloc(GMEM_FIXED,g_buffer_length+min(65536,g_buffer_length));
  88. if (g_buffer == NULL)
  89. {
  90. MessageBox(NULL,"Error allocating buffer", CAPTION,MB_OK|MB_ICONSTOP);
  91. return;
  92. }
  93. g_prebuf=g_buffer_length/4;
  94. g_buffer_read=g_buffer_write=g_buffer;
  95. g_wavecnt=g_pause=g_writeall=g_buffer_valid=g_writetime_bytes=g_outtime_bytes=g_buffer_inlength=0;
  96. g_quit_flag=0;
  97. g_vol_table=NULL;
  98. do_set_blocksizes();
  99. g_hSem=CreateSemaphore(NULL,0,256,NULL);
  100. for (x = 0; (res=waveOutOpen(&g_hWaveOut,WAVE_MAPPER,&wfx,(DWORD)cbFunc,(DWORD)g_hSem,CALLBACK_FUNCTION))==MMSYSERR_ALLOCATED && x<10; x ++)
  101. Sleep(100);
  102. if (res != MMSYSERR_NOERROR)
  103. {
  104. char t[512];
  105. waveOutGetErrorText(res,t,sizeof(t));
  106. MessageBox(NULL,t, CAPTION,MB_OK|MB_ICONSTOP);
  107. GlobalFree((HGLOBAL) g_buffer);
  108. CloseHandle(g_hSem);
  109. g_buffer = NULL;
  110. return;
  111. }
  112. ispcnt=0;
  113. g_outtime_interp=GetTickCount();
  114. g_hEvent=CreateEvent(NULL,FALSE,FALSE,NULL);
  115. InitializeCriticalSection(&g_cs);
  116. g_hThread=CreateThread(NULL,0,_threadproc,(void*)this,0,&id);
  117. SetThreadPriority(g_hThread,THREAD_PRIORITY_HIGHEST);
  118. init=1;
  119. }
  120. void PCM_AudioOut::do_set_blocksizes(void)
  121. {
  122. int t,t2,t4;
  123. t=(MulDiv(BLOCKSIZE_MIN,g_bytes_per_sec,44100)+1023)&~1023;
  124. if (t<1024) t=1024;
  125. if (t>32768) t=32768;
  126. t2=(MulDiv(BLOCKSIZE_MAX,g_bytes_per_sec,44100*4)+1023)&~1023;
  127. if (t2 < t) t2 = t;
  128. if (t2 > 65536) t2=65536;
  129. t4 = NUM_BLOCKS;
  130. num_blocks=t4;
  131. max_blocksize=t2;
  132. min_blocksize=t;
  133. }
  134. PCM_AudioOut::~PCM_AudioOut(void)
  135. {
  136. if (init)
  137. {
  138. int x;
  139. g_quit_flag=1;
  140. SetEvent(g_hEvent);
  141. while (g_quit_flag == 1) Sleep(70);
  142. waveOutReset(g_hWaveOut);
  143. for (x = 0; x < MAX_NUM_BLOCKS; x++)
  144. if (g_wave_headers[x].dwFlags & WHDR_PREPARED)
  145. waveOutUnprepareHeader(g_hWaveOut,&g_wave_headers[x],sizeof(g_wave_headers[0]));
  146. if (waveOutClose(g_hWaveOut) != MMSYSERR_NOERROR)
  147. {
  148. MessageBox(NULL,"Error closing sound device.",CAPTION,MB_OK);
  149. }
  150. if (g_buffer) GlobalFree((HGLOBAL) g_buffer);
  151. DeleteCriticalSection(&g_cs);
  152. CloseHandle(g_hThread);
  153. CloseHandle(g_hSem);
  154. CloseHandle(g_hEvent);
  155. if(g_vol_table) GlobalFree((HGLOBAL)g_vol_table);
  156. }
  157. }
  158. void PCM_AudioOut::write(void *_buf, int len)
  159. {
  160. char *buf=(char *)_buf;
  161. int l2;
  162. if (len > 8192) len=8192;
  163. l2=(g_buffer_write+len)-(g_buffer+g_buffer_length);
  164. if (len <= 0 || !buf)
  165. {
  166. g_writeall=1;
  167. //g_prebuf=0;
  168. SetEvent(g_hEvent);
  169. return;
  170. }
  171. ispcnt=0;
  172. g_writeall=0;
  173. if (l2 > 0)
  174. {
  175. int l1=len-l2;
  176. memcpy(g_buffer_write,buf,l1);
  177. memcpy(g_buffer,buf+l1,l2);
  178. g_buffer_write=g_buffer+l2;
  179. }
  180. else
  181. {
  182. memcpy(g_buffer_write,buf,len);
  183. g_buffer_write += len;
  184. if (g_buffer_write == g_buffer+g_buffer_length) g_buffer_write=g_buffer;
  185. }
  186. EnterCriticalSection(&g_cs);
  187. g_buffer_valid+=len;
  188. LeaveCriticalSection(&g_cs);
  189. g_writetime_bytes+=len;
  190. if (g_wavecnt < num_blocks)
  191. {
  192. SetEvent(g_hEvent);
  193. }
  194. return;
  195. }
  196. int PCM_AudioOut::canwrite(void)
  197. {
  198. int t=(g_buffer_length-g_buffer_valid);
  199. if (g_wavecnt==0)
  200. {
  201. SetEvent(g_hEvent);
  202. }
  203. if (t>8192) t=8192; // RG: since write() caps the # of bytes at 8192, this should reflect that! otherwise, if we call write() with too many bytes, it throws the extra away and we'll never know it.
  204. return t;
  205. }
  206. int PCM_AudioOut::isplaying(void)
  207. {
  208. if (g_wavecnt==0)
  209. {
  210. SetEvent(g_hEvent);
  211. }
  212. if (ispcnt < 7) ispcnt++;
  213. if (g_buffer_valid < MIN(g_buffer_length/2,min_blocksize) && ispcnt==7)
  214. {
  215. g_writeall=1;
  216. g_prebuf=0;
  217. }
  218. return (g_wavecnt>0) || (g_buffer_valid>0);
  219. }
  220. void PCM_AudioOut::pause(int pause)
  221. {
  222. if (g_hWaveOut)
  223. {
  224. int lastp=g_pause;
  225. g_pause=pause;
  226. if (pause == lastp) return;
  227. if (g_pause)
  228. waveOutPause(g_hWaveOut);
  229. else
  230. {
  231. waveOutRestart(g_hWaveOut);
  232. g_outtime_interp=GetTickCount();
  233. SetEvent(g_hEvent);
  234. }
  235. }
  236. }
  237. void PCM_AudioOut::_setvol(void)
  238. {
  239. DWORD vol, vo2, gv;
  240. if (g_hWaveOut)
  241. {
  242. a_v=MIN(255,MAX(a_v,0));
  243. a_p=MIN(127,MAX(a_p,-127));
  244. vo2 = vol = (a_v*65535) / 255;
  245. if (a_p > 0)
  246. {
  247. vol *= (127-a_p);
  248. vol /= 127;
  249. }
  250. else if (a_p < 0)
  251. {
  252. vo2 *= (127+a_p);
  253. vo2 /= 127;
  254. }
  255. gv=vol|(vo2<<16);
  256. if(g_audio_use_mixer) {
  257. if(g_vol_table) {
  258. EnterCriticalSection(&g_cs);
  259. GlobalFree((HGLOBAL)g_vol_table);
  260. g_vol_table=NULL;
  261. LeaveCriticalSection(&g_cs);
  262. }
  263. waveOutSetVolume(g_hWaveOut,gv);
  264. } else {
  265. EnterCriticalSection(&g_cs);
  266. if(!g_vol_table) {
  267. int l=(g_bps==8)?512:(4*32769);
  268. g_vol_table=(unsigned char *)GlobalAlloc(GPTR,l);
  269. }
  270. //compute volume lookup table
  271. int x;
  272. if (g_bps==8) {
  273. if (g_nch==1) for (x = 0; x < 256; x ++) g_vol_table[x] = (x*a_v)/256;
  274. else for (x = 0; x < 256; x ++)
  275. {
  276. g_vol_table[x] = (x*(int)vol)/65536;
  277. g_vol_table[x+256] = (x*(int)vo2)/65536;
  278. }
  279. } else {
  280. short *vol_tab16 = (short *)g_vol_table;
  281. if (g_nch==1) for (x = 0; x < 32769; x ++) vol_tab16[x] = -(x*a_v)/256;
  282. else for (x = 0; x < 32769; x ++)
  283. {
  284. vol_tab16[x] = -(x*(int)vol)/65536;
  285. vol_tab16[x+32769] = -(x*(int)vo2)/65536;
  286. }
  287. }
  288. LeaveCriticalSection(&g_cs);
  289. }
  290. }
  291. }
  292. void PCM_AudioOut::flush(unsigned int time_ms)
  293. {
  294. int x;
  295. EnterCriticalSection(&g_cs);
  296. g_outtime_bytes=g_writetime_bytes=MulDiv(time_ms,g_bytes_per_sec,1000);
  297. waveOutReset(g_hWaveOut);
  298. for (x = 0; x < MAX_NUM_BLOCKS; x++)
  299. if ((g_wave_headers[x].dwFlags & WHDR_PREPARED))
  300. {
  301. waveOutUnprepareHeader(g_hWaveOut,&g_wave_headers[x],sizeof(g_wave_headers[0]));
  302. g_wave_headers[x].dwFlags =0;
  303. }
  304. while (WaitForSingleObject(g_hSem,0)==WAIT_OBJECT_0);
  305. g_prebuf=g_buffer_length/8;
  306. g_buffer_read=g_buffer_write=g_buffer;
  307. g_writeall=g_wavecnt=g_buffer_valid=g_buffer_inlength=0;
  308. ispcnt=0;
  309. LeaveCriticalSection(&g_cs);
  310. }
  311. unsigned int PCM_AudioOut::getwritepos(void)
  312. {
  313. return MulDiv(g_writetime_bytes,1000,g_bytes_per_sec);
  314. }
  315. unsigned int PCM_AudioOut::getpos(void)
  316. {
  317. unsigned int t;
  318. if (!g_pause)
  319. {
  320. t=GetTickCount()-g_outtime_interp;
  321. if (t > 1000) t=1000;
  322. }
  323. else t=0;
  324. return t+MulDiv(g_outtime_bytes,1000,g_bytes_per_sec);
  325. }
  326. DWORD WINAPI PCM_AudioOut::_threadproc(LPVOID p)
  327. {
  328. return ((PCM_AudioOut *)p)->ThreadP();
  329. }
  330. DWORD PCM_AudioOut::ThreadP()
  331. {
  332. HANDLE hs[2]={g_hSem,g_hEvent};
  333. while (1)
  334. {
  335. int i;
  336. i=WaitForMultipleObjects(2,hs,FALSE,INFINITE);
  337. if (g_quit_flag) break;
  338. if (i == WAIT_OBJECT_0)
  339. {
  340. int x;
  341. for (x = 0; x < MAX_NUM_BLOCKS && !(g_wave_headers[x].dwFlags & WHDR_DONE); x++);
  342. if (x < MAX_NUM_BLOCKS)
  343. {
  344. EnterCriticalSection(&g_cs);
  345. if (g_wave_headers[x].dwFlags & WHDR_DONE)
  346. {
  347. int r=g_wave_headers[x].dwBufferLength;
  348. g_outtime_interp=GetTickCount();
  349. g_buffer_valid -=r;
  350. g_buffer_inlength-=r;
  351. g_outtime_bytes +=r;
  352. waveOutUnprepareHeader(g_hWaveOut,&g_wave_headers[x],sizeof(g_wave_headers[0]));
  353. g_wave_headers[x].dwFlags=0;
  354. g_wavecnt--;
  355. i++;
  356. }
  357. LeaveCriticalSection(&g_cs);
  358. }
  359. }
  360. if (i == WAIT_OBJECT_0+1 && !g_pause)
  361. {
  362. int l;
  363. int m;
  364. int t=num_blocks;
  365. EnterCriticalSection(&g_cs);
  366. l=g_buffer_valid-g_buffer_inlength;
  367. LeaveCriticalSection(&g_cs);
  368. again:
  369. if (g_quit_flag) break;
  370. if (g_writeall && l<max_blocksize)
  371. {
  372. ispcnt=0;
  373. g_writeall=0;
  374. m=1;
  375. }
  376. else
  377. {
  378. m=MAX(MIN(g_buffer_length/2,min_blocksize),g_prebuf);
  379. l&=~1023;
  380. }
  381. if (l >= m && g_wavecnt < t)
  382. {
  383. int x;
  384. if (l > max_blocksize) l=max_blocksize;
  385. for (x = 0; x < t && (g_wave_headers[x].dwFlags & WHDR_PREPARED); x++);
  386. if (x < t)
  387. {
  388. int ml=(g_buffer+g_buffer_length)-g_buffer_read;
  389. if (l > g_buffer_length) l=g_buffer_length;
  390. if (l>ml)
  391. {
  392. int addlen=l-ml;
  393. if (addlen > 65536) addlen=65536;
  394. if (addlen > g_buffer_length) addlen=g_buffer_length;
  395. memcpy(g_buffer+g_buffer_length,g_buffer,addlen);
  396. }
  397. g_wave_headers[x].dwBufferLength=l;
  398. g_wave_headers[x].lpData=g_buffer_read;
  399. if (waveOutPrepareHeader(g_hWaveOut,&g_wave_headers[x],sizeof(g_wave_headers[0])) == MMSYSERR_NOERROR)
  400. {
  401. do_samples_altvol(g_wave_headers[x].lpData,g_wave_headers[x].dwBufferLength);
  402. if (waveOutWrite(g_hWaveOut,&g_wave_headers[x],sizeof(g_wave_headers[0])) == MMSYSERR_NOERROR)
  403. {
  404. g_prebuf=0;
  405. g_wavecnt++;
  406. g_buffer_inlength += l;
  407. g_buffer_read += l;
  408. if (g_buffer_read >= g_buffer+g_buffer_length) g_buffer_read-=g_buffer_length;
  409. if (g_wavecnt < t)
  410. {
  411. EnterCriticalSection(&g_cs);
  412. l=g_buffer_valid-g_buffer_inlength;
  413. LeaveCriticalSection(&g_cs);
  414. if (l >= m) goto again;
  415. }
  416. }
  417. else
  418. {
  419. waveOutUnprepareHeader(g_hWaveOut,&g_wave_headers[x],sizeof(g_wave_headers[0]));
  420. g_wave_headers[x].dwFlags=0;
  421. }
  422. }
  423. else g_wave_headers[x].dwFlags=0;
  424. }
  425. }
  426. }
  427. }
  428. g_quit_flag=2;
  429. return 0;
  430. }
  431. void PCM_AudioOut::do_samples_altvol(char *in, int blen)
  432. {
  433. if ((a_v != 255 || a_p) && g_vol_table)
  434. {
  435. EnterCriticalSection(&g_cs);
  436. if (g_bps == 8)
  437. {
  438. unsigned char *i=(unsigned char *)in;
  439. int x = blen;
  440. if (g_nch==1)
  441. {
  442. while (x--) { *i = g_vol_table[*i]; i ++; }
  443. }
  444. else
  445. {
  446. x>>=1;
  447. while (x--)
  448. {
  449. i[0] = g_vol_table[i[0]];
  450. i[1] = g_vol_table[i[1] + 256];
  451. i+=2;
  452. }
  453. }
  454. }
  455. else if (g_bps == 16)
  456. {
  457. short *i = (short *) in;
  458. short *tab= (short *)g_vol_table;
  459. int x = blen>>1;
  460. if (g_nch==1)
  461. {
  462. while (x--)
  463. {
  464. int a = i[0];
  465. if (a <= 0) i[0] = tab[-a];
  466. else i[0] = -tab[a];
  467. i++;
  468. }
  469. }
  470. else
  471. {
  472. x>>=1;
  473. while (x--)
  474. {
  475. int a = i[0];
  476. if (a <= 0) i[0] = tab[-a];
  477. else i[0] = -tab[a];
  478. a=i[1];
  479. if (a <= 0) i[1] = tab[32769-a];
  480. else i[1] = -tab[32769+a];
  481. i+=2;
  482. }
  483. }
  484. }
  485. LeaveCriticalSection(&g_cs);
  486. }
  487. }
  488. void PCM_AudioOut::setvolume(int volume)
  489. {
  490. if (volume >= 0 && volume <= 255) a_v=volume;
  491. _setvol();
  492. }
  493. void PCM_AudioOut::setpan(int pan)
  494. {
  495. if (pan >= -255 && pan <= 255) a_p=pan;
  496. _setvol();
  497. }
  498. IAudioOutput *PCMOUT_CREATE(unsigned int outfmt[8])
  499. {
  500. if (outfmt[0] != NSV_MAKETYPE('P','C','M',' ') ||
  501. !outfmt[1] || !outfmt[2] || !outfmt[3]) return NULL;
  502. PCM_AudioOut *p=new PCM_AudioOut(outfmt[1],outfmt[2],outfmt[3]);
  503. if (p->open_success()) return p;
  504. delete p;
  505. return NULL;
  506. }