mirror of
https://github.com/DrBeef/QuakeQuest.git
synced 2024-11-29 07:22:21 +00:00
533 lines
18 KiB
C
533 lines
18 KiB
C
|
/*
|
||
|
Copyright (C) 1996-1997 Id Software, Inc.
|
||
|
|
||
|
This program is free software; you can redistribute it and/or
|
||
|
modify it under the terms of the GNU General Public License
|
||
|
as published by the Free Software Foundation; either version 2
|
||
|
of the License, or (at your option) any later version.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||
|
|
||
|
See the GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
|
along with this program; if not, write to the Free Software
|
||
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||
|
|
||
|
*/
|
||
|
|
||
|
#include "quakedef.h"
|
||
|
#include "snd_main.h"
|
||
|
|
||
|
extern cvar_t snd_softclip;
|
||
|
|
||
|
static portable_sampleframe_t paintbuffer[PAINTBUFFER_SIZE];
|
||
|
static portable_sampleframe_t paintbuffer_unswapped[PAINTBUFFER_SIZE];
|
||
|
|
||
|
extern speakerlayout_t snd_speakerlayout; // for querying the listeners
|
||
|
|
||
|
static void S_CaptureAVISound(const portable_sampleframe_t *paintbuffer, size_t length)
|
||
|
{
|
||
|
size_t i;
|
||
|
unsigned int j;
|
||
|
|
||
|
if (!cls.capturevideo.active)
|
||
|
return;
|
||
|
|
||
|
// undo whatever swapping the channel layout (swapstereo, ALSA) did
|
||
|
for(j = 0; j < snd_speakerlayout.channels; ++j)
|
||
|
{
|
||
|
unsigned int j0 = snd_speakerlayout.listeners[j].channel_unswapped;
|
||
|
for(i = 0; i < length; ++i)
|
||
|
paintbuffer_unswapped[i].sample[j0] = paintbuffer[i].sample[j];
|
||
|
}
|
||
|
|
||
|
SCR_CaptureVideo_SoundFrame(paintbuffer_unswapped, length);
|
||
|
}
|
||
|
|
||
|
extern cvar_t snd_softclip;
|
||
|
|
||
|
static void S_SoftClipPaintBuffer(portable_sampleframe_t *painted_ptr, int nbframes, int width, int channels)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
if((snd_softclip.integer == 1 && width <= 2) || snd_softclip.integer > 1)
|
||
|
{
|
||
|
portable_sampleframe_t *p = painted_ptr;
|
||
|
|
||
|
#if 0
|
||
|
/* Soft clipping, the sound of a dream, thanks to Jon Wattes
|
||
|
post to Musicdsp.org */
|
||
|
#define SOFTCLIP(x) (x) = sin(bound(-M_PI/2, (x), M_PI/2)) * 0.25
|
||
|
#endif
|
||
|
|
||
|
// let's do a simple limiter instead, seems to sound better
|
||
|
static float maxvol = 0;
|
||
|
maxvol = max(1.0f, maxvol * (1.0f - nbframes / (0.4f * snd_renderbuffer->format.speed)));
|
||
|
#define SOFTCLIP(x) if(fabs(x)>maxvol) maxvol=fabs(x); (x) /= maxvol;
|
||
|
|
||
|
if (channels == 8) // 7.1 surround
|
||
|
{
|
||
|
for (i = 0;i < nbframes;i++, p++)
|
||
|
{
|
||
|
SOFTCLIP(p->sample[0]);
|
||
|
SOFTCLIP(p->sample[1]);
|
||
|
SOFTCLIP(p->sample[2]);
|
||
|
SOFTCLIP(p->sample[3]);
|
||
|
SOFTCLIP(p->sample[4]);
|
||
|
SOFTCLIP(p->sample[5]);
|
||
|
SOFTCLIP(p->sample[6]);
|
||
|
SOFTCLIP(p->sample[7]);
|
||
|
}
|
||
|
}
|
||
|
else if (channels == 6) // 5.1 surround
|
||
|
{
|
||
|
for (i = 0; i < nbframes; i++, p++)
|
||
|
{
|
||
|
SOFTCLIP(p->sample[0]);
|
||
|
SOFTCLIP(p->sample[1]);
|
||
|
SOFTCLIP(p->sample[2]);
|
||
|
SOFTCLIP(p->sample[3]);
|
||
|
SOFTCLIP(p->sample[4]);
|
||
|
SOFTCLIP(p->sample[5]);
|
||
|
}
|
||
|
}
|
||
|
else if (channels == 4) // 4.0 surround
|
||
|
{
|
||
|
for (i = 0; i < nbframes; i++, p++)
|
||
|
{
|
||
|
SOFTCLIP(p->sample[0]);
|
||
|
SOFTCLIP(p->sample[1]);
|
||
|
SOFTCLIP(p->sample[2]);
|
||
|
SOFTCLIP(p->sample[3]);
|
||
|
}
|
||
|
}
|
||
|
else if (channels == 2) // 2.0 stereo
|
||
|
{
|
||
|
for (i = 0; i < nbframes; i++, p++)
|
||
|
{
|
||
|
SOFTCLIP(p->sample[0]);
|
||
|
SOFTCLIP(p->sample[1]);
|
||
|
}
|
||
|
}
|
||
|
else if (channels == 1) // 1.0 mono
|
||
|
{
|
||
|
for (i = 0; i < nbframes; i++, p++)
|
||
|
{
|
||
|
SOFTCLIP(p->sample[0]);
|
||
|
}
|
||
|
}
|
||
|
#undef SOFTCLIP
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void S_ConvertPaintBuffer(portable_sampleframe_t *painted_ptr, void *rb_ptr, int nbframes, int width, int channels)
|
||
|
{
|
||
|
int i, val;
|
||
|
|
||
|
// FIXME: add 24bit and 32bit float formats
|
||
|
// FIXME: optimize with SSE intrinsics?
|
||
|
if (width == 2) // 16bit
|
||
|
{
|
||
|
short *snd_out = (short*)rb_ptr;
|
||
|
if (channels == 8) // 7.1 surround
|
||
|
{
|
||
|
for (i = 0;i < nbframes;i++, painted_ptr++)
|
||
|
{
|
||
|
val = (int)(painted_ptr->sample[0] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
|
||
|
val = (int)(painted_ptr->sample[1] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
|
||
|
val = (int)(painted_ptr->sample[2] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
|
||
|
val = (int)(painted_ptr->sample[3] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
|
||
|
val = (int)(painted_ptr->sample[4] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
|
||
|
val = (int)(painted_ptr->sample[5] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
|
||
|
val = (int)(painted_ptr->sample[6] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
|
||
|
val = (int)(painted_ptr->sample[7] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
|
||
|
}
|
||
|
}
|
||
|
else if (channels == 6) // 5.1 surround
|
||
|
{
|
||
|
for (i = 0; i < nbframes; i++, painted_ptr++)
|
||
|
{
|
||
|
val = (int)(painted_ptr->sample[0] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
|
||
|
val = (int)(painted_ptr->sample[1] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
|
||
|
val = (int)(painted_ptr->sample[2] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
|
||
|
val = (int)(painted_ptr->sample[3] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
|
||
|
val = (int)(painted_ptr->sample[4] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
|
||
|
val = (int)(painted_ptr->sample[5] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
|
||
|
}
|
||
|
}
|
||
|
else if (channels == 4) // 4.0 surround
|
||
|
{
|
||
|
for (i = 0; i < nbframes; i++, painted_ptr++)
|
||
|
{
|
||
|
val = (int)(painted_ptr->sample[0] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
|
||
|
val = (int)(painted_ptr->sample[1] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
|
||
|
val = (int)(painted_ptr->sample[2] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
|
||
|
val = (int)(painted_ptr->sample[3] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
|
||
|
}
|
||
|
}
|
||
|
else if (channels == 2) // 2.0 stereo
|
||
|
{
|
||
|
for (i = 0; i < nbframes; i++, painted_ptr++)
|
||
|
{
|
||
|
val = (int)(painted_ptr->sample[0] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
|
||
|
val = (int)(painted_ptr->sample[1] * 32768.0f);*snd_out++ = bound(-32768, val, 32767);
|
||
|
}
|
||
|
}
|
||
|
else if (channels == 1) // 1.0 mono
|
||
|
{
|
||
|
for (i = 0; i < nbframes; i++, painted_ptr++)
|
||
|
{
|
||
|
val = (int)((painted_ptr->sample[0] + painted_ptr->sample[1]) * 16384.0f);*snd_out++ = bound(-32768, val, 32767);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// noise is really really annoying
|
||
|
if (cls.timedemo)
|
||
|
memset(rb_ptr, 0, nbframes * channels * width);
|
||
|
}
|
||
|
else // 8bit
|
||
|
{
|
||
|
unsigned char *snd_out = (unsigned char*)rb_ptr;
|
||
|
if (channels == 8) // 7.1 surround
|
||
|
{
|
||
|
for (i = 0; i < nbframes; i++, painted_ptr++)
|
||
|
{
|
||
|
val = (int)(painted_ptr->sample[0] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
|
||
|
val = (int)(painted_ptr->sample[1] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
|
||
|
val = (int)(painted_ptr->sample[2] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
|
||
|
val = (int)(painted_ptr->sample[3] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
|
||
|
val = (int)(painted_ptr->sample[4] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
|
||
|
val = (int)(painted_ptr->sample[5] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
|
||
|
val = (int)(painted_ptr->sample[6] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
|
||
|
val = (int)(painted_ptr->sample[7] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
|
||
|
}
|
||
|
}
|
||
|
else if (channels == 6) // 5.1 surround
|
||
|
{
|
||
|
for (i = 0; i < nbframes; i++, painted_ptr++)
|
||
|
{
|
||
|
val = (int)(painted_ptr->sample[0] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
|
||
|
val = (int)(painted_ptr->sample[1] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
|
||
|
val = (int)(painted_ptr->sample[2] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
|
||
|
val = (int)(painted_ptr->sample[3] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
|
||
|
val = (int)(painted_ptr->sample[4] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
|
||
|
val = (int)(painted_ptr->sample[5] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
|
||
|
}
|
||
|
}
|
||
|
else if (channels == 4) // 4.0 surround
|
||
|
{
|
||
|
for (i = 0; i < nbframes; i++, painted_ptr++)
|
||
|
{
|
||
|
val = (int)(painted_ptr->sample[0] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
|
||
|
val = (int)(painted_ptr->sample[1] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
|
||
|
val = (int)(painted_ptr->sample[2] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
|
||
|
val = (int)(painted_ptr->sample[3] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
|
||
|
}
|
||
|
}
|
||
|
else if (channels == 2) // 2.0 stereo
|
||
|
{
|
||
|
for (i = 0; i < nbframes; i++, painted_ptr++)
|
||
|
{
|
||
|
val = (int)(painted_ptr->sample[0] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
|
||
|
val = (int)(painted_ptr->sample[1] * 128.0f) + 128; *snd_out++ = bound(0, val, 255);
|
||
|
}
|
||
|
}
|
||
|
else if (channels == 1) // 1.0 mono
|
||
|
{
|
||
|
for (i = 0;i < nbframes;i++, painted_ptr++)
|
||
|
{
|
||
|
val = (int)((painted_ptr->sample[0] + painted_ptr->sample[1]) * 64.0f) + 128; *snd_out++ = bound(0, val, 255);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// noise is really really annoying
|
||
|
if (cls.timedemo)
|
||
|
memset(rb_ptr, 128, nbframes * channels);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
===============================================================================
|
||
|
|
||
|
CHANNEL MIXING
|
||
|
|
||
|
===============================================================================
|
||
|
*/
|
||
|
|
||
|
void S_MixToBuffer(void *stream, unsigned int bufferframes)
|
||
|
{
|
||
|
int channelindex;
|
||
|
channel_t *ch;
|
||
|
int totalmixframes;
|
||
|
unsigned char *outbytes = (unsigned char *) stream;
|
||
|
sfx_t *sfx;
|
||
|
portable_sampleframe_t *paint;
|
||
|
int wantframes;
|
||
|
int i;
|
||
|
int count;
|
||
|
int fetched;
|
||
|
int fetch;
|
||
|
int istartframe;
|
||
|
int iendframe;
|
||
|
int ilengthframes;
|
||
|
int totallength;
|
||
|
int loopstart;
|
||
|
int indexfrac;
|
||
|
int indexfracstep;
|
||
|
#define S_FETCHBUFFERSIZE 4096
|
||
|
float fetchsampleframes[S_FETCHBUFFERSIZE*2];
|
||
|
const float *fetchsampleframe;
|
||
|
float vol[SND_LISTENERS];
|
||
|
float lerp[2];
|
||
|
float sample[3];
|
||
|
double posd;
|
||
|
double speedd;
|
||
|
float maxvol;
|
||
|
qboolean looping;
|
||
|
qboolean silent;
|
||
|
|
||
|
// mix as many times as needed to fill the requested buffer
|
||
|
while (bufferframes)
|
||
|
{
|
||
|
// limit to the size of the paint buffer
|
||
|
totalmixframes = min(bufferframes, PAINTBUFFER_SIZE);
|
||
|
|
||
|
// clear the paint buffer
|
||
|
memset(paintbuffer, 0, totalmixframes * sizeof(paintbuffer[0]));
|
||
|
|
||
|
// paint in the channels.
|
||
|
// channels with zero volumes still advance in time but don't paint.
|
||
|
ch = channels; // cppcheck complains here but it is wrong, channels is a channel_t[MAX_CHANNELS] and not an int
|
||
|
for (channelindex = 0;channelindex < (int)total_channels;channelindex++, ch++)
|
||
|
{
|
||
|
sfx = ch->sfx;
|
||
|
if (sfx == NULL)
|
||
|
continue;
|
||
|
if (!S_LoadSound (sfx, true))
|
||
|
continue;
|
||
|
if (ch->flags & CHANNELFLAG_PAUSED)
|
||
|
continue;
|
||
|
if (!sfx->total_length)
|
||
|
continue;
|
||
|
|
||
|
// copy the channel information to the stack for reference, otherwise the
|
||
|
// values might change during a mix if the spatializer is updating them
|
||
|
// (note: this still may get some old and some new values!)
|
||
|
posd = ch->position;
|
||
|
speedd = ch->mixspeed * sfx->format.speed / snd_renderbuffer->format.speed;
|
||
|
for (i = 0;i < SND_LISTENERS;i++)
|
||
|
vol[i] = ch->volume[i];
|
||
|
|
||
|
// check total volume level, because we can skip some code on silent sounds but other code must still run (position updates mainly)
|
||
|
maxvol = 0;
|
||
|
for (i = 0;i < SND_LISTENERS;i++)
|
||
|
if(vol[i] > maxvol)
|
||
|
maxvol = vol[i];
|
||
|
switch(snd_renderbuffer->format.width)
|
||
|
{
|
||
|
case 1: // 8bpp
|
||
|
silent = maxvol < (1.0f / (256.0f));
|
||
|
// so silent it has zero effect
|
||
|
break;
|
||
|
case 2: // 16bpp
|
||
|
silent = maxvol < (1.0f / (65536.0f));
|
||
|
// so silent it has zero effect
|
||
|
break;
|
||
|
default: // floating point
|
||
|
silent = maxvol < 1.0e-13f;
|
||
|
// 130 dB is difference between hearing
|
||
|
// threshold and a jackhammer from
|
||
|
// working distance.
|
||
|
// therefore, anyone who turns up
|
||
|
// volume so much they notice this
|
||
|
// cutoff, likely already has their
|
||
|
// ear-drums blown out anyway.
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// when doing prologic mixing, some channels invert one side
|
||
|
if (ch->prologic_invert == -1)
|
||
|
vol[1] *= -1.0f;
|
||
|
|
||
|
// get some sfx info in a consistent form
|
||
|
totallength = sfx->total_length;
|
||
|
loopstart = (int)sfx->loopstart < totallength ? (int)sfx->loopstart : ((ch->flags & CHANNELFLAG_FORCELOOP) ? 0 : totallength);
|
||
|
looping = loopstart < totallength;
|
||
|
|
||
|
// do the actual paint now (may skip work if silent)
|
||
|
paint = paintbuffer;
|
||
|
istartframe = 0;
|
||
|
for (wantframes = totalmixframes;wantframes > 0;posd += count * speedd, wantframes -= count)
|
||
|
{
|
||
|
// check if this is a delayed sound
|
||
|
if (posd < 0)
|
||
|
{
|
||
|
// for a delayed sound we have to eat into the delay first
|
||
|
count = (int)floor(-posd / speedd) + 1;
|
||
|
count = bound(1, count, wantframes);
|
||
|
// let the for loop iterator apply the skip
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// compute a fetch size that won't overflow our buffer
|
||
|
count = wantframes;
|
||
|
for (;;)
|
||
|
{
|
||
|
istartframe = (int)floor(posd);
|
||
|
iendframe = (int)floor(posd + (count-1) * speedd);
|
||
|
ilengthframes = count > 1 ? (iendframe - istartframe + 2) : 2;
|
||
|
if (ilengthframes <= S_FETCHBUFFERSIZE)
|
||
|
break;
|
||
|
// reduce count by 25% and try again
|
||
|
count -= count >> 2;
|
||
|
}
|
||
|
|
||
|
// zero whole fetch buffer for safety
|
||
|
// (floating point noise from uninitialized memory = HORRIBLE)
|
||
|
// otherwise we would only need to clear the excess
|
||
|
if (!silent)
|
||
|
memset(fetchsampleframes, 0, ilengthframes*sfx->format.channels*sizeof(fetchsampleframes[0]));
|
||
|
|
||
|
// if looping, do multiple fetches
|
||
|
fetched = 0;
|
||
|
for (;;)
|
||
|
{
|
||
|
fetch = min(ilengthframes - fetched, totallength - istartframe);
|
||
|
if (fetch > 0)
|
||
|
{
|
||
|
if (!silent)
|
||
|
sfx->fetcher->getsamplesfloat(ch, sfx, istartframe, fetch, fetchsampleframes + fetched*sfx->format.channels);
|
||
|
istartframe += fetch;
|
||
|
fetched += fetch;
|
||
|
}
|
||
|
if (istartframe == totallength && looping && fetched < ilengthframes)
|
||
|
{
|
||
|
// loop and fetch some more
|
||
|
posd += loopstart - totallength;
|
||
|
istartframe = loopstart;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// set up our fixedpoint resampling variables (float to int conversions are expensive so do not do one per sampleframe)
|
||
|
fetchsampleframe = fetchsampleframes;
|
||
|
indexfrac = (int)floor((posd - floor(posd)) * 65536.0);
|
||
|
indexfracstep = (int)floor(speedd * 65536.0);
|
||
|
if (!silent)
|
||
|
{
|
||
|
if (sfx->format.channels == 2)
|
||
|
{
|
||
|
// music is stereo
|
||
|
#if SND_LISTENERS != 8
|
||
|
#error the following code only supports up to 8 channels, update it
|
||
|
#endif
|
||
|
if (snd_speakerlayout.channels > 2)
|
||
|
{
|
||
|
// surround mixing
|
||
|
for (i = 0;i < count;i++, paint++)
|
||
|
{
|
||
|
lerp[1] = indexfrac * (1.0f / 65536.0f);
|
||
|
lerp[0] = 1.0f - lerp[1];
|
||
|
sample[0] = fetchsampleframe[0] * lerp[0] + fetchsampleframe[2] * lerp[1];
|
||
|
sample[1] = fetchsampleframe[1] * lerp[0] + fetchsampleframe[3] * lerp[1];
|
||
|
sample[2] = (sample[0] + sample[1]) * 0.5f;
|
||
|
paint->sample[0] += sample[0] * vol[0];
|
||
|
paint->sample[1] += sample[1] * vol[1];
|
||
|
paint->sample[2] += sample[0] * vol[2];
|
||
|
paint->sample[3] += sample[1] * vol[3];
|
||
|
paint->sample[4] += sample[2] * vol[4];
|
||
|
paint->sample[5] += sample[2] * vol[5];
|
||
|
paint->sample[6] += sample[0] * vol[6];
|
||
|
paint->sample[7] += sample[1] * vol[7];
|
||
|
indexfrac += indexfracstep;
|
||
|
fetchsampleframe += 2 * (indexfrac >> 16);
|
||
|
indexfrac &= 0xFFFF;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// stereo mixing
|
||
|
for (i = 0;i < count;i++, paint++)
|
||
|
{
|
||
|
lerp[1] = indexfrac * (1.0f / 65536.0f);
|
||
|
lerp[0] = 1.0f - lerp[1];
|
||
|
sample[0] = fetchsampleframe[0] * lerp[0] + fetchsampleframe[2] * lerp[1];
|
||
|
sample[1] = fetchsampleframe[1] * lerp[0] + fetchsampleframe[3] * lerp[1];
|
||
|
paint->sample[0] += sample[0] * vol[0];
|
||
|
paint->sample[1] += sample[1] * vol[1];
|
||
|
indexfrac += indexfracstep;
|
||
|
fetchsampleframe += 2 * (indexfrac >> 16);
|
||
|
indexfrac &= 0xFFFF;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (sfx->format.channels == 1)
|
||
|
{
|
||
|
// most sounds are mono
|
||
|
#if SND_LISTENERS != 8
|
||
|
#error the following code only supports up to 8 channels, update it
|
||
|
#endif
|
||
|
if (snd_speakerlayout.channels > 2)
|
||
|
{
|
||
|
// surround mixing
|
||
|
for (i = 0;i < count;i++, paint++)
|
||
|
{
|
||
|
lerp[1] = indexfrac * (1.0f / 65536.0f);
|
||
|
lerp[0] = 1.0f - lerp[1];
|
||
|
sample[0] = fetchsampleframe[0] * lerp[0] + fetchsampleframe[1] * lerp[1];
|
||
|
paint->sample[0] += sample[0] * vol[0];
|
||
|
paint->sample[1] += sample[0] * vol[1];
|
||
|
paint->sample[2] += sample[0] * vol[2];
|
||
|
paint->sample[3] += sample[0] * vol[3];
|
||
|
paint->sample[4] += sample[0] * vol[4];
|
||
|
paint->sample[5] += sample[0] * vol[5];
|
||
|
paint->sample[6] += sample[0] * vol[6];
|
||
|
paint->sample[7] += sample[0] * vol[7];
|
||
|
indexfrac += indexfracstep;
|
||
|
fetchsampleframe += (indexfrac >> 16);
|
||
|
indexfrac &= 0xFFFF;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// stereo mixing
|
||
|
for (i = 0;i < count;i++, paint++)
|
||
|
{
|
||
|
lerp[1] = indexfrac * (1.0f / 65536.0f);
|
||
|
lerp[0] = 1.0f - lerp[1];
|
||
|
sample[0] = fetchsampleframe[0] * lerp[0] + fetchsampleframe[1] * lerp[1];
|
||
|
paint->sample[0] += sample[0] * vol[0];
|
||
|
paint->sample[1] += sample[0] * vol[1];
|
||
|
indexfrac += indexfracstep;
|
||
|
fetchsampleframe += (indexfrac >> 16);
|
||
|
indexfrac &= 0xFFFF;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
ch->position = posd;
|
||
|
if (!looping && istartframe == totallength)
|
||
|
S_StopChannel(ch - channels, false, false);
|
||
|
}
|
||
|
|
||
|
S_SoftClipPaintBuffer(paintbuffer, totalmixframes, snd_renderbuffer->format.width, snd_renderbuffer->format.channels);
|
||
|
|
||
|
if (!snd_usethreadedmixing)
|
||
|
S_CaptureAVISound(paintbuffer, totalmixframes);
|
||
|
|
||
|
S_ConvertPaintBuffer(paintbuffer, outbytes, totalmixframes, snd_renderbuffer->format.width, snd_renderbuffer->format.channels);
|
||
|
|
||
|
// advance the output pointer
|
||
|
outbytes += totalmixframes * snd_renderbuffer->format.width * snd_renderbuffer->format.channels;
|
||
|
bufferframes -= totalmixframes;
|
||
|
}
|
||
|
}
|