mirror of
https://github.com/Q3Rally-Team/rallyunlimited-engine.git
synced 2024-11-26 06:01:34 +00:00
801 lines
18 KiB
C
801 lines
18 KiB
C
/*
|
|
===========================================================================
|
|
Copyright (C) 1999-2005 Id Software, Inc.
|
|
|
|
This file is part of Quake III Arena source code.
|
|
|
|
Quake III Arena source code 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.
|
|
|
|
Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
===========================================================================
|
|
*/
|
|
// snd_mix.c -- portable code to mix sounds for snd_dma.c
|
|
|
|
#include "client.h"
|
|
#include "snd_local.h"
|
|
|
|
static portable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];
|
|
static int snd_vol;
|
|
|
|
// bk001119 - these not static, required by unix/snd_mixa.s
|
|
int *snd_p;
|
|
int snd_linear_count;
|
|
short *snd_out;
|
|
|
|
void S_WriteLinearBlastStereo16( void )
|
|
{
|
|
int i;
|
|
int val;
|
|
int *src = snd_p;
|
|
short *dst = snd_out;
|
|
for ( i = 0; i < snd_linear_count; i++, src++, dst++ )
|
|
{
|
|
val = *src>>8;
|
|
if ( val > 32767 )
|
|
*dst = 32767;
|
|
else if ( val < -32768 )
|
|
*dst = -32768;
|
|
else
|
|
*dst = val;
|
|
}
|
|
}
|
|
|
|
#if id386 && defined (_MSC_VER)
|
|
|
|
void S_WriteLinearBlastStereo16_MMX( void );
|
|
void S_WriteLinearBlastStereo16_SSE( void );
|
|
|
|
#ifdef _WIN32
|
|
|
|
void S_WriteLinearBlastStereo16_MMX( void )
|
|
{
|
|
__asm {
|
|
push ebx
|
|
push esi
|
|
push edi
|
|
mov esi,snd_p
|
|
mov edi,snd_out
|
|
mov ebx,snd_linear_count
|
|
test ebx,ebx
|
|
jz LExit
|
|
mov ecx,esi
|
|
and ecx,63
|
|
jz LMain
|
|
and ecx,3
|
|
jnz LTail
|
|
shr ecx,2
|
|
not ecx
|
|
add ecx,17
|
|
LClamp1:
|
|
mov eax,[esi]
|
|
sar eax,8
|
|
cmp eax,32767
|
|
jg LClampHigh1
|
|
cmp eax,-32768
|
|
jnl LClampDone1
|
|
mov eax,-32768
|
|
jmp LClampDone1
|
|
LClampHigh1:
|
|
mov eax,32767
|
|
LClampDone1:
|
|
mov [edi],ax
|
|
add esi,4
|
|
add edi,2
|
|
dec ebx
|
|
jz LExit
|
|
dec ecx
|
|
jnz LClamp1
|
|
LMain:
|
|
mov ecx,ebx
|
|
shr ecx,4
|
|
jz LTail
|
|
and ebx,15
|
|
LAgain:
|
|
movq mm0, qword ptr [esi+ 0]
|
|
movq mm1, qword ptr [esi+ 8]
|
|
movq mm2, qword ptr [esi+16]
|
|
movq mm3, qword ptr [esi+24]
|
|
movq mm4, qword ptr [esi+32]
|
|
movq mm5, qword ptr [esi+40]
|
|
movq mm6, qword ptr [esi+48]
|
|
movq mm7, qword ptr [esi+56]
|
|
psrad mm0,8
|
|
psrad mm1,8
|
|
psrad mm2,8
|
|
psrad mm3,8
|
|
psrad mm4,8
|
|
psrad mm5,8
|
|
psrad mm6,8
|
|
psrad mm7,8
|
|
packssdw mm0, mm1
|
|
packssdw mm2, mm3
|
|
packssdw mm4, mm5
|
|
packssdw mm6, mm7
|
|
movq qword ptr [edi+ 0], mm0
|
|
movq qword ptr [edi+ 8], mm2
|
|
movq qword ptr [edi+16], mm4
|
|
movq qword ptr [edi+24], mm6
|
|
add esi, 64
|
|
add edi, 32
|
|
dec ecx
|
|
jnz LAgain
|
|
LTail:
|
|
test ebx, ebx
|
|
jz LEnd
|
|
LClamp2:
|
|
mov eax,[esi]
|
|
sar eax,8
|
|
cmp eax,32767
|
|
jg LClampHigh2
|
|
cmp eax,-32768
|
|
jnl LClampDone2
|
|
mov eax,-32768
|
|
jmp LClampDone2
|
|
LClampHigh2:
|
|
mov eax,32767
|
|
LClampDone2:
|
|
mov [edi],ax
|
|
add esi,4
|
|
add edi,2
|
|
dec ebx
|
|
jnz LClamp2
|
|
LEnd:
|
|
emms
|
|
LExit:
|
|
pop edi
|
|
pop esi
|
|
pop ebx
|
|
} // __asm
|
|
}
|
|
|
|
|
|
void S_WriteLinearBlastStereo16_SSE( void )
|
|
{
|
|
__asm {
|
|
push ebx
|
|
push esi
|
|
push edi
|
|
mov esi,snd_p
|
|
mov edi,snd_out
|
|
mov ebx,snd_linear_count
|
|
test ebx,ebx
|
|
jz LExit
|
|
mov ecx,esi
|
|
and ecx,63
|
|
jz LMain
|
|
and ecx,3
|
|
jnz LTail
|
|
shr ecx,2
|
|
not ecx
|
|
add ecx,17
|
|
LClamp1:
|
|
mov eax,[esi]
|
|
sar eax,8
|
|
cmp eax,32767
|
|
jg LClampHigh1
|
|
cmp eax,-32768
|
|
jnl LClampDone1
|
|
mov eax,-32768
|
|
jmp LClampDone1
|
|
LClampHigh1:
|
|
mov eax,32767
|
|
LClampDone1:
|
|
mov [edi],ax
|
|
add esi,4
|
|
add edi,2
|
|
dec ebx
|
|
jz LExit
|
|
dec ecx
|
|
jnz LClamp1
|
|
LMain:
|
|
mov ecx,ebx
|
|
shr ecx,4
|
|
jz LTail
|
|
and ebx,15
|
|
LAgain:
|
|
movq mm0, qword ptr [esi+ 0]
|
|
movq mm1, qword ptr [esi+ 8]
|
|
movq mm2, qword ptr [esi+16]
|
|
movq mm3, qword ptr [esi+24]
|
|
movq mm4, qword ptr [esi+32]
|
|
movq mm5, qword ptr [esi+40]
|
|
movq mm6, qword ptr [esi+48]
|
|
movq mm7, qword ptr [esi+56]
|
|
psrad mm0,8
|
|
psrad mm1,8
|
|
psrad mm2,8
|
|
psrad mm3,8
|
|
psrad mm4,8
|
|
psrad mm5,8
|
|
psrad mm6,8
|
|
psrad mm7,8
|
|
packssdw mm0, mm1
|
|
packssdw mm2, mm3
|
|
packssdw mm4, mm5
|
|
packssdw mm6, mm7
|
|
movntq qword ptr [edi+ 0], mm0
|
|
movntq qword ptr [edi+ 8], mm2
|
|
movntq qword ptr [edi+16], mm4
|
|
movntq qword ptr [edi+24], mm6
|
|
add esi, 64
|
|
add edi, 32
|
|
dec ecx
|
|
jnz LAgain
|
|
LTail:
|
|
test ebx, ebx
|
|
jz LEnd
|
|
LClamp2:
|
|
mov eax,[esi]
|
|
sar eax,8
|
|
cmp eax,32767
|
|
jg LClampHigh2
|
|
cmp eax,-32768
|
|
jnl LClampDone2
|
|
mov eax,-32768
|
|
jmp LClampDone2
|
|
LClampHigh2:
|
|
mov eax,32767
|
|
LClampDone2:
|
|
mov [edi],ax
|
|
add esi,4
|
|
add edi,2
|
|
dec ebx
|
|
jnz LClamp2
|
|
LEnd:
|
|
sfence
|
|
emms
|
|
LExit:
|
|
pop edi
|
|
pop esi
|
|
pop ebx
|
|
} // __asm
|
|
}
|
|
|
|
#endif // _WIN32
|
|
|
|
#endif // id386
|
|
|
|
#if idx64 && defined (_MSC_VER) && defined(USE_WIN32_ASM)
|
|
void S_WriteLinearBlastStereo16_SSE_x64( int*, short*, int );
|
|
#endif
|
|
|
|
void S_TransferStereo16( unsigned long *pbuf, int endtime )
|
|
{
|
|
int lpos;
|
|
int ls_paintedtime;
|
|
|
|
snd_p = (int *) paintbuffer;
|
|
ls_paintedtime = s_paintedtime;
|
|
|
|
while (ls_paintedtime < endtime)
|
|
{
|
|
// handle recirculating buffer issues
|
|
lpos = ls_paintedtime & ((dma.samples>>1)-1);
|
|
|
|
snd_out = (short *) pbuf + (lpos<<1);
|
|
|
|
snd_linear_count = (dma.samples>>1) - lpos;
|
|
if (ls_paintedtime + snd_linear_count > endtime)
|
|
snd_linear_count = endtime - ls_paintedtime;
|
|
|
|
snd_linear_count <<= 1;
|
|
|
|
// write a linear blast of samples
|
|
#if id386 && defined (_MSC_VER) && defined (USE_WIN32_ASM)
|
|
if ( CPU_Flags & CPU_SSE )
|
|
S_WriteLinearBlastStereo16_SSE();
|
|
else
|
|
if ( CPU_Flags & CPU_MMX )
|
|
S_WriteLinearBlastStereo16_MMX();
|
|
else
|
|
#endif
|
|
#if idx64 && defined (_MSC_VER) && defined (USE_WIN32_ASM)
|
|
S_WriteLinearBlastStereo16_SSE_x64( snd_p, snd_out, snd_linear_count );
|
|
#else
|
|
S_WriteLinearBlastStereo16();
|
|
#endif
|
|
snd_p += snd_linear_count;
|
|
ls_paintedtime += (snd_linear_count>>1);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===================
|
|
S_TransferPaintBuffer
|
|
|
|
===================
|
|
*/
|
|
static void S_TransferPaintBuffer( int endtime, byte *buffer )
|
|
{
|
|
int out_idx;
|
|
int i, count;
|
|
int out_mask;
|
|
int *p;
|
|
int step;
|
|
int val;
|
|
unsigned long *pbuf;
|
|
|
|
pbuf = (unsigned long *)buffer;
|
|
|
|
if ( s_testsound->integer ) {
|
|
// write a fixed sine wave
|
|
count = (endtime - s_paintedtime);
|
|
for (i=0 ; i<count ; i++)
|
|
paintbuffer[i].left = paintbuffer[i].right = sin((s_paintedtime+i)*0.1)*20000*256;
|
|
}
|
|
|
|
if ( dma.samplebits == 16 && dma.channels == 2 )
|
|
{ // optimized case
|
|
S_TransferStereo16( pbuf, endtime );
|
|
}
|
|
else
|
|
{ // general case
|
|
p = (int *) paintbuffer;
|
|
count = (endtime - s_paintedtime) * dma.channels;
|
|
out_mask = dma.samples - 1;
|
|
out_idx = ( s_paintedtime * dma.channels ) & out_mask;
|
|
step = 3 - dma.channels;
|
|
|
|
if ( dma.samplebits == 32 && dma.isfloat )
|
|
{
|
|
const float rdiv = 1.0f / (32768.0f * 256.0f - 128.0f); // 8388480.0f
|
|
float *out = (float *) pbuf;
|
|
while ( count-- > 0 )
|
|
{
|
|
val = *p;
|
|
p += step;
|
|
if (val > 0x7fff00) {
|
|
val = 0x7fff00;
|
|
} else if (val < -32768 * 256) {
|
|
val = -32768 * 256;
|
|
}
|
|
out[out_idx] = (float)(val + 128) * rdiv;
|
|
out_idx = (out_idx + 1) & out_mask;
|
|
}
|
|
}
|
|
else if (dma.samplebits == 16)
|
|
{
|
|
short *out = (short *) pbuf;
|
|
while ( count-- > 0 )
|
|
{
|
|
val = *p >> 8;
|
|
p += step;
|
|
if (val > 0x7fff)
|
|
val = 0x7fff;
|
|
else if (val < -32768)
|
|
val = -32768;
|
|
out[out_idx] = val;
|
|
out_idx = (out_idx + 1) & out_mask;
|
|
}
|
|
}
|
|
else if (dma.samplebits == 8)
|
|
{
|
|
unsigned char *out = (unsigned char *) pbuf;
|
|
while ( count-- > 0 )
|
|
{
|
|
val = *p >> 8;
|
|
p += step;
|
|
if (val > 0x7fff)
|
|
val = 0x7fff;
|
|
else if (val < -32768)
|
|
val = -32768;
|
|
out[out_idx] = (val>>8) + 128;
|
|
out_idx = (out_idx + 1) & out_mask;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( CL_VideoRecording() ) {
|
|
//count = (endtime - s_paintedtime) * dma.channels;
|
|
count = (clc.aviFrameEndTime - s_paintedtime) * dma.channels;
|
|
out_idx = ( s_paintedtime * dma.channels ) % dma.samples;
|
|
while ( count > 0 ) {
|
|
int n = count;
|
|
if ( n + out_idx > dma.samples )
|
|
n = dma.samples - out_idx;
|
|
CL_WriteAVIAudioFrame( buffer + out_idx * dma.samplebits / 8, n * dma.samplebits / 8 );
|
|
out_idx = (out_idx + n) % dma.samples;
|
|
count -= n;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
CHANNEL MIXING
|
|
|
|
===============================================================================
|
|
*/
|
|
static void S_PaintChannelFrom16_scalar( channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
|
|
int data, aoff, boff;
|
|
int leftvol, rightvol;
|
|
int i, j;
|
|
portable_samplepair_t *samp;
|
|
sndBuffer *chunk;
|
|
short *samples;
|
|
float ooff, fdata[2], fdiv, fleftvol, frightvol;
|
|
|
|
if (sc->soundChannels <= 0) {
|
|
return;
|
|
}
|
|
|
|
samp = &paintbuffer[ bufferOffset ];
|
|
|
|
if (ch->doppler) {
|
|
sampleOffset = sampleOffset*ch->oldDopplerScale;
|
|
}
|
|
|
|
if ( sc->soundChannels == 2 ) {
|
|
sampleOffset *= sc->soundChannels;
|
|
|
|
if ( sampleOffset & 1 ) {
|
|
sampleOffset &= ~1;
|
|
}
|
|
}
|
|
|
|
chunk = sc->soundData;
|
|
while (sampleOffset>=SND_CHUNK_SIZE) {
|
|
chunk = chunk->next;
|
|
sampleOffset -= SND_CHUNK_SIZE;
|
|
if (!chunk) {
|
|
chunk = sc->soundData;
|
|
}
|
|
}
|
|
|
|
if (!ch->doppler || ch->dopplerScale==1.0f) {
|
|
leftvol = ch->leftvol*snd_vol;
|
|
rightvol = ch->rightvol*snd_vol;
|
|
samples = chunk->sndChunk;
|
|
for ( i=0 ; i<count ; i++ ) {
|
|
data = samples[sampleOffset++];
|
|
samp[i].left += (data * leftvol)>>8;
|
|
|
|
if ( sc->soundChannels == 2 ) {
|
|
data = samples[sampleOffset++];
|
|
}
|
|
samp[i].right += (data * rightvol)>>8;
|
|
|
|
if (sampleOffset == SND_CHUNK_SIZE) {
|
|
chunk = chunk->next;
|
|
if (!chunk) {
|
|
chunk = sc->soundData;
|
|
}
|
|
samples = chunk->sndChunk;
|
|
sampleOffset = 0;
|
|
}
|
|
}
|
|
} else {
|
|
fleftvol = ch->leftvol*snd_vol;
|
|
frightvol = ch->rightvol*snd_vol;
|
|
|
|
ooff = sampleOffset;
|
|
samples = chunk->sndChunk;
|
|
|
|
for ( i=0 ; i<count ; i++ ) {
|
|
|
|
aoff = ooff;
|
|
ooff = ooff + ch->dopplerScale * sc->soundChannels;
|
|
boff = ooff;
|
|
fdata[0] = fdata[1] = 0;
|
|
for (j=aoff; j<boff; j += sc->soundChannels) {
|
|
if (j == SND_CHUNK_SIZE) {
|
|
chunk = chunk->next;
|
|
if (!chunk) {
|
|
chunk = sc->soundData;
|
|
}
|
|
samples = chunk->sndChunk;
|
|
ooff -= SND_CHUNK_SIZE;
|
|
}
|
|
if ( sc->soundChannels == 2 ) {
|
|
fdata[0] += samples[j&(SND_CHUNK_SIZE-1)];
|
|
fdata[1] += samples[(j+1)&(SND_CHUNK_SIZE-1)];
|
|
} else {
|
|
fdata[0] += samples[j&(SND_CHUNK_SIZE-1)];
|
|
fdata[1] += samples[j&(SND_CHUNK_SIZE-1)];
|
|
}
|
|
}
|
|
fdiv = 256 * (boff-aoff) / sc->soundChannels;
|
|
samp[i].left += (fdata[0] * fleftvol)/fdiv;
|
|
samp[i].right += (fdata[1] * frightvol)/fdiv;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void S_PaintChannelFrom16( channel_t *ch, const sfx_t *sc, int count, int sampleOffset, int bufferOffset )
|
|
{
|
|
S_PaintChannelFrom16_scalar( ch, sc, count, sampleOffset, bufferOffset );
|
|
}
|
|
|
|
|
|
static void S_PaintChannelFromWavelet( channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
|
|
int data;
|
|
int leftvol, rightvol;
|
|
int i;
|
|
portable_samplepair_t *samp;
|
|
sndBuffer *chunk;
|
|
short *samples;
|
|
|
|
leftvol = ch->leftvol*snd_vol;
|
|
rightvol = ch->rightvol*snd_vol;
|
|
|
|
i = 0;
|
|
samp = &paintbuffer[ bufferOffset ];
|
|
chunk = sc->soundData;
|
|
while (sampleOffset>=(SND_CHUNK_SIZE_FLOAT*4)) {
|
|
chunk = chunk->next;
|
|
sampleOffset -= (SND_CHUNK_SIZE_FLOAT*4);
|
|
i++;
|
|
}
|
|
|
|
if (i!=sfxScratchIndex || sfxScratchPointer != sc) {
|
|
S_AdpcmGetSamples( chunk, sfxScratchBuffer );
|
|
sfxScratchIndex = i;
|
|
sfxScratchPointer = sc;
|
|
}
|
|
|
|
samples = sfxScratchBuffer;
|
|
|
|
for ( i=0 ; i<count ; i++ ) {
|
|
data = samples[sampleOffset++];
|
|
samp[i].left += (data * leftvol)>>8;
|
|
samp[i].right += (data * rightvol)>>8;
|
|
|
|
if (sampleOffset == SND_CHUNK_SIZE*2) {
|
|
chunk = chunk->next;
|
|
decodeWavelet(chunk, sfxScratchBuffer);
|
|
sfxScratchIndex++;
|
|
sampleOffset = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void S_PaintChannelFromADPCM( channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
|
|
int data;
|
|
int leftvol, rightvol;
|
|
int i;
|
|
portable_samplepair_t *samp;
|
|
sndBuffer *chunk;
|
|
short *samples;
|
|
|
|
leftvol = ch->leftvol*snd_vol;
|
|
rightvol = ch->rightvol*snd_vol;
|
|
|
|
i = 0;
|
|
samp = &paintbuffer[ bufferOffset ];
|
|
chunk = sc->soundData;
|
|
|
|
if (ch->doppler) {
|
|
sampleOffset = sampleOffset*ch->oldDopplerScale;
|
|
}
|
|
|
|
while (sampleOffset>=(SND_CHUNK_SIZE*4)) {
|
|
chunk = chunk->next;
|
|
sampleOffset -= (SND_CHUNK_SIZE*4);
|
|
i++;
|
|
}
|
|
|
|
if (i!=sfxScratchIndex || sfxScratchPointer != sc) {
|
|
S_AdpcmGetSamples( chunk, sfxScratchBuffer );
|
|
sfxScratchIndex = i;
|
|
sfxScratchPointer = sc;
|
|
}
|
|
|
|
samples = sfxScratchBuffer;
|
|
|
|
for ( i=0 ; i<count ; i++ ) {
|
|
data = samples[sampleOffset++];
|
|
samp[i].left += (data * leftvol)>>8;
|
|
samp[i].right += (data * rightvol)>>8;
|
|
|
|
if (sampleOffset == SND_CHUNK_SIZE*4) {
|
|
chunk = chunk->next;
|
|
S_AdpcmGetSamples( chunk, sfxScratchBuffer);
|
|
sampleOffset = 0;
|
|
sfxScratchIndex++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static void S_PaintChannelFromMuLaw( channel_t *ch, sfx_t *sc, int count, int sampleOffset, int bufferOffset ) {
|
|
int data;
|
|
int leftvol, rightvol;
|
|
int i;
|
|
portable_samplepair_t *samp;
|
|
sndBuffer *chunk;
|
|
byte *samples;
|
|
float ooff;
|
|
|
|
leftvol = ch->leftvol*snd_vol;
|
|
rightvol = ch->rightvol*snd_vol;
|
|
|
|
samp = &paintbuffer[ bufferOffset ];
|
|
chunk = sc->soundData;
|
|
while (sampleOffset>=(SND_CHUNK_SIZE*2)) {
|
|
chunk = chunk->next;
|
|
sampleOffset -= (SND_CHUNK_SIZE*2);
|
|
if (!chunk) {
|
|
chunk = sc->soundData;
|
|
}
|
|
}
|
|
|
|
if (!ch->doppler) {
|
|
samples = (byte *)chunk->sndChunk + sampleOffset;
|
|
for ( i=0 ; i<count ; i++ ) {
|
|
data = mulawToShort[*samples];
|
|
samp[i].left += (data * leftvol)>>8;
|
|
samp[i].right += (data * rightvol)>>8;
|
|
samples++;
|
|
if ( chunk != NULL && samples == (byte *)chunk->sndChunk+(SND_CHUNK_SIZE*2)) {
|
|
chunk = chunk->next;
|
|
samples = (byte *)chunk->sndChunk;
|
|
}
|
|
}
|
|
} else {
|
|
ooff = sampleOffset;
|
|
samples = (byte *)chunk->sndChunk;
|
|
for ( i=0 ; i<count ; i++ ) {
|
|
data = mulawToShort[samples[(int)(ooff)]];
|
|
ooff = ooff + ch->dopplerScale;
|
|
samp[i].left += (data * leftvol)>>8;
|
|
samp[i].right += (data * rightvol)>>8;
|
|
if (ooff >= SND_CHUNK_SIZE*2) {
|
|
chunk = chunk->next;
|
|
if (!chunk) {
|
|
chunk = sc->soundData;
|
|
}
|
|
samples = (byte *)chunk->sndChunk;
|
|
ooff = 0.0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
===================
|
|
S_PaintChannels
|
|
===================
|
|
*/
|
|
void S_PaintChannels( int endtime ) {
|
|
static qboolean muted = qfalse;
|
|
int i;
|
|
int end;
|
|
channel_t *ch;
|
|
sfx_t *sc;
|
|
int ltime, count;
|
|
int sampleOffset;
|
|
byte *buffer;
|
|
|
|
snd_vol = s_volume->value * 255;
|
|
|
|
if ( (!gw_active && !gw_minimized && s_muteWhenUnfocused->integer) || (gw_minimized && s_muteWhenMinimized->integer) ) {
|
|
buffer = dma_buffer2;
|
|
if ( !muted ) {
|
|
// switching to muted, clear hardware buffer
|
|
Com_Memset( dma.buffer, 0, dma.samples * dma.samplebits/8 );
|
|
}
|
|
muted = qtrue;
|
|
} else {
|
|
buffer = dma.buffer;
|
|
// switching to unmuted, clear both buffers
|
|
if ( muted ) {
|
|
Com_Memset( dma.buffer, 0, dma.samples * dma.samplebits/8 );
|
|
Com_Memset( dma_buffer2, 0, dma.samples * dma.samplebits/8 );
|
|
}
|
|
muted = qfalse;
|
|
}
|
|
|
|
//Com_Printf ("%i to %i\n", s_paintedtime, endtime);
|
|
while ( endtime - s_paintedtime > 0 ) {
|
|
// if paintbuffer is smaller than DMA buffer
|
|
// we may need to fill it multiple times
|
|
end = endtime;
|
|
if ( endtime - s_paintedtime > PAINTBUFFER_SIZE ) {
|
|
end = s_paintedtime + PAINTBUFFER_SIZE;
|
|
}
|
|
|
|
// clear the paint buffer and mix any raw samples...
|
|
Com_Memset( paintbuffer, 0, sizeof( paintbuffer ) );
|
|
if ( s_rawend - s_paintedtime >= 0 ) {
|
|
// copy from the streaming sound source
|
|
const int stop = (end < s_rawend) ? end : s_rawend;
|
|
for ( i = s_paintedtime; i < stop; i++ ) {
|
|
const int s = i&(MAX_RAW_SAMPLES-1);
|
|
paintbuffer[i-s_paintedtime].left += s_rawsamples[s].left;
|
|
paintbuffer[i-s_paintedtime].right += s_rawsamples[s].right;
|
|
}
|
|
}
|
|
|
|
// paint in the channels.
|
|
ch = s_channels;
|
|
for ( i = 0; i < MAX_CHANNELS ; i++, ch++ ) {
|
|
if ( !ch->thesfx || (!ch->leftvol && !ch->rightvol) ) {
|
|
continue;
|
|
}
|
|
|
|
ltime = s_paintedtime;
|
|
sc = ch->thesfx;
|
|
|
|
if ( sc->soundData == NULL || sc->soundLength == 0 ) {
|
|
continue;
|
|
}
|
|
|
|
sampleOffset = ltime - ch->startSample;
|
|
count = end - ltime;
|
|
if ( sampleOffset + count > sc->soundLength ) {
|
|
count = sc->soundLength - sampleOffset;
|
|
}
|
|
|
|
if ( count > 0 ) {
|
|
if( sc->soundCompressionMethod == 1) {
|
|
S_PaintChannelFromADPCM (ch, sc, count, sampleOffset, ltime - s_paintedtime);
|
|
} else if( sc->soundCompressionMethod == 2) {
|
|
S_PaintChannelFromWavelet (ch, sc, count, sampleOffset, ltime - s_paintedtime);
|
|
} else if( sc->soundCompressionMethod == 3) {
|
|
S_PaintChannelFromMuLaw (ch, sc, count, sampleOffset, ltime - s_paintedtime);
|
|
} else {
|
|
S_PaintChannelFrom16 (ch, sc, count, sampleOffset, ltime - s_paintedtime);
|
|
}
|
|
}
|
|
}
|
|
|
|
// paint in the looped channels.
|
|
ch = loop_channels;
|
|
for ( i = 0; i < numLoopChannels ; i++, ch++ ) {
|
|
if ( !ch->thesfx || (!ch->leftvol && !ch->rightvol )) {
|
|
continue;
|
|
}
|
|
|
|
ltime = s_paintedtime;
|
|
sc = ch->thesfx;
|
|
|
|
if (sc->soundData==NULL || sc->soundLength==0) {
|
|
continue;
|
|
}
|
|
// we might have to make two passes if it
|
|
// is a looping sound effect and the end of
|
|
// the sample is hit
|
|
do {
|
|
sampleOffset = (ltime % sc->soundLength);
|
|
|
|
count = end - ltime;
|
|
if ( sampleOffset + count > sc->soundLength ) {
|
|
count = sc->soundLength - sampleOffset;
|
|
}
|
|
|
|
if ( count > 0 ) {
|
|
if( sc->soundCompressionMethod == 1) {
|
|
S_PaintChannelFromADPCM (ch, sc, count, sampleOffset, ltime - s_paintedtime);
|
|
} else if( sc->soundCompressionMethod == 2) {
|
|
S_PaintChannelFromWavelet (ch, sc, count, sampleOffset, ltime - s_paintedtime);
|
|
} else if( sc->soundCompressionMethod == 3) {
|
|
S_PaintChannelFromMuLaw (ch, sc, count, sampleOffset, ltime - s_paintedtime);
|
|
} else {
|
|
S_PaintChannelFrom16 (ch, sc, count, sampleOffset, ltime - s_paintedtime);
|
|
}
|
|
ltime += count;
|
|
}
|
|
} while ( ltime - end < 0 );
|
|
}
|
|
|
|
// transfer out according to DMA format
|
|
S_TransferPaintBuffer( end, buffer );
|
|
s_paintedtime = end;
|
|
}
|
|
}
|