Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5131 clevermous 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
39
void Snd_WriteLinearBlastStereo16 (void)
40
{
41
	int		i;
42
	int		val;
43
 
44
	for (i=0 ; i
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
 
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
 
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
 
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
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
 
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
 
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 = (signed char *)sc->data + ch->pos;
361
 
362
	for (i=0 ; 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
 
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
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