1/* 2Copyright (C) 1996-1997 Id Software, Inc. 3 4This program is free software; you can redistribute it and/or 5modify it under the terms of the GNU General Public License 6as published by the Free Software Foundation; either version 2 7of the License, or (at your option) any later version. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13See the GNU General Public License for more details. 14 15You should have received a copy of the GNU General Public License 16along with this program; if not, write to the Free Software 17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19*/ 20// snd_mix.c -- portable code to mix sounds for snd_dma.c 21 22#include "quakedef.h" 23 24#ifdef _WIN32 25#include "winquake.h" 26#else 27#define DWORD unsigned long 28#endif 29 30#define PAINTBUFFER_SIZE 512 31portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE]; 32int snd_scaletable[32][256]; 33int *snd_p, snd_linear_count, snd_vol; 34short *snd_out; 35 36void Snd_WriteLinearBlastStereo16 (void); 37 38#if !id386 39void Snd_WriteLinearBlastStereo16 (void) 40{ 41 int i; 42 int val; 43 44 for (i=0 ; i<snd_linear_count ; i+=2) 45 { 46 val = (snd_p[i]*snd_vol)>>8; 47 if (val > 0x7fff) 48 snd_out[i] = 0x7fff; 49 else if (val < (short)0x8000) 50 snd_out[i] = (short)0x8000; 51 else 52 snd_out[i] = val; 53 54 val = (snd_p[i+1]*snd_vol)>>8; 55 if (val > 0x7fff) 56 snd_out[i+1] = 0x7fff; 57 else if (val < (short)0x8000) 58 snd_out[i+1] = (short)0x8000; 59 else 60 snd_out[i+1] = val; 61 } 62} 63#endif 64 65void S_TransferStereo16 (int endtime) 66{ 67 int lpos; 68 int lpaintedtime; 69 DWORD *pbuf; 70#ifdef _WIN32 71 int reps; 72 DWORD dwSize,dwSize2; 73 DWORD *pbuf2; 74 HRESULT hresult; 75#endif 76 77 snd_vol = volume.value*256; 78 79 snd_p = (int *) paintbuffer; 80 lpaintedtime = paintedtime; 81 82#ifdef _WIN32 83 if (pDSBuf) 84 { 85 reps = 0; 86 87 while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &dwSize, 88 &pbuf2, &dwSize2, 0)) != DS_OK) 89 { 90 if (hresult != DSERR_BUFFERLOST) 91 { 92 Con_Printf ("S_TransferStereo16: DS::Lock Sound Buffer Failed\n"); 93 S_Shutdown (); 94 S_Startup (); 95 return; 96 } 97 98 if (++reps > 10000) 99 { 100 Con_Printf ("S_TransferStereo16: DS: couldn't restore buffer\n"); 101 S_Shutdown (); 102 S_Startup (); 103 return; 104 } 105 } 106 } 107 else 108#endif 109 { 110 pbuf = (DWORD *)shm->buffer; 111 } 112 113 while (lpaintedtime < endtime) 114 { 115 // handle recirculating buffer issues 116 lpos = lpaintedtime & ((shm->samples>>1)-1); 117 118 snd_out = (short *) pbuf + (lpos<<1); 119 120 snd_linear_count = (shm->samples>>1) - lpos; 121 if (lpaintedtime + snd_linear_count > endtime) 122 snd_linear_count = endtime - lpaintedtime; 123 124 snd_linear_count <<= 1; 125 126 // write a linear blast of samples 127 Snd_WriteLinearBlastStereo16 (); 128 129 snd_p += snd_linear_count; 130 lpaintedtime += (snd_linear_count>>1); 131 } 132 133#ifdef _WIN32 134 if (pDSBuf) 135 pDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0); 136#endif 137} 138 139void S_TransferPaintBuffer(int endtime) 140{ 141 int out_idx; 142 int count; 143 int out_mask; 144 int *p; 145 int step; 146 int val; 147 int snd_vol; 148 DWORD *pbuf; 149#ifdef _WIN32 150 int reps; 151 DWORD dwSize,dwSize2; 152 DWORD *pbuf2; 153 HRESULT hresult; 154#endif 155 156 if (shm->samplebits == 16 && shm->channels == 2) 157 { 158 S_TransferStereo16 (endtime); 159 return; 160 } 161 162 p = (int *) paintbuffer; 163 count = (endtime - paintedtime) * shm->channels; 164 out_mask = shm->samples - 1; 165 out_idx = paintedtime * shm->channels & out_mask; 166 step = 3 - shm->channels; 167 snd_vol = volume.value*256; 168 169#ifdef _WIN32 170 if (pDSBuf) 171 { 172 reps = 0; 173 174 while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &dwSize, 175 &pbuf2,&dwSize2, 0)) != DS_OK) 176 { 177 if (hresult != DSERR_BUFFERLOST) 178 { 179 Con_Printf ("S_TransferPaintBuffer: DS::Lock Sound Buffer Failed\n"); 180 S_Shutdown (); 181 S_Startup (); 182 return; 183 } 184 185 if (++reps > 10000) 186 { 187 Con_Printf ("S_TransferPaintBuffer: DS: couldn't restore buffer\n"); 188 S_Shutdown (); 189 S_Startup (); 190 return; 191 } 192 } 193 } 194 else 195#endif 196 { 197 pbuf = (DWORD *)shm->buffer; 198 } 199 200 if (shm->samplebits == 16) 201 { 202 short *out = (short *) pbuf; 203 while (count--) 204 { 205 val = (*p * snd_vol) >> 8; 206 p+= step; 207 if (val > 0x7fff) 208 val = 0x7fff; 209 else if (val < (short)0x8000) 210 val = (short)0x8000; 211 out[out_idx] = val; 212 out_idx = (out_idx + 1) & out_mask; 213 } 214 } 215 else if (shm->samplebits == 8) 216 { 217 unsigned char *out = (unsigned char *) pbuf; 218 while (count--) 219 { 220 val = (*p * snd_vol) >> 8; 221 p+= step; 222 if (val > 0x7fff) 223 val = 0x7fff; 224 else if (val < (short)0x8000) 225 val = (short)0x8000; 226 out[out_idx] = (val>>8) + 128; 227 out_idx = (out_idx + 1) & out_mask; 228 } 229 } 230 231#ifdef _WIN32 232 if (pDSBuf) { 233 DWORD dwNewpos, dwWrite; 234 int il = paintedtime; 235 int ir = endtime - paintedtime; 236 237 ir += il; 238 239 pDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0); 240 241 pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &dwNewpos, &dwWrite); 242 243// if ((dwNewpos >= il) && (dwNewpos <= ir)) 244// Con_Printf("%d-%d p %d c\n", il, ir, dwNewpos); 245 } 246#endif 247} 248 249 250/* 251=============================================================================== 252 253CHANNEL MIXING 254 255=============================================================================== 256*/ 257 258void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime); 259void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime); 260 261void S_PaintChannels(int endtime) 262{ 263 int i; 264 int end; 265 channel_t *ch; 266 sfxcache_t *sc; 267 int ltime, count; 268 269 while (paintedtime < endtime) 270 { 271 // if paintbuffer is smaller than DMA buffer 272 end = endtime; 273 if (endtime - paintedtime > PAINTBUFFER_SIZE) 274 end = paintedtime + PAINTBUFFER_SIZE; 275 276 // clear the paint buffer 277 Q_memset(paintbuffer, 0, (end - paintedtime) * sizeof(portable_samplepair_t)); 278 279 // paint in the channels. 280 ch = channels; 281 for (i=0; i<total_channels ; i++, ch++) 282 { 283 if (!ch->sfx) 284 continue; 285 if (!ch->leftvol && !ch->rightvol) 286 continue; 287 sc = S_LoadSound (ch->sfx); 288 if (!sc) 289 continue; 290 291 ltime = paintedtime; 292 293 while (ltime < end) 294 { // paint up to end 295 if (ch->end < end) 296 count = ch->end - ltime; 297 else 298 count = end - ltime; 299 300 if (count > 0) 301 { 302 if (sc->width == 1) 303 SND_PaintChannelFrom8(ch, sc, count); 304 else 305 SND_PaintChannelFrom16(ch, sc, count); 306 307 ltime += count; 308 } 309 310 // if at end of loop, restart 311 if (ltime >= ch->end) 312 { 313 if (sc->loopstart >= 0) 314 { 315 ch->pos = sc->loopstart; 316 ch->end = ltime + sc->length - ch->pos; 317 } 318 else 319 { // channel just stopped 320 ch->sfx = NULL; 321 break; 322 } 323 } 324 } 325 326 } 327 328 // transfer out according to DMA format 329 S_TransferPaintBuffer(end); 330 paintedtime = end; 331 } 332} 333 334void SND_InitScaletable (void) 335{ 336 int i, j; 337 338 for (i=0 ; i<32 ; i++) 339 for (j=0 ; j<256 ; j++) 340 snd_scaletable[i][j] = ((signed char)j) * i * 8; 341} 342 343 344#if !id386 345 346void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count) 347{ 348 int data; 349 int *lscale, *rscale; 350 unsigned char *sfx; 351 int i; 352 353 if (ch->leftvol > 255) 354 ch->leftvol = 255; 355 if (ch->rightvol > 255) 356 ch->rightvol = 255; 357 358 lscale = snd_scaletable[ch->leftvol >> 3]; 359 rscale = snd_scaletable[ch->rightvol >> 3]; 360 sfx = (unsigned char *)sc->data + ch->pos; 361 362 for (i=0 ; i<count ; i++) 363 { 364 data = sfx[i]; 365 paintbuffer[i].left += lscale[data]; 366 paintbuffer[i].right += rscale[data]; 367 } 368 369 ch->pos += count; 370} 371 372#endif // !id386 373 374 375void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count) 376{ 377 int data; 378 int left, right; 379 int leftvol, rightvol; 380 signed short *sfx; 381 int i; 382 383 leftvol = ch->leftvol; 384 rightvol = ch->rightvol; 385 sfx = (signed short *)sc->data + ch->pos; 386 387 for (i=0 ; i<count ; i++) 388 { 389 data = sfx[i]; 390 left = (data * leftvol) >> 8; 391 right = (data * rightvol) >> 8; 392 paintbuffer[i].left += left; 393 paintbuffer[i].right += right; 394 } 395 396 ch->pos += count; 397} 398 399