• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
32 int		snd_scaletable[32][256];
33 int 	*snd_p, snd_linear_count, snd_vol;
34 short	*snd_out;
35 
36 void Snd_WriteLinearBlastStereo16 (void);
37 
38 #if	!id386
Snd_WriteLinearBlastStereo16(void)39 void 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 
S_TransferStereo16(int endtime)65 void 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 
S_TransferPaintBuffer(int endtime)139 void 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 
253 CHANNEL MIXING
254 
255 ===============================================================================
256 */
257 
258 void SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime);
259 void SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime);
260 
S_PaintChannels(int endtime)261 void 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 
SND_InitScaletable(void)334 void 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 
SND_PaintChannelFrom8(channel_t * ch,sfxcache_t * sc,int count)346 void 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 
SND_PaintChannelFrom16(channel_t * ch,sfxcache_t * sc,int count)375 void 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