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