Quake II RTX doxygen  1.0 dev
mix.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (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. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18 // snd_mix.c -- portable code to mix sounds for snd_dma.c
19 
20 #include "sound.h"
21 
22 #define PAINTBUFFER_SIZE 2048
23 
24 static int snd_scaletable[32][256];
25 static int snd_vol;
26 
28 int s_rawend = 0;
29 
30 static void WriteLinearBlast(int16_t *out, samplepair_t *samp, int count)
31 {
32  int i, val;
33 
34  for (i = 0; i < count; i++, samp++, out += 2) {
35  val = samp->left >> 8;
36  out[0] = clamp(val, INT16_MIN, INT16_MAX);
37 
38  val = samp->right >> 8;
39  out[1] = clamp(val, INT16_MIN, INT16_MAX);
40  }
41 }
42 
43 static void TransferStereo16(samplepair_t *samp, int endtime)
44 {
45  int lpos;
46  int ltime;
47  int16_t *out;
48  int count;
49 
50  for (ltime = paintedtime; ltime < endtime;) {
51  // handle recirculating buffer issues
52  lpos = ltime & ((dma.samples >> 1) - 1);
53 
54  out = (int16_t *)dma.buffer + (lpos << 1);
55 
56  count = (dma.samples >> 1) - lpos;
57  if (ltime + count > endtime)
58  count = endtime - ltime;
59 
60  // write a linear blast of samples
61  WriteLinearBlast(out, samp, count);
62 
63  samp += count;
64  ltime += count;
65  }
66 }
67 
68 static void TransferStereo(samplepair_t *samp, int endtime)
69 {
70  int out_idx, out_mask;
71  int count;
72  int *p, val;
73  int step;
74 
75  p = (int *)samp;
76  count = (endtime - paintedtime) * dma.channels;
77  out_mask = dma.samples - 1;
78  out_idx = paintedtime * dma.channels & out_mask;
79  step = 3 - dma.channels;
80 
81  if (dma.samplebits == 16) {
82  int16_t *out = (int16_t *)dma.buffer;
83  while (count--) {
84  val = *p >> 8;
85  p += step;
86  clamp(val, INT16_MIN, INT16_MAX);
87  out[out_idx] = val;
88  out_idx = (out_idx + 1) & out_mask;
89  }
90  } else if (dma.samplebits == 8) {
91  uint8_t *out = (uint8_t *)dma.buffer;
92  while (count--) {
93  val = *p >> 8;
94  p += step;
95  clamp(val, INT16_MIN, INT16_MAX);
96  out[out_idx] = (val >> 8) + 128;
97  out_idx = (out_idx + 1) & out_mask;
98  }
99  }
100 }
101 
102 static void TransferPaintBuffer(samplepair_t *samp, int endtime)
103 {
104  if (s_testsound->integer) {
105  int i;
106 
107  // write a fixed sine wave
108  for (i = paintedtime; i < endtime; i++) {
109  samp[i].left = samp[i].right = sin(i * 0.1) * 20000 * 256;
110  }
111  }
112 
113  if (dma.samplebits == 16 && dma.channels == 2) {
114  // optimized case
115  TransferStereo16(samp, endtime);
116  } else {
117  // general case
118  TransferStereo(samp, endtime);
119  }
120 }
121 
122 
123 /*
124 ===============================================================================
125 
126 CHANNEL MIXING
127 
128 ===============================================================================
129 */
130 
131 static void Paint8(channel_t *ch, sfxcache_t *sc, int count, samplepair_t *samp)
132 {
133  int data;
134  int *lscale, *rscale;
135  uint8_t *sfx;
136  int i;
137 
138  if (ch->leftvol > 255)
139  ch->leftvol = 255;
140  if (ch->rightvol > 255)
141  ch->rightvol = 255;
142 
143  lscale = snd_scaletable[ch->leftvol >> 3];
144  rscale = snd_scaletable[ch->rightvol >> 3];
145  sfx = (uint8_t *)sc->data + ch->pos;
146 
147  for (i = 0; i < count; i++, samp++) {
148  data = *sfx++;
149  samp->left += lscale[data];
150  samp->right += rscale[data];
151  }
152 
153  ch->pos += count;
154 }
155 
156 static void Paint16(channel_t *ch, sfxcache_t *sc, int count, samplepair_t *samp)
157 {
158  int data;
159  int left, right;
160  int leftvol, rightvol;
161  int16_t *sfx;
162  int i;
163 
164  leftvol = ch->leftvol * snd_vol;
165  rightvol = ch->rightvol * snd_vol;
166  sfx = (int16_t *)sc->data + ch->pos;
167 
168  for (i = 0; i < count; i++, samp++) {
169  data = *sfx++;
170  left = (data * leftvol) >> 8;
171  right = (data * rightvol) >> 8;
172  samp->left += left;
173  samp->right += right;
174  }
175 
176  ch->pos += count;
177 }
178 
179 void S_PaintChannels(int endtime)
180 {
181  samplepair_t paintbuffer[PAINTBUFFER_SIZE];
182  int i;
183  int end;
184  channel_t *ch;
185  sfxcache_t *sc;
186  int ltime, count;
187  playsound_t *ps;
188 
189  while (paintedtime < endtime) {
190  // if paintbuffer is smaller than DMA buffer
191  end = endtime;
192  if (end - paintedtime > PAINTBUFFER_SIZE)
194 
195  // start any playsounds
196  while (1) {
197  ps = s_pendingplays.next;
198  if (ps == &s_pendingplays)
199  break; // no more pending sounds
200  if (ps->begin <= paintedtime) {
201  S_IssuePlaysound(ps);
202  continue;
203  }
204 
205  if (ps->begin < end)
206  end = ps->begin; // stop here
207  break;
208  }
209 
210  // clear the paint buffer
211  memset(paintbuffer, 0, (end - paintedtime) * sizeof(samplepair_t));
212 
213  // paint in the channels.
214  ch = channels;
215  for (i = 0; i < s_numchannels; i++, ch++) {
216  ltime = paintedtime;
217 
218  while (ltime < end) {
219  if (!ch->sfx || (!ch->leftvol && !ch->rightvol))
220  break;
221 
222  // max painting is to the end of the buffer
223  count = end - ltime;
224 
225  // might be stopped by running out of data
226  if (ch->end - ltime < count)
227  count = ch->end - ltime;
228 
229  sc = S_LoadSound(ch->sfx);
230  if (!sc)
231  break;
232 
233  if (count > 0 && ch->sfx) {
234  samplepair_t *samp = &paintbuffer[ltime - paintedtime];
235  if (sc->width == 1)
236  Paint8(ch, sc, count, samp);
237  else
238  Paint16(ch, sc, count, samp);
239 
240  ltime += count;
241  }
242 
243  // if at end of loop, restart
244  if (ltime >= ch->end) {
245  if (ch->autosound) {
246  // autolooping sounds always go back to start
247  ch->pos = 0;
248  ch->end = ltime + sc->length;
249  } else if (sc->loopstart >= 0) {
250  ch->pos = sc->loopstart;
251  ch->end = ltime + sc->length - ch->pos;
252  } else {
253  // channel just stopped
254  ch->sfx = NULL;
255  }
256  }
257  }
258 
259  }
260 
261  if (s_rawend >= paintedtime)
262  {
263  /* add from the streaming sound source */
264  int stop = (end < s_rawend) ? end : s_rawend;
265 
266  for (int i = paintedtime; i < stop; i++)
267  {
268  int s = i & (S_MAX_RAW_SAMPLES - 1);
269  paintbuffer[i - paintedtime].left += s_rawsamples[s].left;
270  paintbuffer[i - paintedtime].right += s_rawsamples[s].right;
271  }
272  }
273 
274  // transfer out according to DMA format
275  TransferPaintBuffer(paintbuffer, end);
276  paintedtime = end;
277  }
278 }
279 
280 
282 {
283  int i, j;
284  int scale;
285 
286  snd_vol = S_GetLinearVolume(s_volume->value) * 256;
287  for (i = 0; i < 32; i++) {
288  scale = i * 8 * snd_vol;
289  for (j = 0; j < 256; j++) {
290  snd_scaletable[i][j] = (j - 128) * scale;
291  }
292  }
293 
294  s_volume->modified = qfalse;
295 }
296 
297 /*
298  * Cinematic streaming and voice over network.
299  * This could be used for chat over network, but
300  * that would be terrible slow.
301  */
302 void
303 S_RawSamples(int samples, int rate, int width,
304  int channels, byte *data, float volume)
305 {
306  if (!s_started) return;
307 
308  if (s_started == SS_OAL)
309  {
310  AL_RawSamples(samples, rate, width, channels, data, volume);
311  return;
312  }
313 
314  if (s_rawend < paintedtime)
316 
317  // mimic the OpenAL behavior: s_volume is master volume
318  volume *= s_volume->value;
319 
320  // rescale because ogg is always 44100 and dma is configurable via s_khz
321  float scale = (float)rate / dma.speed;
322  int intVolume = (int)(256 * volume);
323 
324  if ((channels == 2) && (width == 2))
325  {
326  for (int i = 0; ; i++)
327  {
328  int src = (int)(i * scale);
329 
330  if (src >= samples)
331  {
332  break;
333  }
334 
335  int dst = s_rawend & (S_MAX_RAW_SAMPLES - 1);
336  s_rawend++;
337  s_rawsamples[dst].left = ((short *)data)[src * 2] * intVolume;
338  s_rawsamples[dst].right = ((short *)data)[src * 2 + 1] * intVolume;
339  }
340  }
341  else if ((channels == 1) && (width == 2))
342  {
343  for (int i = 0; ; i++)
344  {
345  int src = (int)(i * scale);
346 
347  if (src >= samples)
348  {
349  break;
350  }
351 
352  int dst = s_rawend & (S_MAX_RAW_SAMPLES - 1);
353  s_rawend++;
354  s_rawsamples[dst].left = ((short *)data)[src] * intVolume;
355  s_rawsamples[dst].right = ((short *)data)[src] * intVolume;
356  }
357  }
358  else if ((channels == 2) && (width == 1))
359  {
360  intVolume *= 256;
361 
362  for (int i = 0; ; i++)
363  {
364  int src = (int)(i * scale);
365 
366  if (src >= samples)
367  {
368  break;
369  }
370 
371  int dst = s_rawend & (S_MAX_RAW_SAMPLES - 1);
372  s_rawend++;
373  s_rawsamples[dst].left =
374  (((byte *)data)[src * 2] - 128) * intVolume;
375  s_rawsamples[dst].right =
376  (((byte *)data)[src * 2 + 1] - 128) * intVolume;
377  }
378  }
379  else if ((channels == 1) && (width == 1))
380  {
381  intVolume *= 256;
382 
383  for (int i = 0; ; i++)
384  {
385  int src = (int)(i * scale);
386 
387  if (src >= samples)
388  {
389  break;
390  }
391 
392  int dst = s_rawend & (S_MAX_RAW_SAMPLES - 1);
393  s_rawend++;
394  s_rawsamples[dst].left = (((byte *)data)[src] - 128) * intVolume;
395  s_rawsamples[dst].right = (((byte *)data)[src] - 128) * intVolume;
396  }
397  }
398 }
399 
401 {
402 #ifdef USE_OPENAL
403  if (s_started == SS_OAL)
404  {
406  }
407 #endif
408 }
Paint16
static void Paint16(channel_t *ch, sfxcache_t *sc, int count, samplepair_t *samp)
Definition: mix.c:156
dma
dma_t dma
Definition: dma.c:22
playsound_s
Definition: sound.h:55
TransferStereo16
static void TransferStereo16(samplepair_t *samp, int endtime)
Definition: mix.c:43
samplepair_s::left
int left
Definition: sound.h:29
channels
channel_t channels[MAX_CHANNELS]
Definition: main.c:29
PAINTBUFFER_SIZE
#define PAINTBUFFER_SIZE
Definition: mix.c:22
snd_vol
static int snd_vol
Definition: mix.c:25
S_InitScaletable
void S_InitScaletable(void)
Definition: mix.c:281
samplepair_s::right
int right
Definition: sound.h:30
channel_s::end
int end
Definition: sound.h:72
TransferPaintBuffer
static void TransferPaintBuffer(samplepair_t *samp, int endtime)
Definition: mix.c:102
sfxcache_s::length
int length
Definition: sound.h:34
paintedtime
int paintedtime
Definition: main.c:43
playsound_s::begin
unsigned begin
Definition: sound.h:64
snd_scaletable
static int snd_scaletable[32][256]
Definition: mix.c:24
s_rawsamples
samplepair_t s_rawsamples[S_MAX_RAW_SAMPLES]
Definition: mix.c:27
width
static int width
Definition: physical_sky.c:38
AL_UnqueueRawSamples
void AL_UnqueueRawSamples()
Definition: al.c:562
s_testsound
cvar_t * s_testsound
Definition: dma.c:25
TransferStereo
static void TransferStereo(samplepair_t *samp, int endtime)
Definition: mix.c:68
S_UnqueueRawSamples
void S_UnqueueRawSamples()
Definition: mix.c:400
channel_s::pos
int pos
Definition: sound.h:73
playsound_s::next
struct playsound_s * next
Definition: sound.h:56
samplepair_s
Definition: sound.h:28
s_numchannels
int s_numchannels
Definition: main.c:30
S_IssuePlaysound
void S_IssuePlaysound(playsound_t *ps)
Definition: main.c:759
channel_s::autosound
qboolean autosound
Definition: sound.h:81
sfxcache_s::data
byte data[1]
Definition: sound.h:41
S_LoadSound
sfxcache_t * S_LoadSound(sfx_t *s)
Definition: mem.c:288
sfxcache_s::loopstart
int loopstart
Definition: sound.h:35
channel_s::sfx
sfx_t * sfx
Definition: sound.h:69
sfxcache_s
Definition: sound.h:33
channel_s::rightvol
int rightvol
Definition: sound.h:71
s_volume
cvar_t * s_volume
Definition: main.c:58
channel_s::leftvol
int leftvol
Definition: sound.h:70
s_pendingplays
playsound_t s_pendingplays
Definition: main.c:56
AL_RawSamples
void AL_RawSamples(int samples, int rate, int width, int channels, byte *data, float volume)
Definition: al.c:505
right
static vec3_t right
Definition: p_view.c:27
s_rawend
int s_rawend
Definition: mix.c:28
channel_s
Definition: sound.h:68
samples
unsigned samples[LAG_WIDTH]
Definition: screen.c:528
S_MAX_RAW_SAMPLES
#define S_MAX_RAW_SAMPLES
Definition: sound.h:154
S_GetLinearVolume
float S_GetLinearVolume(float perceptual)
Definition: main.c:1171
S_PaintChannels
void S_PaintChannels(int endtime)
Definition: mix.c:179
s_started
sndstarted_t s_started
Definition: main.c:32
int
CONST PIXELFORMATDESCRIPTOR int
Definition: wgl.c:26
sfxcache_s::width
int width
Definition: sound.h:36
Paint8
static void Paint8(channel_t *ch, sfxcache_t *sc, int count, samplepair_t *samp)
Definition: mix.c:131
sound.h
WriteLinearBlast
static void WriteLinearBlast(int16_t *out, samplepair_t *samp, int count)
Definition: mix.c:30
S_RawSamples
void S_RawSamples(int samples, int rate, int width, int channels, byte *data, float volume)
Definition: mix.c:303