snd_mix.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. // snd_mix.c -- portable code to mix sounds for snd_dma.c
  16. #include "client.h"
  17. #include "snd_loc.h"
  18. #define PAINTBUFFER_SIZE 2048
  19. portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
  20. int snd_scaletable[32][256];
  21. int *snd_p, snd_linear_count, snd_vol;
  22. short *snd_out;
  23. void S_WriteLinearBlastStereo16 (void);
  24. #if !(defined __linux__ && defined __i386__)
  25. #if !id386
  26. void S_WriteLinearBlastStereo16 (void)
  27. {
  28. int i;
  29. int val;
  30. for (i=0 ; i<snd_linear_count ; i+=2)
  31. {
  32. val = snd_p[i]>>8;
  33. if (val > 0x7fff)
  34. snd_out[i] = 0x7fff;
  35. else if (val < (short)0x8000)
  36. snd_out[i] = (short)0x8000;
  37. else
  38. snd_out[i] = val;
  39. val = snd_p[i+1]>>8;
  40. if (val > 0x7fff)
  41. snd_out[i+1] = 0x7fff;
  42. else if (val < (short)0x8000)
  43. snd_out[i+1] = (short)0x8000;
  44. else
  45. snd_out[i+1] = val;
  46. }
  47. }
  48. #else
  49. __declspec( naked ) void S_WriteLinearBlastStereo16 (void)
  50. {
  51. __asm {
  52. push edi
  53. push ebx
  54. mov ecx,ds:dword ptr[snd_linear_count]
  55. mov ebx,ds:dword ptr[snd_p]
  56. mov edi,ds:dword ptr[snd_out]
  57. LWLBLoopTop:
  58. mov eax,ds:dword ptr[-8+ebx+ecx*4]
  59. sar eax,8
  60. cmp eax,07FFFh
  61. jg LClampHigh
  62. cmp eax,0FFFF8000h
  63. jnl LClampDone
  64. mov eax,0FFFF8000h
  65. jmp LClampDone
  66. LClampHigh:
  67. mov eax,07FFFh
  68. LClampDone:
  69. mov edx,ds:dword ptr[-4+ebx+ecx*4]
  70. sar edx,8
  71. cmp edx,07FFFh
  72. jg LClampHigh2
  73. cmp edx,0FFFF8000h
  74. jnl LClampDone2
  75. mov edx,0FFFF8000h
  76. jmp LClampDone2
  77. LClampHigh2:
  78. mov edx,07FFFh
  79. LClampDone2:
  80. shl edx,16
  81. and eax,0FFFFh
  82. or edx,eax
  83. mov ds:dword ptr[-4+edi+ecx*2],edx
  84. sub ecx,2
  85. jnz LWLBLoopTop
  86. pop ebx
  87. pop edi
  88. ret
  89. }
  90. }
  91. #endif
  92. #endif
  93. void S_TransferStereo16 (unsigned long *pbuf, int endtime)
  94. {
  95. int lpos;
  96. int lpaintedtime;
  97. snd_p = (int *) paintbuffer;
  98. lpaintedtime = paintedtime;
  99. while (lpaintedtime < endtime)
  100. {
  101. // handle recirculating buffer issues
  102. lpos = lpaintedtime & ((dma.samples>>1)-1);
  103. snd_out = (short *) pbuf + (lpos<<1);
  104. snd_linear_count = (dma.samples>>1) - lpos;
  105. if (lpaintedtime + snd_linear_count > endtime)
  106. snd_linear_count = endtime - lpaintedtime;
  107. snd_linear_count <<= 1;
  108. // write a linear blast of samples
  109. S_WriteLinearBlastStereo16 ();
  110. snd_p += snd_linear_count;
  111. lpaintedtime += (snd_linear_count>>1);
  112. }
  113. }
  114. /*
  115. ===================
  116. S_TransferPaintBuffer
  117. ===================
  118. */
  119. void S_TransferPaintBuffer(int endtime)
  120. {
  121. int out_idx;
  122. int count;
  123. int out_mask;
  124. int *p;
  125. int step;
  126. int val;
  127. unsigned long *pbuf;
  128. pbuf = (unsigned long *)dma.buffer;
  129. if (s_testsound->value)
  130. {
  131. int i;
  132. int count;
  133. // write a fixed sine wave
  134. count = (endtime - paintedtime);
  135. for (i=0 ; i<count ; i++)
  136. paintbuffer[i].left = paintbuffer[i].right = sin((paintedtime+i)*0.1)*20000*256;
  137. }
  138. if (dma.samplebits == 16 && dma.channels == 2)
  139. { // optimized case
  140. S_TransferStereo16 (pbuf, endtime);
  141. }
  142. else
  143. { // general case
  144. p = (int *) paintbuffer;
  145. count = (endtime - paintedtime) * dma.channels;
  146. out_mask = dma.samples - 1;
  147. out_idx = paintedtime * dma.channels & out_mask;
  148. step = 3 - dma.channels;
  149. if (dma.samplebits == 16)
  150. {
  151. short *out = (short *) pbuf;
  152. while (count--)
  153. {
  154. val = *p >> 8;
  155. p+= step;
  156. if (val > 0x7fff)
  157. val = 0x7fff;
  158. else if (val < (short)0x8000)
  159. val = (short)0x8000;
  160. out[out_idx] = val;
  161. out_idx = (out_idx + 1) & out_mask;
  162. }
  163. }
  164. else if (dma.samplebits == 8)
  165. {
  166. unsigned char *out = (unsigned char *) pbuf;
  167. while (count--)
  168. {
  169. val = *p >> 8;
  170. p+= step;
  171. if (val > 0x7fff)
  172. val = 0x7fff;
  173. else if (val < (short)0x8000)
  174. val = (short)0x8000;
  175. out[out_idx] = (val>>8) + 128;
  176. out_idx = (out_idx + 1) & out_mask;
  177. }
  178. }
  179. }
  180. }
  181. /*
  182. ===============================================================================
  183. CHANNEL MIXING
  184. ===============================================================================
  185. */
  186. void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime, int offset);
  187. void S_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime, int offset);
  188. void S_PaintChannels(int endtime)
  189. {
  190. int i;
  191. int end;
  192. channel_t *ch;
  193. sfxcache_t *sc;
  194. int ltime, count;
  195. playsound_t *ps;
  196. snd_vol = s_volume->value*256;
  197. //Com_Printf ("%i to %i\n", paintedtime, endtime);
  198. while (paintedtime < endtime)
  199. {
  200. // if paintbuffer is smaller than DMA buffer
  201. end = endtime;
  202. if (endtime - paintedtime > PAINTBUFFER_SIZE)
  203. end = paintedtime + PAINTBUFFER_SIZE;
  204. // start any playsounds
  205. while (1)
  206. {
  207. ps = s_pendingplays.next;
  208. if (ps == &s_pendingplays)
  209. break; // no more pending sounds
  210. if (ps->begin <= paintedtime)
  211. {
  212. S_IssuePlaysound (ps);
  213. continue;
  214. }
  215. if (ps->begin < end)
  216. end = ps->begin; // stop here
  217. break;
  218. }
  219. // clear the paint buffer
  220. if (s_rawend < paintedtime)
  221. {
  222. // Com_Printf ("clear\n");
  223. memset(paintbuffer, 0, (end - paintedtime) * sizeof(portable_samplepair_t));
  224. }
  225. else
  226. { // copy from the streaming sound source
  227. int s;
  228. int stop;
  229. stop = (end < s_rawend) ? end : s_rawend;
  230. for (i=paintedtime ; i<stop ; i++)
  231. {
  232. s = i&(MAX_RAW_SAMPLES-1);
  233. paintbuffer[i-paintedtime] = s_rawsamples[s];
  234. }
  235. // if (i != end)
  236. // Com_Printf ("partial stream\n");
  237. // else
  238. // Com_Printf ("full stream\n");
  239. for ( ; i<end ; i++)
  240. {
  241. paintbuffer[i-paintedtime].left =
  242. paintbuffer[i-paintedtime].right = 0;
  243. }
  244. }
  245. // paint in the channels.
  246. ch = channels;
  247. for (i=0; i<MAX_CHANNELS ; i++, ch++)
  248. {
  249. ltime = paintedtime;
  250. while (ltime < end)
  251. {
  252. if (!ch->sfx || (!ch->leftvol && !ch->rightvol) )
  253. break;
  254. // max painting is to the end of the buffer
  255. count = end - ltime;
  256. // might be stopped by running out of data
  257. if (ch->end - ltime < count)
  258. count = ch->end - ltime;
  259. sc = S_LoadSound (ch->sfx);
  260. if (!sc)
  261. break;
  262. if (count > 0 && ch->sfx)
  263. {
  264. if (sc->width == 1)// FIXME; 8 bit asm is wrong now
  265. S_PaintChannelFrom8(ch, sc, count, ltime - paintedtime);
  266. else
  267. S_PaintChannelFrom16(ch, sc, count, ltime - paintedtime);
  268. ltime += count;
  269. }
  270. // if at end of loop, restart
  271. if (ltime >= ch->end)
  272. {
  273. if (ch->autosound)
  274. { // autolooping sounds always go back to start
  275. ch->pos = 0;
  276. ch->end = ltime + sc->length;
  277. }
  278. else if (sc->loopstart >= 0)
  279. {
  280. ch->pos = sc->loopstart;
  281. ch->end = ltime + sc->length - ch->pos;
  282. }
  283. else
  284. { // channel just stopped
  285. ch->sfx = NULL;
  286. }
  287. }
  288. }
  289. }
  290. // transfer out according to DMA format
  291. S_TransferPaintBuffer(end);
  292. paintedtime = end;
  293. }
  294. }
  295. void S_InitScaletable (void)
  296. {
  297. int i, j;
  298. int scale;
  299. s_volume->modified = false;
  300. for (i=0 ; i<32 ; i++)
  301. {
  302. scale = i * 8 * 256 * s_volume->value;
  303. for (j=0 ; j<256 ; j++)
  304. snd_scaletable[i][j] = ((signed char)j) * scale;
  305. }
  306. }
  307. #if !(defined __linux__ && defined __i386__)
  308. #if !id386
  309. void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count, int offset)
  310. {
  311. int data;
  312. int *lscale, *rscale;
  313. unsigned char *sfx;
  314. int i;
  315. portable_samplepair_t *samp;
  316. if (ch->leftvol > 255)
  317. ch->leftvol = 255;
  318. if (ch->rightvol > 255)
  319. ch->rightvol = 255;
  320. lscale = snd_scaletable[ ch->leftvol >> 11];
  321. rscale = snd_scaletable[ ch->rightvol >> 11];
  322. sfx = (signed char *)sc->data + ch->pos;
  323. samp = &paintbuffer[offset];
  324. for (i=0 ; i<count ; i++, samp++)
  325. {
  326. data = sfx[i];
  327. samp->left += lscale[data];
  328. samp->right += rscale[data];
  329. }
  330. ch->pos += count;
  331. }
  332. #else
  333. __declspec( naked ) void S_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count, int offset)
  334. {
  335. __asm {
  336. push esi
  337. push edi
  338. push ebx
  339. push ebp
  340. mov ebx,ds:dword ptr[4+16+esp]
  341. mov esi,ds:dword ptr[8+16+esp]
  342. mov eax,ds:dword ptr[4+ebx]
  343. mov edx,ds:dword ptr[8+ebx]
  344. cmp eax,255
  345. jna LLeftSet
  346. mov eax,255
  347. LLeftSet:
  348. cmp edx,255
  349. jna LRightSet
  350. mov edx,255
  351. LRightSet:
  352. and eax,0F8h
  353. add esi,20
  354. and edx,0F8h
  355. mov edi,ds:dword ptr[16+ebx]
  356. mov ecx,ds:dword ptr[12+16+esp]
  357. add esi,edi
  358. shl eax,7
  359. add edi,ecx
  360. shl edx,7
  361. mov ds:dword ptr[16+ebx],edi
  362. add eax,offset snd_scaletable
  363. add edx,offset snd_scaletable
  364. sub ebx,ebx
  365. mov bl,ds:byte ptr[-1+esi+ecx*1]
  366. test ecx,1
  367. jz LMix8Loop
  368. mov edi,ds:dword ptr[eax+ebx*4]
  369. mov ebp,ds:dword ptr[edx+ebx*4]
  370. add edi,ds:dword ptr[paintbuffer+0-8+ecx*8]
  371. add ebp,ds:dword ptr[paintbuffer+4-8+ecx*8]
  372. mov ds:dword ptr[paintbuffer+0-8+ecx*8],edi
  373. mov ds:dword ptr[paintbuffer+4-8+ecx*8],ebp
  374. mov bl,ds:byte ptr[-2+esi+ecx*1]
  375. dec ecx
  376. jz LDone
  377. LMix8Loop:
  378. mov edi,ds:dword ptr[eax+ebx*4]
  379. mov ebp,ds:dword ptr[edx+ebx*4]
  380. add edi,ds:dword ptr[paintbuffer+0-8+ecx*8]
  381. add ebp,ds:dword ptr[paintbuffer+4-8+ecx*8]
  382. mov bl,ds:byte ptr[-2+esi+ecx*1]
  383. mov ds:dword ptr[paintbuffer+0-8+ecx*8],edi
  384. mov ds:dword ptr[paintbuffer+4-8+ecx*8],ebp
  385. mov edi,ds:dword ptr[eax+ebx*4]
  386. mov ebp,ds:dword ptr[edx+ebx*4]
  387. mov bl,ds:byte ptr[-3+esi+ecx*1]
  388. add edi,ds:dword ptr[paintbuffer+0-8*2+ecx*8]
  389. add ebp,ds:dword ptr[paintbuffer+4-8*2+ecx*8]
  390. mov ds:dword ptr[paintbuffer+0-8*2+ecx*8],edi
  391. mov ds:dword ptr[paintbuffer+4-8*2+ecx*8],ebp
  392. sub ecx,2
  393. jnz LMix8Loop
  394. LDone:
  395. pop ebp
  396. pop ebx
  397. pop edi
  398. pop esi
  399. ret
  400. }
  401. }
  402. #endif
  403. #endif
  404. void S_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count, int offset)
  405. {
  406. int data;
  407. int left, right;
  408. int leftvol, rightvol;
  409. signed short *sfx;
  410. int i;
  411. portable_samplepair_t *samp;
  412. leftvol = ch->leftvol*snd_vol;
  413. rightvol = ch->rightvol*snd_vol;
  414. sfx = (signed short *)sc->data + ch->pos;
  415. samp = &paintbuffer[offset];
  416. for (i=0 ; i<count ; i++, samp++)
  417. {
  418. data = sfx[i];
  419. left = (data * leftvol)>>8;
  420. right = (data * rightvol)>>8;
  421. samp->left += left;
  422. samp->right += right;
  423. }
  424. ch->pos += count;
  425. }