snd_mix.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. /*
  2. Copyright (C) 1996-1997 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 "quakedef.h"
  17. #ifdef _WIN32
  18. #include "winquake.h"
  19. #else
  20. #define DWORD unsigned long
  21. #endif
  22. #define PAINTBUFFER_SIZE 512
  23. portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
  24. int snd_scaletable[32][256];
  25. int *snd_p, snd_linear_count, snd_vol;
  26. short *snd_out;
  27. void Snd_WriteLinearBlastStereo16 (void);
  28. #if !id386
  29. void Snd_WriteLinearBlastStereo16 (void)
  30. {
  31. int i;
  32. int val;
  33. for (i=0 ; i<snd_linear_count ; i+=2)
  34. {
  35. val = (snd_p[i]*snd_vol)>>8;
  36. if (val > 0x7fff)
  37. snd_out[i] = 0x7fff;
  38. else if (val < (short)0x8000)
  39. snd_out[i] = (short)0x8000;
  40. else
  41. snd_out[i] = val;
  42. val = (snd_p[i+1]*snd_vol)>>8;
  43. if (val > 0x7fff)
  44. snd_out[i+1] = 0x7fff;
  45. else if (val < (short)0x8000)
  46. snd_out[i+1] = (short)0x8000;
  47. else
  48. snd_out[i+1] = val;
  49. }
  50. }
  51. #endif
  52. void S_TransferStereo16 (int endtime)
  53. {
  54. int lpos;
  55. int lpaintedtime;
  56. DWORD *pbuf;
  57. #ifdef _WIN32
  58. int reps;
  59. DWORD dwSize,dwSize2;
  60. DWORD *pbuf2;
  61. HRESULT hresult;
  62. #endif
  63. snd_vol = volume.value*256;
  64. snd_p = (int *) paintbuffer;
  65. lpaintedtime = paintedtime;
  66. #ifdef _WIN32
  67. if (pDSBuf)
  68. {
  69. reps = 0;
  70. while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &dwSize,
  71. &pbuf2, &dwSize2, 0)) != DS_OK)
  72. {
  73. if (hresult != DSERR_BUFFERLOST)
  74. {
  75. Con_Printf ("S_TransferStereo16: DS::Lock Sound Buffer Failed\n");
  76. S_Shutdown ();
  77. S_Startup ();
  78. return;
  79. }
  80. if (++reps > 10000)
  81. {
  82. Con_Printf ("S_TransferStereo16: DS: couldn't restore buffer\n");
  83. S_Shutdown ();
  84. S_Startup ();
  85. return;
  86. }
  87. }
  88. }
  89. else
  90. #endif
  91. {
  92. pbuf = (DWORD *)shm->buffer;
  93. }
  94. while (lpaintedtime < endtime)
  95. {
  96. // handle recirculating buffer issues
  97. lpos = lpaintedtime & ((shm->samples>>1)-1);
  98. snd_out = (short *) pbuf + (lpos<<1);
  99. snd_linear_count = (shm->samples>>1) - lpos;
  100. if (lpaintedtime + snd_linear_count > endtime)
  101. snd_linear_count = endtime - lpaintedtime;
  102. snd_linear_count <<= 1;
  103. // write a linear blast of samples
  104. Snd_WriteLinearBlastStereo16 ();
  105. snd_p += snd_linear_count;
  106. lpaintedtime += (snd_linear_count>>1);
  107. }
  108. #ifdef _WIN32
  109. if (pDSBuf)
  110. pDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0);
  111. #endif
  112. }
  113. void S_TransferPaintBuffer(int endtime)
  114. {
  115. int out_idx;
  116. int count;
  117. int out_mask;
  118. int *p;
  119. int step;
  120. int val;
  121. int snd_vol;
  122. DWORD *pbuf;
  123. #ifdef _WIN32
  124. int reps;
  125. DWORD dwSize,dwSize2;
  126. DWORD *pbuf2;
  127. HRESULT hresult;
  128. #endif
  129. if (shm->samplebits == 16 && shm->channels == 2)
  130. {
  131. S_TransferStereo16 (endtime);
  132. return;
  133. }
  134. p = (int *) paintbuffer;
  135. count = (endtime - paintedtime) * shm->channels;
  136. out_mask = shm->samples - 1;
  137. out_idx = paintedtime * shm->channels & out_mask;
  138. step = 3 - shm->channels;
  139. snd_vol = volume.value*256;
  140. #ifdef _WIN32
  141. if (pDSBuf)
  142. {
  143. reps = 0;
  144. while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &dwSize,
  145. &pbuf2,&dwSize2, 0)) != DS_OK)
  146. {
  147. if (hresult != DSERR_BUFFERLOST)
  148. {
  149. Con_Printf ("S_TransferPaintBuffer: DS::Lock Sound Buffer Failed\n");
  150. S_Shutdown ();
  151. S_Startup ();
  152. return;
  153. }
  154. if (++reps > 10000)
  155. {
  156. Con_Printf ("S_TransferPaintBuffer: DS: couldn't restore buffer\n");
  157. S_Shutdown ();
  158. S_Startup ();
  159. return;
  160. }
  161. }
  162. }
  163. else
  164. #endif
  165. {
  166. pbuf = (DWORD *)shm->buffer;
  167. }
  168. if (shm->samplebits == 16)
  169. {
  170. short *out = (short *) pbuf;
  171. while (count--)
  172. {
  173. val = (*p * snd_vol) >> 8;
  174. p+= step;
  175. if (val > 0x7fff)
  176. val = 0x7fff;
  177. else if (val < (short)0x8000)
  178. val = (short)0x8000;
  179. out[out_idx] = val;
  180. out_idx = (out_idx + 1) & out_mask;
  181. }
  182. }
  183. else if (shm->samplebits == 8)
  184. {
  185. unsigned char *out = (unsigned char *) pbuf;
  186. while (count--)
  187. {
  188. val = (*p * snd_vol) >> 8;
  189. p+= step;
  190. if (val > 0x7fff)
  191. val = 0x7fff;
  192. else if (val < (short)0x8000)
  193. val = (short)0x8000;
  194. out[out_idx] = (val>>8) + 128;
  195. out_idx = (out_idx + 1) & out_mask;
  196. }
  197. }
  198. #ifdef _WIN32
  199. if (pDSBuf) {
  200. DWORD dwNewpos, dwWrite;
  201. int il = paintedtime;
  202. int ir = endtime - paintedtime;
  203. ir += il;
  204. pDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0);
  205. pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &dwNewpos, &dwWrite);
  206. // if ((dwNewpos >= il) && (dwNewpos <= ir))
  207. // Con_Printf("%d-%d p %d c\n", il, ir, dwNewpos);
  208. }
  209. #endif
  210. }
  211. /*
  212. ===============================================================================
  213. CHANNEL MIXING
  214. ===============================================================================
  215. */
  216. void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime);
  217. void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime);
  218. void S_PaintChannels(int endtime)
  219. {
  220. int i;
  221. int end;
  222. channel_t *ch;
  223. sfxcache_t *sc;
  224. int ltime, count;
  225. while (paintedtime < endtime)
  226. {
  227. // if paintbuffer is smaller than DMA buffer
  228. end = endtime;
  229. if (endtime - paintedtime > PAINTBUFFER_SIZE)
  230. end = paintedtime + PAINTBUFFER_SIZE;
  231. // clear the paint buffer
  232. Q_memset(paintbuffer, 0, (end - paintedtime) * sizeof(portable_samplepair_t));
  233. // paint in the channels.
  234. ch = channels;
  235. for (i=0; i<total_channels ; i++, ch++)
  236. {
  237. if (!ch->sfx)
  238. continue;
  239. if (!ch->leftvol && !ch->rightvol)
  240. continue;
  241. sc = S_LoadSound (ch->sfx);
  242. if (!sc)
  243. continue;
  244. ltime = paintedtime;
  245. while (ltime < end)
  246. { // paint up to end
  247. if (ch->end < end)
  248. count = ch->end - ltime;
  249. else
  250. count = end - ltime;
  251. if (count > 0)
  252. {
  253. if (sc->width == 1)
  254. SND_PaintChannelFrom8(ch, sc, count);
  255. else
  256. SND_PaintChannelFrom16(ch, sc, count);
  257. ltime += count;
  258. }
  259. // if at end of loop, restart
  260. if (ltime >= ch->end)
  261. {
  262. if (sc->loopstart >= 0)
  263. {
  264. ch->pos = sc->loopstart;
  265. ch->end = ltime + sc->length - ch->pos;
  266. }
  267. else
  268. { // channel just stopped
  269. ch->sfx = NULL;
  270. break;
  271. }
  272. }
  273. }
  274. }
  275. // transfer out according to DMA format
  276. S_TransferPaintBuffer(end);
  277. paintedtime = end;
  278. }
  279. }
  280. void SND_InitScaletable (void)
  281. {
  282. int i, j;
  283. for (i=0 ; i<32 ; i++)
  284. for (j=0 ; j<256 ; j++)
  285. snd_scaletable[i][j] = ((signed char)j) * i * 8;
  286. }
  287. #if !id386
  288. void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count)
  289. {
  290. int data;
  291. int *lscale, *rscale;
  292. unsigned char *sfx;
  293. int i;
  294. if (ch->leftvol > 255)
  295. ch->leftvol = 255;
  296. if (ch->rightvol > 255)
  297. ch->rightvol = 255;
  298. lscale = snd_scaletable[ch->leftvol >> 3];
  299. rscale = snd_scaletable[ch->rightvol >> 3];
  300. sfx = (signed char *)sc->data + ch->pos;
  301. for (i=0 ; i<count ; i++)
  302. {
  303. data = sfx[i];
  304. paintbuffer[i].left += lscale[data];
  305. paintbuffer[i].right += rscale[data];
  306. }
  307. ch->pos += count;
  308. }
  309. #endif // !id386
  310. void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count)
  311. {
  312. int data;
  313. int left, right;
  314. int leftvol, rightvol;
  315. signed short *sfx;
  316. int i;
  317. leftvol = ch->leftvol;
  318. rightvol = ch->rightvol;
  319. sfx = (signed short *)sc->data + ch->pos;
  320. for (i=0 ; i<count ; i++)
  321. {
  322. data = sfx[i];
  323. left = (data * leftvol) >> 8;
  324. right = (data * rightvol) >> 8;
  325. paintbuffer[i].left += left;
  326. paintbuffer[i].right += right;
  327. }
  328. ch->pos += count;
  329. }