gstreamer/gst/modplug/libmodplug/fastmix.cpp
Jeremy Simon ac87bfc370 adding modplug
Original commit message from CVS:
adding modplug
2002-02-28 21:10:42 +00:00

2277 lines
64 KiB
C++

/*
* This source code is public domain.
*
* Authors: Olivier Lapicque <olivierl@jps.net>
* Markus Fick <webmaster@mark-f.de> spline + fir-resampler
*/
#include "stdafx.h"
#include "sndfile.h"
#include <math.h>
#ifdef MSC_VER
#pragma bss_seg(".modplug")
#endif
// Front Mix Buffer (Also room for interleaved rear mix)
int MixSoundBuffer[MIXBUFFERSIZE*4];
// Reverb Mix Buffer
#ifndef NO_REVERB
int MixReverbBuffer[MIXBUFFERSIZE*2];
extern UINT gnReverbSend;
#endif
#ifndef FASTSOUNDLIB
int MixRearBuffer[MIXBUFFERSIZE*2];
float MixFloatBuffer[MIXBUFFERSIZE*2];
#endif
#ifdef MSC_VER
#pragma bss_seg()
#endif
extern LONG gnDryROfsVol;
extern LONG gnDryLOfsVol;
extern LONG gnRvbROfsVol;
extern LONG gnRvbLOfsVol;
// 4x256 taps polyphase FIR resampling filter
extern short int gFastSinc[];
extern short int gKaiserSinc[]; // 8-taps polyphase
/*
------------------------------------------------------------------------------------------------
cubic spline interpolation doc,
(derived from "digital image warping", g. wolberg)
interpolation polynomial: f(x) = A3*(x-floor(x))**3 + A2*(x-floor(x))**2 + A1*(x-floor(x)) + A0
with Y = equispaced data points (dist=1), YD = first derivates of data points and IP = floor(x)
the A[0..3] can be found by solving
A0 = Y[IP]
A1 = YD[IP]
A2 = 3*(Y[IP+1]-Y[IP])-2.0*YD[IP]-YD[IP+1]
A3 = -2.0 * (Y[IP+1]-Y[IP]) + YD[IP] - YD[IP+1]
with the first derivates as
YD[IP] = 0.5 * (Y[IP+1] - Y[IP-1]);
YD[IP+1] = 0.5 * (Y[IP+2] - Y[IP])
the coefs becomes
A0 = Y[IP]
A1 = YD[IP]
= 0.5 * (Y[IP+1] - Y[IP-1]);
A2 = 3.0 * (Y[IP+1]-Y[IP])-2.0*YD[IP]-YD[IP+1]
= 3.0 * (Y[IP+1] - Y[IP]) - 0.5 * 2.0 * (Y[IP+1] - Y[IP-1]) - 0.5 * (Y[IP+2] - Y[IP])
= 3.0 * Y[IP+1] - 3.0 * Y[IP] - Y[IP+1] + Y[IP-1] - 0.5 * Y[IP+2] + 0.5 * Y[IP]
= -0.5 * Y[IP+2] + 2.0 * Y[IP+1] - 2.5 * Y[IP] + Y[IP-1]
= Y[IP-1] + 2 * Y[IP+1] - 0.5 * (5.0 * Y[IP] + Y[IP+2])
A3 = -2.0 * (Y[IP+1]-Y[IP]) + YD[IP] + YD[IP+1]
= -2.0 * Y[IP+1] + 2.0 * Y[IP] + 0.5 * (Y[IP+1] - Y[IP-1]) + 0.5 * (Y[IP+2] - Y[IP])
= -2.0 * Y[IP+1] + 2.0 * Y[IP] + 0.5 * Y[IP+1] - 0.5 * Y[IP-1] + 0.5 * Y[IP+2] - 0.5 * Y[IP]
= 0.5 * Y[IP+2] - 1.5 * Y[IP+1] + 1.5 * Y[IP] - 0.5 * Y[IP-1]
= 0.5 * (3.0 * (Y[IP] - Y[IP+1]) - Y[IP-1] + YP[IP+2])
then interpolated data value is (horner rule)
out = (((A3*x)+A2)*x+A1)*x+A0
this gives parts of data points Y[IP-1] to Y[IP+2] of
part x**3 x**2 x**1 x**0
Y[IP-1] -0.5 1 -0.5 0
Y[IP] 1.5 -2.5 0 1
Y[IP+1] -1.5 2 0.5 0
Y[IP+2] 0.5 -0.5 0 0
--------------------------------------------------------------------------------------------------
*/
// number of bits used to scale spline coefs
#define SPLINE_QUANTBITS 14
#define SPLINE_QUANTSCALE (1L<<SPLINE_QUANTBITS)
#define SPLINE_8SHIFT (SPLINE_QUANTBITS-8)
#define SPLINE_16SHIFT (SPLINE_QUANTBITS)
// forces coefsset to unity gain
#define SPLINE_CLAMPFORUNITY
// log2(number) of precalculated splines (range is [4..14])
#define SPLINE_FRACBITS 10
#define SPLINE_LUTLEN (1L<<SPLINE_FRACBITS)
class CzCUBICSPLINE
{ public:
CzCUBICSPLINE( );
~CzCUBICSPLINE( );
static signed short lut[4*(1L<<SPLINE_FRACBITS)];
};
signed short CzCUBICSPLINE::lut[4*(1L<<SPLINE_FRACBITS)];
CzCUBICSPLINE::CzCUBICSPLINE( )
{ int _LIi;
int _LLen = (1L<<SPLINE_FRACBITS);
float _LFlen = 1.0f / (float)_LLen;
float _LScale = (float)SPLINE_QUANTSCALE;
for(_LIi=0;_LIi<_LLen;_LIi++)
{ float _LCm1, _LC0, _LC1, _LC2;
float _LX = ((float)_LIi)*_LFlen;
int _LSum,_LIdx = _LIi<<2;
_LCm1 = (float)floor( 0.5 + _LScale * (-0.5*_LX*_LX*_LX + 1.0 * _LX*_LX - 0.5 * _LX ) );
_LC0 = (float)floor( 0.5 + _LScale * ( 1.5*_LX*_LX*_LX - 2.5 * _LX*_LX + 1.0 ) );
_LC1 = (float)floor( 0.5 + _LScale * (-1.5*_LX*_LX*_LX + 2.0 * _LX*_LX + 0.5 * _LX ) );
_LC2 = (float)floor( 0.5 + _LScale * ( 0.5*_LX*_LX*_LX - 0.5 * _LX*_LX ) );
lut[_LIdx+0] = (signed short)( (_LCm1 < -_LScale) ? -_LScale : ((_LCm1 > _LScale) ? _LScale : _LCm1) );
lut[_LIdx+1] = (signed short)( (_LC0 < -_LScale) ? -_LScale : ((_LC0 > _LScale) ? _LScale : _LC0 ) );
lut[_LIdx+2] = (signed short)( (_LC1 < -_LScale) ? -_LScale : ((_LC1 > _LScale) ? _LScale : _LC1 ) );
lut[_LIdx+3] = (signed short)( (_LC2 < -_LScale) ? -_LScale : ((_LC2 > _LScale) ? _LScale : _LC2 ) );
#ifdef SPLINE_CLAMPFORUNITY
_LSum = lut[_LIdx+0]+lut[_LIdx+1]+lut[_LIdx+2]+lut[_LIdx+3];
if( _LSum != SPLINE_QUANTSCALE )
{ int _LMax = _LIdx;
if( lut[_LIdx+1]>lut[_LMax] ) _LMax = _LIdx+1;
if( lut[_LIdx+2]>lut[_LMax] ) _LMax = _LIdx+2;
if( lut[_LIdx+3]>lut[_LMax] ) _LMax = _LIdx+3;
lut[_LMax] += (SPLINE_QUANTSCALE-_LSum);
}
#endif
}
}
CzCUBICSPLINE::~CzCUBICSPLINE( )
{ // nothing todo
}
CzCUBICSPLINE sspline;
/*
------------------------------------------------------------------------------------------------
fir interpolation doc,
(derived from "an engineer's guide to fir digital filters", n.j. loy)
calculate coefficients for ideal lowpass filter (with cutoff = fc in 0..1 (mapped to 0..nyquist))
c[-N..N] = (i==0) ? fc : sin(fc*pi*i)/(pi*i)
then apply selected window to coefficients
c[-N..N] *= w(0..N)
with n in 2*N and w(n) being a window function (see loy)
then calculate gain and scale filter coefs to have unity gain.
------------------------------------------------------------------------------------------------
*/
// quantizer scale of window coefs
#define WFIR_QUANTBITS 15
#define WFIR_QUANTSCALE (1L<<WFIR_QUANTBITS)
#define WFIR_8SHIFT (WFIR_QUANTBITS-8)
#define WFIR_16BITSHIFT (WFIR_QUANTBITS)
// log2(number)-1 of precalculated taps range is [4..12]
#define WFIR_FRACBITS 10
#define WFIR_LUTLEN ((1L<<(WFIR_FRACBITS+1))+1)
// number of samples in window
#define WFIR_LOG2WIDTH 3
#define WFIR_WIDTH (1L<<WFIR_LOG2WIDTH)
#define WFIR_SMPSPERWING ((WFIR_WIDTH-1)>>1)
// cutoff (1.0 == pi/2)
#define WFIR_CUTOFF 0.90f
// wfir type
#define WFIR_HANN 0
#define WFIR_HAMMING 1
#define WFIR_BLACKMANEXACT 2
#define WFIR_BLACKMAN3T61 3
#define WFIR_BLACKMAN3T67 4
#define WFIR_BLACKMAN4T92 5
#define WFIR_BLACKMAN4T74 6
#define WFIR_KAISER4T 7
#define WFIR_TYPE WFIR_BLACKMANEXACT
// wfir help
#ifndef M_zPI
#define M_zPI 3.1415926535897932384626433832795
#endif
#define M_zEPS 1e-8
#define M_zBESSELEPS 1e-21
class CzWINDOWEDFIR
{ public:
CzWINDOWEDFIR( );
~CzWINDOWEDFIR( );
float coef( int _PCnr, float _POfs, float _PCut, int _PWidth, int _PType ) //float _PPos, float _PFc, int _PLen )
{ double _LWidthM1 = _PWidth-1;
double _LWidthM1Half = 0.5*_LWidthM1;
double _LPosU = ((double)_PCnr - _POfs);
double _LPos = _LPosU-_LWidthM1Half;
double _LPIdl = 2.0*M_zPI/_LWidthM1;
double _LWc,_LSi;
if( fabs(_LPos)<M_zEPS )
{ _LWc = 1.0;
_LSi = _PCut;
}
else
{ switch( _PType )
{ case WFIR_HANN:
_LWc = 0.50 - 0.50 * cos(_LPIdl*_LPosU);
break;
case WFIR_HAMMING:
_LWc = 0.54 - 0.46 * cos(_LPIdl*_LPosU);
break;
case WFIR_BLACKMANEXACT:
_LWc = 0.42 - 0.50 * cos(_LPIdl*_LPosU) + 0.08 * cos(2.0*_LPIdl*_LPosU);
break;
case WFIR_BLACKMAN3T61:
_LWc = 0.44959 - 0.49364 * cos(_LPIdl*_LPosU) + 0.05677 * cos(2.0*_LPIdl*_LPosU);
break;
case WFIR_BLACKMAN3T67:
_LWc = 0.42323 - 0.49755 * cos(_LPIdl*_LPosU) + 0.07922 * cos(2.0*_LPIdl*_LPosU);
break;
case WFIR_BLACKMAN4T92:
_LWc = 0.35875 - 0.48829 * cos(_LPIdl*_LPosU) + 0.14128 * cos(2.0*_LPIdl*_LPosU) - 0.01168 * cos(3.0*_LPIdl*_LPosU);
break;
case WFIR_BLACKMAN4T74:
_LWc = 0.40217 - 0.49703 * cos(_LPIdl*_LPosU) + 0.09392 * cos(2.0*_LPIdl*_LPosU) - 0.00183 * cos(3.0*_LPIdl*_LPosU);
break;
case WFIR_KAISER4T:
_LWc = 0.40243 - 0.49804 * cos(_LPIdl*_LPosU) + 0.09831 * cos(2.0*_LPIdl*_LPosU) - 0.00122 * cos(3.0*_LPIdl*_LPosU);
break;
default:
_LWc = 1.0;
break;
}
_LPos *= M_zPI;
_LSi = sin(_PCut*_LPos)/_LPos;
}
return (float)(_LWc*_LSi);
}
static signed short lut[WFIR_LUTLEN*WFIR_WIDTH];
};
signed short CzWINDOWEDFIR::lut[WFIR_LUTLEN*WFIR_WIDTH];
CzWINDOWEDFIR::CzWINDOWEDFIR()
{ int _LPcl;
float _LPcllen = (float)(1L<<WFIR_FRACBITS); // number of precalculated lines for 0..1 (-1..0)
float _LNorm = 1.0f / (float)(2.0f * _LPcllen);
float _LCut = WFIR_CUTOFF;
float _LScale = (float)WFIR_QUANTSCALE;
for( _LPcl=0;_LPcl<WFIR_LUTLEN;_LPcl++ )
{ float _LGain,_LCoefs[WFIR_WIDTH];
float _LOfs = ((float)_LPcl-_LPcllen)*_LNorm;
int _LCc,_LIdx = _LPcl<<WFIR_LOG2WIDTH;
for( _LCc=0,_LGain=0.0f;_LCc<WFIR_WIDTH;_LCc++ )
{ _LGain += (_LCoefs[_LCc] = coef( _LCc, _LOfs, _LCut, WFIR_WIDTH, WFIR_TYPE ));
}
_LGain = 1.0f/_LGain;
for( _LCc=0;_LCc<WFIR_WIDTH;_LCc++ )
{ float _LCoef = (float)floor( 0.5 + _LScale*_LCoefs[_LCc]*_LGain );
lut[_LIdx+_LCc] = (signed short)( (_LCoef<-_LScale)?-_LScale:((_LCoef>_LScale)?_LScale:_LCoef) );
}
}
}
CzWINDOWEDFIR::~CzWINDOWEDFIR()
{ // nothing todo
}
CzWINDOWEDFIR sfir;
// ------------------------------------------------------------------------------------------------
// MIXING MACROS
// ------------------------------------------------------------------------------------------------
/////////////////////////////////////////////////////
// Mixing Macros
#define SNDMIX_BEGINSAMPLELOOP8\
register MODCHANNEL * const pChn = pChannel;\
nPos = pChn->nPosLo;\
const signed char *p = (signed char *)(pChn->pCurrentSample+pChn->nPos);\
if (pChn->dwFlags & CHN_STEREO) p += pChn->nPos;\
int *pvol = pbuffer;\
do {
#define SNDMIX_BEGINSAMPLELOOP16\
register MODCHANNEL * const pChn = pChannel;\
nPos = pChn->nPosLo;\
const signed short *p = (signed short *)(pChn->pCurrentSample+(pChn->nPos*2));\
if (pChn->dwFlags & CHN_STEREO) p += pChn->nPos;\
int *pvol = pbuffer;\
do {
#define SNDMIX_ENDSAMPLELOOP\
nPos += pChn->nInc;\
} while (pvol < pbufmax);\
pChn->nPos += nPos >> 16;\
pChn->nPosLo = nPos & 0xFFFF;
#define SNDMIX_ENDSAMPLELOOP8 SNDMIX_ENDSAMPLELOOP
#define SNDMIX_ENDSAMPLELOOP16 SNDMIX_ENDSAMPLELOOP
//////////////////////////////////////////////////////////////////////////////
// Mono
// No interpolation
#define SNDMIX_GETMONOVOL8NOIDO\
int vol = p[nPos >> 16] << 8;
#define SNDMIX_GETMONOVOL16NOIDO\
int vol = p[nPos >> 16];
// Linear Interpolation
#define SNDMIX_GETMONOVOL8LINEAR\
int poshi = nPos >> 16;\
int poslo = (nPos >> 8) & 0xFF;\
int srcvol = p[poshi];\
int destvol = p[poshi+1];\
int vol = (srcvol<<8) + ((int)(poslo * (destvol - srcvol)));
#define SNDMIX_GETMONOVOL16LINEAR\
int poshi = nPos >> 16;\
int poslo = (nPos >> 8) & 0xFF;\
int srcvol = p[poshi];\
int destvol = p[poshi+1];\
int vol = srcvol + ((int)(poslo * (destvol - srcvol)) >> 8);
// spline interpolation (2 guard bits should be enough???)
#define SPLINE_FRACSHIFT ((16-SPLINE_FRACBITS)-2)
#define SPLINE_FRACMASK (((1L<<(16-SPLINE_FRACSHIFT))-1)&~3)
#define SNDMIX_GETMONOVOL8SPLINE \
int poshi = nPos >> 16; \
int poslo = (nPos >> SPLINE_FRACSHIFT) & SPLINE_FRACMASK; \
int vol = (CzCUBICSPLINE::lut[poslo ]*(int)p[poshi-1] + \
CzCUBICSPLINE::lut[poslo+1]*(int)p[poshi ] + \
CzCUBICSPLINE::lut[poslo+3]*(int)p[poshi+2] + \
CzCUBICSPLINE::lut[poslo+2]*(int)p[poshi+1]) >> SPLINE_8SHIFT;
#define SNDMIX_GETMONOVOL16SPLINE \
int poshi = nPos >> 16; \
int poslo = (nPos >> SPLINE_FRACSHIFT) & SPLINE_FRACMASK; \
int vol = (CzCUBICSPLINE::lut[poslo ]*(int)p[poshi-1] + \
CzCUBICSPLINE::lut[poslo+1]*(int)p[poshi ] + \
CzCUBICSPLINE::lut[poslo+3]*(int)p[poshi+2] + \
CzCUBICSPLINE::lut[poslo+2]*(int)p[poshi+1]) >> SPLINE_16SHIFT;
// fir interpolation
#define WFIR_FRACSHIFT (16-(WFIR_FRACBITS+1+WFIR_LOG2WIDTH))
#define WFIR_FRACMASK ((((1L<<(17-WFIR_FRACSHIFT))-1)&~((1L<<WFIR_LOG2WIDTH)-1)))
#define WFIR_FRACHALVE (1L<<(16-(WFIR_FRACBITS+2)))
#define SNDMIX_GETMONOVOL8FIRFILTER \
int poshi = nPos >> 16;\
int poslo = (nPos & 0xFFFF);\
int firidx = ((poslo+WFIR_FRACHALVE)>>WFIR_FRACSHIFT) & WFIR_FRACMASK; \
int vol = (CzWINDOWEDFIR::lut[firidx+0]*(int)p[poshi+1-4]); \
vol += (CzWINDOWEDFIR::lut[firidx+1]*(int)p[poshi+2-4]); \
vol += (CzWINDOWEDFIR::lut[firidx+2]*(int)p[poshi+3-4]); \
vol += (CzWINDOWEDFIR::lut[firidx+3]*(int)p[poshi+4-4]); \
vol += (CzWINDOWEDFIR::lut[firidx+4]*(int)p[poshi+5-4]); \
vol += (CzWINDOWEDFIR::lut[firidx+5]*(int)p[poshi+6-4]); \
vol += (CzWINDOWEDFIR::lut[firidx+6]*(int)p[poshi+7-4]); \
vol += (CzWINDOWEDFIR::lut[firidx+7]*(int)p[poshi+8-4]); \
vol >>= WFIR_8SHIFT;
#define SNDMIX_GETMONOVOL16FIRFILTER \
int poshi = nPos >> 16;\
int poslo = (nPos & 0xFFFF);\
int firidx = ((poslo+WFIR_FRACHALVE)>>WFIR_FRACSHIFT) & WFIR_FRACMASK; \
int vol1 = (CzWINDOWEDFIR::lut[firidx+0]*(int)p[poshi+1-4]); \
vol1 += (CzWINDOWEDFIR::lut[firidx+1]*(int)p[poshi+2-4]); \
vol1 += (CzWINDOWEDFIR::lut[firidx+2]*(int)p[poshi+3-4]); \
vol1 += (CzWINDOWEDFIR::lut[firidx+3]*(int)p[poshi+4-4]); \
int vol2 = (CzWINDOWEDFIR::lut[firidx+4]*(int)p[poshi+5-4]); \
vol2 += (CzWINDOWEDFIR::lut[firidx+5]*(int)p[poshi+6-4]); \
vol2 += (CzWINDOWEDFIR::lut[firidx+6]*(int)p[poshi+7-4]); \
vol2 += (CzWINDOWEDFIR::lut[firidx+7]*(int)p[poshi+8-4]); \
int vol = ((vol1>>1)+(vol2>>1)) >> (WFIR_16BITSHIFT-1);
/////////////////////////////////////////////////////////////////////////////
// Stereo
// No interpolation
#define SNDMIX_GETSTEREOVOL8NOIDO\
int vol_l = p[(nPos>>16)*2] << 8;\
int vol_r = p[(nPos>>16)*2+1] << 8;
#define SNDMIX_GETSTEREOVOL16NOIDO\
int vol_l = p[(nPos>>16)*2];\
int vol_r = p[(nPos>>16)*2+1];
// Linear Interpolation
#define SNDMIX_GETSTEREOVOL8LINEAR\
int poshi = nPos >> 16;\
int poslo = (nPos >> 8) & 0xFF;\
int srcvol_l = p[poshi*2];\
int vol_l = (srcvol_l<<8) + ((int)(poslo * (p[poshi*2+2] - srcvol_l)));\
int srcvol_r = p[poshi*2+1];\
int vol_r = (srcvol_r<<8) + ((int)(poslo * (p[poshi*2+3] - srcvol_r)));
#define SNDMIX_GETSTEREOVOL16LINEAR\
int poshi = nPos >> 16;\
int poslo = (nPos >> 8) & 0xFF;\
int srcvol_l = p[poshi*2];\
int vol_l = srcvol_l + ((int)(poslo * (p[poshi*2+2] - srcvol_l)) >> 8);\
int srcvol_r = p[poshi*2+1];\
int vol_r = srcvol_r + ((int)(poslo * (p[poshi*2+3] - srcvol_r)) >> 8);\
// Spline Interpolation
#define SNDMIX_GETSTEREOVOL8SPLINE \
int poshi = nPos >> 16; \
int poslo = (nPos >> SPLINE_FRACSHIFT) & SPLINE_FRACMASK; \
int vol_l = (CzCUBICSPLINE::lut[poslo ]*(int)p[(poshi-1)*2 ] + \
CzCUBICSPLINE::lut[poslo+1]*(int)p[(poshi )*2 ] + \
CzCUBICSPLINE::lut[poslo+2]*(int)p[(poshi+1)*2 ] + \
CzCUBICSPLINE::lut[poslo+3]*(int)p[(poshi+2)*2 ]) >> SPLINE_8SHIFT; \
int vol_r = (CzCUBICSPLINE::lut[poslo ]*(int)p[(poshi-1)*2+1] + \
CzCUBICSPLINE::lut[poslo+1]*(int)p[(poshi )*2+1] + \
CzCUBICSPLINE::lut[poslo+2]*(int)p[(poshi+1)*2+1] + \
CzCUBICSPLINE::lut[poslo+3]*(int)p[(poshi+2)*2+1]) >> SPLINE_8SHIFT;
#define SNDMIX_GETSTEREOVOL16SPLINE \
int poshi = nPos >> 16; \
int poslo = (nPos >> SPLINE_FRACSHIFT) & SPLINE_FRACMASK; \
int vol_l = (CzCUBICSPLINE::lut[poslo ]*(int)p[(poshi-1)*2 ] + \
CzCUBICSPLINE::lut[poslo+1]*(int)p[(poshi )*2 ] + \
CzCUBICSPLINE::lut[poslo+2]*(int)p[(poshi+1)*2 ] + \
CzCUBICSPLINE::lut[poslo+3]*(int)p[(poshi+2)*2 ]) >> SPLINE_16SHIFT; \
int vol_r = (CzCUBICSPLINE::lut[poslo ]*(int)p[(poshi-1)*2+1] + \
CzCUBICSPLINE::lut[poslo+1]*(int)p[(poshi )*2+1] + \
CzCUBICSPLINE::lut[poslo+2]*(int)p[(poshi+1)*2+1] + \
CzCUBICSPLINE::lut[poslo+3]*(int)p[(poshi+2)*2+1]) >> SPLINE_16SHIFT;
// fir interpolation
#define SNDMIX_GETSTEREOVOL8FIRFILTER \
int poshi = nPos >> 16;\
int poslo = (nPos & 0xFFFF);\
int firidx = ((poslo+WFIR_FRACHALVE)>>WFIR_FRACSHIFT) & WFIR_FRACMASK; \
int vol_l = (CzWINDOWEDFIR::lut[firidx+0]*(int)p[(poshi+1-4)*2 ]); \
vol_l += (CzWINDOWEDFIR::lut[firidx+1]*(int)p[(poshi+2-4)*2 ]); \
vol_l += (CzWINDOWEDFIR::lut[firidx+2]*(int)p[(poshi+3-4)*2 ]); \
vol_l += (CzWINDOWEDFIR::lut[firidx+3]*(int)p[(poshi+4-4)*2 ]); \
vol_l += (CzWINDOWEDFIR::lut[firidx+4]*(int)p[(poshi+5-4)*2 ]); \
vol_l += (CzWINDOWEDFIR::lut[firidx+5]*(int)p[(poshi+6-4)*2 ]); \
vol_l += (CzWINDOWEDFIR::lut[firidx+6]*(int)p[(poshi+7-4)*2 ]); \
vol_l += (CzWINDOWEDFIR::lut[firidx+7]*(int)p[(poshi+8-4)*2 ]); \
vol_l >>= WFIR_8SHIFT; \
int vol_r = (CzWINDOWEDFIR::lut[firidx+0]*(int)p[(poshi+1-4)*2+1]); \
vol_r += (CzWINDOWEDFIR::lut[firidx+1]*(int)p[(poshi+2-4)*2+1]); \
vol_r += (CzWINDOWEDFIR::lut[firidx+2]*(int)p[(poshi+3-4)*2+1]); \
vol_r += (CzWINDOWEDFIR::lut[firidx+3]*(int)p[(poshi+4-4)*2+1]); \
vol_r += (CzWINDOWEDFIR::lut[firidx+4]*(int)p[(poshi+5-4)*2+1]); \
vol_r += (CzWINDOWEDFIR::lut[firidx+5]*(int)p[(poshi+6-4)*2+1]); \
vol_r += (CzWINDOWEDFIR::lut[firidx+6]*(int)p[(poshi+7-4)*2+1]); \
vol_r += (CzWINDOWEDFIR::lut[firidx+7]*(int)p[(poshi+8-4)*2+1]); \
vol_r >>= WFIR_8SHIFT;
#define SNDMIX_GETSTEREOVOL16FIRFILTER \
int poshi = nPos >> 16;\
int poslo = (nPos & 0xFFFF);\
int firidx = ((poslo+WFIR_FRACHALVE)>>WFIR_FRACSHIFT) & WFIR_FRACMASK; \
int vol1_l = (CzWINDOWEDFIR::lut[firidx+0]*(int)p[(poshi+1-4)*2 ]); \
vol1_l += (CzWINDOWEDFIR::lut[firidx+1]*(int)p[(poshi+2-4)*2 ]); \
vol1_l += (CzWINDOWEDFIR::lut[firidx+2]*(int)p[(poshi+3-4)*2 ]); \
vol1_l += (CzWINDOWEDFIR::lut[firidx+3]*(int)p[(poshi+4-4)*2 ]); \
int vol2_l = (CzWINDOWEDFIR::lut[firidx+4]*(int)p[(poshi+5-4)*2 ]); \
vol2_l += (CzWINDOWEDFIR::lut[firidx+5]*(int)p[(poshi+6-4)*2 ]); \
vol2_l += (CzWINDOWEDFIR::lut[firidx+6]*(int)p[(poshi+7-4)*2 ]); \
vol2_l += (CzWINDOWEDFIR::lut[firidx+7]*(int)p[(poshi+8-4)*2 ]); \
int vol_l = ((vol1_l>>1)+(vol2_l>>1)) >> (WFIR_16BITSHIFT-1); \
int vol1_r = (CzWINDOWEDFIR::lut[firidx+0]*(int)p[(poshi+1-4)*2+1]); \
vol1_r += (CzWINDOWEDFIR::lut[firidx+1]*(int)p[(poshi+2-4)*2+1]); \
vol1_r += (CzWINDOWEDFIR::lut[firidx+2]*(int)p[(poshi+3-4)*2+1]); \
vol1_r += (CzWINDOWEDFIR::lut[firidx+3]*(int)p[(poshi+4-4)*2+1]); \
int vol2_r = (CzWINDOWEDFIR::lut[firidx+4]*(int)p[(poshi+5-4)*2+1]); \
vol2_r += (CzWINDOWEDFIR::lut[firidx+5]*(int)p[(poshi+6-4)*2+1]); \
vol2_r += (CzWINDOWEDFIR::lut[firidx+6]*(int)p[(poshi+7-4)*2+1]); \
vol2_r += (CzWINDOWEDFIR::lut[firidx+7]*(int)p[(poshi+8-4)*2+1]); \
int vol_r = ((vol1_r>>1)+(vol2_r>>1)) >> (WFIR_16BITSHIFT-1);
/////////////////////////////////////////////////////////////////////////////
#define SNDMIX_STOREMONOVOL\
pvol[0] += vol * pChn->nRightVol;\
pvol[1] += vol * pChn->nLeftVol;\
pvol += 2;
#define SNDMIX_STORESTEREOVOL\
pvol[0] += vol_l * pChn->nRightVol;\
pvol[1] += vol_r * pChn->nLeftVol;\
pvol += 2;
#define SNDMIX_STOREFASTMONOVOL\
int v = vol * pChn->nRightVol;\
pvol[0] += v;\
pvol[1] += v;\
pvol += 2;
#define SNDMIX_RAMPMONOVOL\
nRampLeftVol += pChn->nLeftRamp;\
nRampRightVol += pChn->nRightRamp;\
pvol[0] += vol * (nRampRightVol >> VOLUMERAMPPRECISION);\
pvol[1] += vol * (nRampLeftVol >> VOLUMERAMPPRECISION);\
pvol += 2;
#define SNDMIX_RAMPFASTMONOVOL\
nRampRightVol += pChn->nRightRamp;\
int fastvol = vol * (nRampRightVol >> VOLUMERAMPPRECISION);\
pvol[0] += fastvol;\
pvol[1] += fastvol;\
pvol += 2;
#define SNDMIX_RAMPSTEREOVOL\
nRampLeftVol += pChn->nLeftRamp;\
nRampRightVol += pChn->nRightRamp;\
pvol[0] += vol_l * (nRampRightVol >> VOLUMERAMPPRECISION);\
pvol[1] += vol_r * (nRampLeftVol >> VOLUMERAMPPRECISION);\
pvol += 2;
///////////////////////////////////////////////////
// Resonant Filters
// Mono
#define MIX_BEGIN_FILTER\
int fy1 = pChannel->nFilter_Y1;\
int fy2 = pChannel->nFilter_Y2;\
#define MIX_END_FILTER\
pChannel->nFilter_Y1 = fy1;\
pChannel->nFilter_Y2 = fy2;
#define SNDMIX_PROCESSFILTER\
vol = (vol * pChn->nFilter_A0 + fy1 * pChn->nFilter_B0 + fy2 * pChn->nFilter_B1 + 4096) >> 13;\
fy2 = fy1;\
fy1 = vol;\
// Stereo
#define MIX_BEGIN_STEREO_FILTER\
int fy1 = pChannel->nFilter_Y1;\
int fy2 = pChannel->nFilter_Y2;\
int fy3 = pChannel->nFilter_Y3;\
int fy4 = pChannel->nFilter_Y4;\
#define MIX_END_STEREO_FILTER\
pChannel->nFilter_Y1 = fy1;\
pChannel->nFilter_Y2 = fy2;\
pChannel->nFilter_Y3 = fy3;\
pChannel->nFilter_Y4 = fy4;\
#define SNDMIX_PROCESSSTEREOFILTER\
vol_l = (vol_l * pChn->nFilter_A0 + fy1 * pChn->nFilter_B0 + fy2 * pChn->nFilter_B1 + 4096) >> 13;\
vol_r = (vol_r * pChn->nFilter_A0 + fy3 * pChn->nFilter_B0 + fy4 * pChn->nFilter_B1 + 4096) >> 13;\
fy2 = fy1; fy1 = vol_l;\
fy4 = fy3; fy3 = vol_r;\
//////////////////////////////////////////////////////////
// Interfaces
typedef VOID (MPPASMCALL * LPMIXINTERFACE)(MODCHANNEL *, int *, int *);
#define BEGIN_MIX_INTERFACE(func)\
VOID MPPASMCALL func(MODCHANNEL *pChannel, int *pbuffer, int *pbufmax)\
{\
LONG nPos;
#define END_MIX_INTERFACE()\
SNDMIX_ENDSAMPLELOOP\
}
// Volume Ramps
#define BEGIN_RAMPMIX_INTERFACE(func)\
BEGIN_MIX_INTERFACE(func)\
LONG nRampRightVol = pChannel->nRampRightVol;\
LONG nRampLeftVol = pChannel->nRampLeftVol;
#define END_RAMPMIX_INTERFACE()\
SNDMIX_ENDSAMPLELOOP\
pChannel->nRampRightVol = nRampRightVol;\
pChannel->nRightVol = nRampRightVol >> VOLUMERAMPPRECISION;\
pChannel->nRampLeftVol = nRampLeftVol;\
pChannel->nLeftVol = nRampLeftVol >> VOLUMERAMPPRECISION;\
}
#define BEGIN_FASTRAMPMIX_INTERFACE(func)\
BEGIN_MIX_INTERFACE(func)\
LONG nRampRightVol = pChannel->nRampRightVol;
#define END_FASTRAMPMIX_INTERFACE()\
SNDMIX_ENDSAMPLELOOP\
pChannel->nRampRightVol = nRampRightVol;\
pChannel->nRampLeftVol = nRampRightVol;\
pChannel->nRightVol = nRampRightVol >> VOLUMERAMPPRECISION;\
pChannel->nLeftVol = pChannel->nRightVol;\
}
// Mono Resonant Filters
#define BEGIN_MIX_FLT_INTERFACE(func)\
BEGIN_MIX_INTERFACE(func)\
MIX_BEGIN_FILTER
#define END_MIX_FLT_INTERFACE()\
SNDMIX_ENDSAMPLELOOP\
MIX_END_FILTER\
}
#define BEGIN_RAMPMIX_FLT_INTERFACE(func)\
BEGIN_MIX_INTERFACE(func)\
LONG nRampRightVol = pChannel->nRampRightVol;\
LONG nRampLeftVol = pChannel->nRampLeftVol;\
MIX_BEGIN_FILTER
#define END_RAMPMIX_FLT_INTERFACE()\
SNDMIX_ENDSAMPLELOOP\
MIX_END_FILTER\
pChannel->nRampRightVol = nRampRightVol;\
pChannel->nRightVol = nRampRightVol >> VOLUMERAMPPRECISION;\
pChannel->nRampLeftVol = nRampLeftVol;\
pChannel->nLeftVol = nRampLeftVol >> VOLUMERAMPPRECISION;\
}
// Stereo Resonant Filters
#define BEGIN_MIX_STFLT_INTERFACE(func)\
BEGIN_MIX_INTERFACE(func)\
MIX_BEGIN_STEREO_FILTER
#define END_MIX_STFLT_INTERFACE()\
SNDMIX_ENDSAMPLELOOP\
MIX_END_STEREO_FILTER\
}
#define BEGIN_RAMPMIX_STFLT_INTERFACE(func)\
BEGIN_MIX_INTERFACE(func)\
LONG nRampRightVol = pChannel->nRampRightVol;\
LONG nRampLeftVol = pChannel->nRampLeftVol;\
MIX_BEGIN_STEREO_FILTER
#define END_RAMPMIX_STFLT_INTERFACE()\
SNDMIX_ENDSAMPLELOOP\
MIX_END_STEREO_FILTER\
pChannel->nRampRightVol = nRampRightVol;\
pChannel->nRightVol = nRampRightVol >> VOLUMERAMPPRECISION;\
pChannel->nRampLeftVol = nRampLeftVol;\
pChannel->nLeftVol = nRampLeftVol >> VOLUMERAMPPRECISION;\
}
/////////////////////////////////////////////////////
//
void MPPASMCALL X86_InitMixBuffer(int *pBuffer, UINT nSamples);
void MPPASMCALL X86_EndChannelOfs(MODCHANNEL *pChannel, int *pBuffer, UINT nSamples);
void MPPASMCALL X86_StereoFill(int *pBuffer, UINT nSamples, LPLONG lpROfs, LPLONG lpLOfs);
void X86_StereoMixToFloat(const int *, float *, float *, UINT nCount);
void X86_FloatToStereoMix(const float *pIn1, const float *pIn2, int *pOut, UINT nCount);
/////////////////////////////////////////////////////
// Mono samples functions
BEGIN_MIX_INTERFACE(Mono8BitMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETMONOVOL8NOIDO
SNDMIX_STOREMONOVOL
END_MIX_INTERFACE()
BEGIN_MIX_INTERFACE(Mono16BitMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETMONOVOL16NOIDO
SNDMIX_STOREMONOVOL
END_MIX_INTERFACE()
BEGIN_MIX_INTERFACE(Mono8BitLinearMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETMONOVOL8LINEAR
SNDMIX_STOREMONOVOL
END_MIX_INTERFACE()
BEGIN_MIX_INTERFACE(Mono16BitLinearMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETMONOVOL16LINEAR
SNDMIX_STOREMONOVOL
END_MIX_INTERFACE()
BEGIN_MIX_INTERFACE(Mono8BitSplineMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETMONOVOL8SPLINE
SNDMIX_STOREMONOVOL
END_MIX_INTERFACE()
BEGIN_MIX_INTERFACE(Mono16BitSplineMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETMONOVOL16SPLINE
SNDMIX_STOREMONOVOL
END_MIX_INTERFACE()
BEGIN_MIX_INTERFACE(Mono8BitFirFilterMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETMONOVOL8FIRFILTER
SNDMIX_STOREMONOVOL
END_MIX_INTERFACE()
BEGIN_MIX_INTERFACE(Mono16BitFirFilterMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETMONOVOL16FIRFILTER
SNDMIX_STOREMONOVOL
END_MIX_INTERFACE()
// Volume Ramps
BEGIN_RAMPMIX_INTERFACE(Mono8BitRampMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETMONOVOL8NOIDO
SNDMIX_RAMPMONOVOL
END_RAMPMIX_INTERFACE()
BEGIN_RAMPMIX_INTERFACE(Mono16BitRampMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETMONOVOL16NOIDO
SNDMIX_RAMPMONOVOL
END_RAMPMIX_INTERFACE()
BEGIN_RAMPMIX_INTERFACE(Mono8BitLinearRampMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETMONOVOL8LINEAR
SNDMIX_RAMPMONOVOL
END_RAMPMIX_INTERFACE()
BEGIN_RAMPMIX_INTERFACE(Mono16BitLinearRampMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETMONOVOL16LINEAR
SNDMIX_RAMPMONOVOL
END_RAMPMIX_INTERFACE()
BEGIN_RAMPMIX_INTERFACE(Mono8BitSplineRampMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETMONOVOL8SPLINE
SNDMIX_RAMPMONOVOL
END_RAMPMIX_INTERFACE()
BEGIN_RAMPMIX_INTERFACE(Mono16BitSplineRampMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETMONOVOL16SPLINE
SNDMIX_RAMPMONOVOL
END_RAMPMIX_INTERFACE()
BEGIN_RAMPMIX_INTERFACE(Mono8BitFirFilterRampMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETMONOVOL8FIRFILTER
SNDMIX_RAMPMONOVOL
END_RAMPMIX_INTERFACE()
BEGIN_RAMPMIX_INTERFACE(Mono16BitFirFilterRampMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETMONOVOL16FIRFILTER
SNDMIX_RAMPMONOVOL
END_RAMPMIX_INTERFACE()
//////////////////////////////////////////////////////
// Fast mono mix for leftvol=rightvol (1 less imul)
BEGIN_MIX_INTERFACE(FastMono8BitMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETMONOVOL8NOIDO
SNDMIX_STOREFASTMONOVOL
END_MIX_INTERFACE()
BEGIN_MIX_INTERFACE(FastMono16BitMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETMONOVOL16NOIDO
SNDMIX_STOREFASTMONOVOL
END_MIX_INTERFACE()
BEGIN_MIX_INTERFACE(FastMono8BitLinearMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETMONOVOL8LINEAR
SNDMIX_STOREFASTMONOVOL
END_MIX_INTERFACE()
BEGIN_MIX_INTERFACE(FastMono16BitLinearMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETMONOVOL16LINEAR
SNDMIX_STOREFASTMONOVOL
END_MIX_INTERFACE()
BEGIN_MIX_INTERFACE(FastMono8BitSplineMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETMONOVOL8SPLINE
SNDMIX_STOREFASTMONOVOL
END_MIX_INTERFACE()
BEGIN_MIX_INTERFACE(FastMono16BitSplineMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETMONOVOL16SPLINE
SNDMIX_STOREFASTMONOVOL
END_MIX_INTERFACE()
BEGIN_MIX_INTERFACE(FastMono8BitFirFilterMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETMONOVOL8FIRFILTER
SNDMIX_STOREFASTMONOVOL
END_MIX_INTERFACE()
BEGIN_MIX_INTERFACE(FastMono16BitFirFilterMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETMONOVOL16FIRFILTER
SNDMIX_STOREFASTMONOVOL
END_MIX_INTERFACE()
// Fast Ramps
BEGIN_FASTRAMPMIX_INTERFACE(FastMono8BitRampMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETMONOVOL8NOIDO
SNDMIX_RAMPFASTMONOVOL
END_FASTRAMPMIX_INTERFACE()
BEGIN_FASTRAMPMIX_INTERFACE(FastMono16BitRampMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETMONOVOL16NOIDO
SNDMIX_RAMPFASTMONOVOL
END_FASTRAMPMIX_INTERFACE()
BEGIN_FASTRAMPMIX_INTERFACE(FastMono8BitLinearRampMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETMONOVOL8LINEAR
SNDMIX_RAMPFASTMONOVOL
END_FASTRAMPMIX_INTERFACE()
BEGIN_FASTRAMPMIX_INTERFACE(FastMono16BitLinearRampMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETMONOVOL16LINEAR
SNDMIX_RAMPFASTMONOVOL
END_FASTRAMPMIX_INTERFACE()
BEGIN_FASTRAMPMIX_INTERFACE(FastMono8BitSplineRampMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETMONOVOL8SPLINE
SNDMIX_RAMPFASTMONOVOL
END_FASTRAMPMIX_INTERFACE()
BEGIN_FASTRAMPMIX_INTERFACE(FastMono16BitSplineRampMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETMONOVOL16SPLINE
SNDMIX_RAMPFASTMONOVOL
END_FASTRAMPMIX_INTERFACE()
BEGIN_FASTRAMPMIX_INTERFACE(FastMono8BitFirFilterRampMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETMONOVOL8FIRFILTER
SNDMIX_RAMPFASTMONOVOL
END_FASTRAMPMIX_INTERFACE()
BEGIN_FASTRAMPMIX_INTERFACE(FastMono16BitFirFilterRampMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETMONOVOL16FIRFILTER
SNDMIX_RAMPFASTMONOVOL
END_FASTRAMPMIX_INTERFACE()
//////////////////////////////////////////////////////
// Stereo samples
BEGIN_MIX_INTERFACE(Stereo8BitMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETSTEREOVOL8NOIDO
SNDMIX_STORESTEREOVOL
END_MIX_INTERFACE()
BEGIN_MIX_INTERFACE(Stereo16BitMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETSTEREOVOL16NOIDO
SNDMIX_STORESTEREOVOL
END_MIX_INTERFACE()
BEGIN_MIX_INTERFACE(Stereo8BitLinearMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETSTEREOVOL8LINEAR
SNDMIX_STORESTEREOVOL
END_MIX_INTERFACE()
BEGIN_MIX_INTERFACE(Stereo16BitLinearMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETSTEREOVOL16LINEAR
SNDMIX_STORESTEREOVOL
END_MIX_INTERFACE()
BEGIN_MIX_INTERFACE(Stereo8BitSplineMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETSTEREOVOL8SPLINE
SNDMIX_STORESTEREOVOL
END_MIX_INTERFACE()
BEGIN_MIX_INTERFACE(Stereo16BitSplineMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETSTEREOVOL16SPLINE
SNDMIX_STORESTEREOVOL
END_MIX_INTERFACE()
BEGIN_MIX_INTERFACE(Stereo8BitFirFilterMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETSTEREOVOL8FIRFILTER
SNDMIX_STORESTEREOVOL
END_MIX_INTERFACE()
BEGIN_MIX_INTERFACE(Stereo16BitFirFilterMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETSTEREOVOL16FIRFILTER
SNDMIX_STORESTEREOVOL
END_MIX_INTERFACE()
// Volume Ramps
BEGIN_RAMPMIX_INTERFACE(Stereo8BitRampMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETSTEREOVOL8NOIDO
SNDMIX_RAMPSTEREOVOL
END_RAMPMIX_INTERFACE()
BEGIN_RAMPMIX_INTERFACE(Stereo16BitRampMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETSTEREOVOL16NOIDO
SNDMIX_RAMPSTEREOVOL
END_RAMPMIX_INTERFACE()
BEGIN_RAMPMIX_INTERFACE(Stereo8BitLinearRampMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETSTEREOVOL8LINEAR
SNDMIX_RAMPSTEREOVOL
END_RAMPMIX_INTERFACE()
BEGIN_RAMPMIX_INTERFACE(Stereo16BitLinearRampMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETSTEREOVOL16LINEAR
SNDMIX_RAMPSTEREOVOL
END_RAMPMIX_INTERFACE()
BEGIN_RAMPMIX_INTERFACE(Stereo8BitSplineRampMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETSTEREOVOL8SPLINE
SNDMIX_RAMPSTEREOVOL
END_RAMPMIX_INTERFACE()
BEGIN_RAMPMIX_INTERFACE(Stereo16BitSplineRampMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETSTEREOVOL16SPLINE
SNDMIX_RAMPSTEREOVOL
END_RAMPMIX_INTERFACE()
BEGIN_RAMPMIX_INTERFACE(Stereo8BitFirFilterRampMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETSTEREOVOL8FIRFILTER
SNDMIX_RAMPSTEREOVOL
END_RAMPMIX_INTERFACE()
BEGIN_RAMPMIX_INTERFACE(Stereo16BitFirFilterRampMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETSTEREOVOL16FIRFILTER
SNDMIX_RAMPSTEREOVOL
END_RAMPMIX_INTERFACE()
//////////////////////////////////////////////////////
// Resonant Filter Mix
#ifndef NO_FILTER
// Mono Filter Mix
BEGIN_MIX_FLT_INTERFACE(FilterMono8BitMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETMONOVOL8NOIDO
SNDMIX_PROCESSFILTER
SNDMIX_STOREMONOVOL
END_MIX_FLT_INTERFACE()
BEGIN_MIX_FLT_INTERFACE(FilterMono16BitMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETMONOVOL16NOIDO
SNDMIX_PROCESSFILTER
SNDMIX_STOREMONOVOL
END_MIX_FLT_INTERFACE()
BEGIN_MIX_FLT_INTERFACE(FilterMono8BitLinearMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETMONOVOL8LINEAR
SNDMIX_PROCESSFILTER
SNDMIX_STOREMONOVOL
END_MIX_FLT_INTERFACE()
BEGIN_MIX_FLT_INTERFACE(FilterMono16BitLinearMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETMONOVOL16LINEAR
SNDMIX_PROCESSFILTER
SNDMIX_STOREMONOVOL
END_MIX_FLT_INTERFACE()
BEGIN_MIX_FLT_INTERFACE(FilterMono8BitSplineMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETMONOVOL8SPLINE
SNDMIX_PROCESSFILTER
SNDMIX_STOREMONOVOL
END_MIX_FLT_INTERFACE()
BEGIN_MIX_FLT_INTERFACE(FilterMono16BitSplineMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETMONOVOL16SPLINE
SNDMIX_PROCESSFILTER
SNDMIX_STOREMONOVOL
END_MIX_FLT_INTERFACE()
BEGIN_MIX_FLT_INTERFACE(FilterMono8BitFirFilterMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETMONOVOL8FIRFILTER
SNDMIX_PROCESSFILTER
SNDMIX_STOREMONOVOL
END_MIX_FLT_INTERFACE()
BEGIN_MIX_FLT_INTERFACE(FilterMono16BitFirFilterMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETMONOVOL16FIRFILTER
SNDMIX_PROCESSFILTER
SNDMIX_STOREMONOVOL
END_MIX_FLT_INTERFACE()
// Filter + Ramp
BEGIN_RAMPMIX_FLT_INTERFACE(FilterMono8BitRampMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETMONOVOL8NOIDO
SNDMIX_PROCESSFILTER
SNDMIX_RAMPMONOVOL
END_RAMPMIX_FLT_INTERFACE()
BEGIN_RAMPMIX_FLT_INTERFACE(FilterMono16BitRampMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETMONOVOL16NOIDO
SNDMIX_PROCESSFILTER
SNDMIX_RAMPMONOVOL
END_RAMPMIX_FLT_INTERFACE()
BEGIN_RAMPMIX_FLT_INTERFACE(FilterMono8BitLinearRampMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETMONOVOL8LINEAR
SNDMIX_PROCESSFILTER
SNDMIX_RAMPMONOVOL
END_RAMPMIX_FLT_INTERFACE()
BEGIN_RAMPMIX_FLT_INTERFACE(FilterMono16BitLinearRampMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETMONOVOL16LINEAR
SNDMIX_PROCESSFILTER
SNDMIX_RAMPMONOVOL
END_RAMPMIX_FLT_INTERFACE()
BEGIN_RAMPMIX_FLT_INTERFACE(FilterMono8BitSplineRampMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETMONOVOL8SPLINE
SNDMIX_PROCESSFILTER
SNDMIX_RAMPMONOVOL
END_RAMPMIX_FLT_INTERFACE()
BEGIN_RAMPMIX_FLT_INTERFACE(FilterMono16BitSplineRampMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETMONOVOL16SPLINE
SNDMIX_PROCESSFILTER
SNDMIX_RAMPMONOVOL
END_RAMPMIX_FLT_INTERFACE()
BEGIN_RAMPMIX_FLT_INTERFACE(FilterMono8BitFirFilterRampMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETMONOVOL8FIRFILTER
SNDMIX_PROCESSFILTER
SNDMIX_RAMPMONOVOL
END_RAMPMIX_FLT_INTERFACE()
BEGIN_RAMPMIX_FLT_INTERFACE(FilterMono16BitFirFilterRampMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETMONOVOL16FIRFILTER
SNDMIX_PROCESSFILTER
SNDMIX_RAMPMONOVOL
END_RAMPMIX_FLT_INTERFACE()
// Stereo Filter Mix
BEGIN_MIX_STFLT_INTERFACE(FilterStereo8BitMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETSTEREOVOL8NOIDO
SNDMIX_PROCESSSTEREOFILTER
SNDMIX_STORESTEREOVOL
END_MIX_STFLT_INTERFACE()
BEGIN_MIX_STFLT_INTERFACE(FilterStereo16BitMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETSTEREOVOL16NOIDO
SNDMIX_PROCESSSTEREOFILTER
SNDMIX_STORESTEREOVOL
END_MIX_STFLT_INTERFACE()
BEGIN_MIX_STFLT_INTERFACE(FilterStereo8BitLinearMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETSTEREOVOL8LINEAR
SNDMIX_PROCESSSTEREOFILTER
SNDMIX_STORESTEREOVOL
END_MIX_STFLT_INTERFACE()
BEGIN_MIX_STFLT_INTERFACE(FilterStereo16BitLinearMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETSTEREOVOL16LINEAR
SNDMIX_PROCESSSTEREOFILTER
SNDMIX_STORESTEREOVOL
END_MIX_STFLT_INTERFACE()
BEGIN_MIX_STFLT_INTERFACE(FilterStereo8BitSplineMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETSTEREOVOL8SPLINE
SNDMIX_PROCESSSTEREOFILTER
SNDMIX_STORESTEREOVOL
END_MIX_STFLT_INTERFACE()
BEGIN_MIX_STFLT_INTERFACE(FilterStereo16BitSplineMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETSTEREOVOL16SPLINE
SNDMIX_PROCESSSTEREOFILTER
SNDMIX_STORESTEREOVOL
END_MIX_STFLT_INTERFACE()
BEGIN_MIX_STFLT_INTERFACE(FilterStereo8BitFirFilterMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETSTEREOVOL8FIRFILTER
SNDMIX_PROCESSSTEREOFILTER
SNDMIX_STORESTEREOVOL
END_MIX_STFLT_INTERFACE()
BEGIN_MIX_STFLT_INTERFACE(FilterStereo16BitFirFilterMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETSTEREOVOL16FIRFILTER
SNDMIX_PROCESSSTEREOFILTER
SNDMIX_STORESTEREOVOL
END_MIX_STFLT_INTERFACE()
// Stereo Filter + Ramp
BEGIN_RAMPMIX_STFLT_INTERFACE(FilterStereo8BitRampMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETSTEREOVOL8NOIDO
SNDMIX_PROCESSSTEREOFILTER
SNDMIX_RAMPSTEREOVOL
END_RAMPMIX_STFLT_INTERFACE()
BEGIN_RAMPMIX_STFLT_INTERFACE(FilterStereo16BitRampMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETSTEREOVOL16NOIDO
SNDMIX_PROCESSSTEREOFILTER
SNDMIX_RAMPSTEREOVOL
END_RAMPMIX_STFLT_INTERFACE()
BEGIN_RAMPMIX_STFLT_INTERFACE(FilterStereo8BitLinearRampMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETSTEREOVOL8LINEAR
SNDMIX_PROCESSSTEREOFILTER
SNDMIX_RAMPSTEREOVOL
END_RAMPMIX_STFLT_INTERFACE()
BEGIN_RAMPMIX_STFLT_INTERFACE(FilterStereo16BitLinearRampMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETSTEREOVOL16LINEAR
SNDMIX_PROCESSSTEREOFILTER
SNDMIX_RAMPSTEREOVOL
END_RAMPMIX_STFLT_INTERFACE()
BEGIN_RAMPMIX_STFLT_INTERFACE(FilterStereo8BitSplineRampMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETSTEREOVOL8SPLINE
SNDMIX_PROCESSSTEREOFILTER
SNDMIX_RAMPSTEREOVOL
END_RAMPMIX_STFLT_INTERFACE()
BEGIN_RAMPMIX_STFLT_INTERFACE(FilterStereo16BitSplineRampMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETSTEREOVOL16SPLINE
SNDMIX_PROCESSSTEREOFILTER
SNDMIX_RAMPSTEREOVOL
END_RAMPMIX_STFLT_INTERFACE()
BEGIN_RAMPMIX_STFLT_INTERFACE(FilterStereo8BitFirFilterRampMix)
SNDMIX_BEGINSAMPLELOOP8
SNDMIX_GETSTEREOVOL8FIRFILTER
SNDMIX_PROCESSSTEREOFILTER
SNDMIX_RAMPSTEREOVOL
END_RAMPMIX_STFLT_INTERFACE()
BEGIN_RAMPMIX_STFLT_INTERFACE(FilterStereo16BitFirFilterRampMix)
SNDMIX_BEGINSAMPLELOOP16
SNDMIX_GETSTEREOVOL16FIRFILTER
SNDMIX_PROCESSSTEREOFILTER
SNDMIX_RAMPSTEREOVOL
END_RAMPMIX_STFLT_INTERFACE()
#else
// Mono
#define FilterMono8BitMix Mono8BitMix
#define FilterMono16BitMix Mono16BitMix
#define FilterMono8BitLinearMix Mono8BitLinearMix
#define FilterMono16BitLinearMix Mono16BitLinearMix
#define FilterMono8BitSplineMix Mono8BitSplineMix
#define FilterMono16BitSplineMix Mono16BitSplineMix
#define FilterMono8BitFirFilterMix Mono8BitFirFilterMix
#define FilterMono16BitFirFilterMix Mono16BitFirFilterMix
#define FilterMono8BitRampMix Mono8BitRampMix
#define FilterMono16BitRampMix Mono16BitRampMix
#define FilterMono8BitLinearRampMix Mono8BitLinearRampMix
#define FilterMono16BitLinearRampMix Mono16BitLinearRampMix
#define FilterMono8BitSplineRampMix Mono8BitSplineRampMix
#define FilterMono16BitSplineRampMix Mono16BitSplineRampMix
#define FilterMono8BitFirFilterRampMix Mono8BitFirFilterRampMix
#define FilterMono16BitFirFilterRampMix Mono16BitFirFilterRampMix
// Stereo
#define FilterStereo8BitMix Stereo8BitMix
#define FilterStereo16BitMix Stereo16BitMix
#define FilterStereo8BitLinearMix Stereo8BitLinearMix
#define FilterStereo16BitLinearMix Stereo16BitLinearMix
#define FilterStereo8BitSplineMix Stereo8BitSplineMix
#define FilterStereo16BitSplineMix Stereo16BitSplineMix
#define FilterStereo8BitFirFilterMix Stereo8BitFirFilterMix
#define FilterStereo16BitFirFilterMix Stereo16BitFirFilterMix
#define FilterStereo8BitRampMix Stereo8BitRampMix
#define FilterStereo16BitRampMix Stereo16BitRampMix
#define FilterStereo8BitLinearRampMix Stereo8BitLinearRampMix
#define FilterStereo16BitLinearRampMix Stereo16BitLinearRampMix
#define FilterStereo8BitSplineRampMix Stereo8BitSplineRampMix
#define FilterStereo16BitSplineRampMix Stereo16BitSplineRampMix
#define FilterStereo8BitFirFilterRampMix Stereo8BitFirFilterRampMix
#define FilterStereo16BitFirFilterRampMix Stereo16BitFirFilterRampMix
#endif
/////////////////////////////////////////////////////////////////////////////////////
//
// Mix function tables
//
//
// Index is as follow:
// [b1-b0] format (8-bit-mono, 16-bit-mono, 8-bit-stereo, 16-bit-stereo)
// [b2] ramp
// [b3] filter
// [b5-b4] src type
//
#define MIXNDX_16BIT 0x01
#define MIXNDX_STEREO 0x02
#define MIXNDX_RAMP 0x04
#define MIXNDX_FILTER 0x08
#define MIXNDX_LINEARSRC 0x10
#define MIXNDX_SPLINESRC 0x20
#define MIXNDX_FIRSRC 0x30
const LPMIXINTERFACE gpMixFunctionTable[2*2*16] =
{
// No SRC
Mono8BitMix, Mono16BitMix, Stereo8BitMix, Stereo16BitMix,
Mono8BitRampMix, Mono16BitRampMix, Stereo8BitRampMix, Stereo16BitRampMix,
// No SRC, Filter
FilterMono8BitMix, FilterMono16BitMix, FilterStereo8BitMix, FilterStereo16BitMix,
FilterMono8BitRampMix, FilterMono16BitRampMix, FilterStereo8BitRampMix,FilterStereo16BitRampMix,
// Linear SRC
Mono8BitLinearMix, Mono16BitLinearMix, Stereo8BitLinearMix, Stereo16BitLinearMix,
Mono8BitLinearRampMix, Mono16BitLinearRampMix, Stereo8BitLinearRampMix,Stereo16BitLinearRampMix,
// Linear SRC, Filter
FilterMono8BitLinearMix, FilterMono16BitLinearMix, FilterStereo8BitLinearMix, FilterStereo16BitLinearMix,
FilterMono8BitLinearRampMix,FilterMono16BitLinearRampMix,FilterStereo8BitLinearRampMix,FilterStereo16BitLinearRampMix,
// FirFilter SRC
Mono8BitSplineMix, Mono16BitSplineMix, Stereo8BitSplineMix, Stereo16BitSplineMix,
Mono8BitSplineRampMix, Mono16BitSplineRampMix, Stereo8BitSplineRampMix,Stereo16BitSplineRampMix,
// Spline SRC, Filter
FilterMono8BitSplineMix, FilterMono16BitSplineMix, FilterStereo8BitSplineMix, FilterStereo16BitSplineMix,
FilterMono8BitSplineRampMix,FilterMono16BitSplineRampMix,FilterStereo8BitSplineRampMix,FilterStereo16BitSplineRampMix,
// FirFilter SRC
Mono8BitFirFilterMix, Mono16BitFirFilterMix, Stereo8BitFirFilterMix, Stereo16BitFirFilterMix,
Mono8BitFirFilterRampMix, Mono16BitFirFilterRampMix, Stereo8BitFirFilterRampMix,Stereo16BitFirFilterRampMix,
// FirFilter SRC, Filter
FilterMono8BitFirFilterMix, FilterMono16BitFirFilterMix, FilterStereo8BitFirFilterMix, FilterStereo16BitFirFilterMix,
FilterMono8BitFirFilterRampMix,FilterMono16BitFirFilterRampMix,FilterStereo8BitFirFilterRampMix,FilterStereo16BitFirFilterRampMix
};
const LPMIXINTERFACE gpFastMixFunctionTable[2*2*16] =
{
// No SRC
FastMono8BitMix, FastMono16BitMix, Stereo8BitMix, Stereo16BitMix,
FastMono8BitRampMix, FastMono16BitRampMix, Stereo8BitRampMix, Stereo16BitRampMix,
// No SRC, Filter
FilterMono8BitMix, FilterMono16BitMix, FilterStereo8BitMix, FilterStereo16BitMix,
FilterMono8BitRampMix, FilterMono16BitRampMix, FilterStereo8BitRampMix,FilterStereo16BitRampMix,
// Linear SRC
FastMono8BitLinearMix, FastMono16BitLinearMix, Stereo8BitLinearMix, Stereo16BitLinearMix,
FastMono8BitLinearRampMix, FastMono16BitLinearRampMix, Stereo8BitLinearRampMix,Stereo16BitLinearRampMix,
// Linear SRC, Filter
FilterMono8BitLinearMix, FilterMono16BitLinearMix, FilterStereo8BitLinearMix, FilterStereo16BitLinearMix,
FilterMono8BitLinearRampMix,FilterMono16BitLinearRampMix,FilterStereo8BitLinearRampMix,FilterStereo16BitLinearRampMix,
// Spline SRC
Mono8BitSplineMix, Mono16BitSplineMix, Stereo8BitSplineMix, Stereo16BitSplineMix,
Mono8BitSplineRampMix, Mono16BitSplineRampMix, Stereo8BitSplineRampMix,Stereo16BitSplineRampMix,
// Spline SRC, Filter
FilterMono8BitSplineMix, FilterMono16BitSplineMix, FilterStereo8BitSplineMix, FilterStereo16BitSplineMix,
FilterMono8BitSplineRampMix,FilterMono16BitSplineRampMix,FilterStereo8BitSplineRampMix,FilterStereo16BitSplineRampMix,
// FirFilter SRC
Mono8BitFirFilterMix, Mono16BitFirFilterMix, Stereo8BitFirFilterMix, Stereo16BitFirFilterMix,
Mono8BitFirFilterRampMix, Mono16BitFirFilterRampMix, Stereo8BitFirFilterRampMix,Stereo16BitFirFilterRampMix,
// FirFilter SRC, Filter
FilterMono8BitFirFilterMix, FilterMono16BitFirFilterMix, FilterStereo8BitFirFilterMix, FilterStereo16BitFirFilterMix,
FilterMono8BitFirFilterRampMix,FilterMono16BitFirFilterRampMix,FilterStereo8BitFirFilterRampMix,FilterStereo16BitFirFilterRampMix,
};
/////////////////////////////////////////////////////////////////////////
static LONG MPPFASTCALL GetSampleCount(MODCHANNEL *pChn, LONG nSamples)
//---------------------------------------------------------------------
{
LONG nLoopStart = (pChn->dwFlags & CHN_LOOP) ? pChn->nLoopStart : 0;
LONG nInc = pChn->nInc;
if ((nSamples <= 0) || (!nInc) || (!pChn->nLength)) return 0;
// Under zero ?
if ((LONG)pChn->nPos < nLoopStart)
{
if (nInc < 0)
{
// Invert loop for bidi loops
LONG nDelta = ((nLoopStart - pChn->nPos) << 16) - (pChn->nPosLo & 0xffff);
pChn->nPos = nLoopStart | (nDelta>>16);
pChn->nPosLo = nDelta & 0xffff;
if (((LONG)pChn->nPos < nLoopStart) || (pChn->nPos >= (nLoopStart+pChn->nLength)/2))
{
pChn->nPos = nLoopStart; pChn->nPosLo = 0;
}
nInc = -nInc;
pChn->nInc = nInc;
pChn->dwFlags &= ~(CHN_PINGPONGFLAG); // go forward
if ((!(pChn->dwFlags & CHN_LOOP)) || (pChn->nPos >= pChn->nLength))
{
pChn->nPos = pChn->nLength;
pChn->nPosLo = 0;
return 0;
}
} else
{
// We probably didn't hit the loop end yet (first loop), so we do nothing
if ((LONG)pChn->nPos < 0) pChn->nPos = 0;
}
} else
// Past the end
if (pChn->nPos >= pChn->nLength)
{
if (!(pChn->dwFlags & CHN_LOOP)) return 0; // not looping -> stop this channel
if (pChn->dwFlags & CHN_PINGPONGLOOP)
{
// Invert loop
if (nInc > 0)
{
nInc = -nInc;
pChn->nInc = nInc;
}
pChn->dwFlags |= CHN_PINGPONGFLAG;
// adjust loop position
LONG nDeltaHi = (pChn->nPos - pChn->nLength);
LONG nDeltaLo = 0x10000 - (pChn->nPosLo & 0xffff);
pChn->nPos = pChn->nLength - nDeltaHi - (nDeltaLo>>16);
pChn->nPosLo = nDeltaLo & 0xffff;
if ((pChn->nPos <= pChn->nLoopStart) || (pChn->nPos >= pChn->nLength)) pChn->nPos = pChn->nLength-1;
} else
{
if (nInc < 0) // This is a bug
{
nInc = -nInc;
pChn->nInc = nInc;
}
// Restart at loop start
pChn->nPos += nLoopStart - pChn->nLength;
if ((LONG)pChn->nPos < nLoopStart) pChn->nPos = pChn->nLoopStart;
}
}
LONG nPos = pChn->nPos;
// too big increment, and/or too small loop length
if (nPos < nLoopStart)
{
if ((nPos < 0) || (nInc < 0)) return 0;
}
if ((nPos < 0) || (nPos >= (LONG)pChn->nLength)) return 0;
LONG nPosLo = (USHORT)pChn->nPosLo, nSmpCount = nSamples;
if (nInc < 0)
{
LONG nInv = -nInc;
LONG maxsamples = 16384 / ((nInv>>16)+1);
if (maxsamples < 2) maxsamples = 2;
if (nSamples > maxsamples) nSamples = maxsamples;
LONG nDeltaHi = (nInv>>16) * (nSamples - 1);
LONG nDeltaLo = (nInv&0xffff) * (nSamples - 1);
LONG nPosDest = nPos - nDeltaHi + ((nPosLo - nDeltaLo) >> 16);
if (nPosDest < nLoopStart)
{
nSmpCount = (ULONG)(((((LONGLONG)nPos - nLoopStart) << 16) + nPosLo - 1) / nInv) + 1;
}
} else
{
LONG maxsamples = 16384 / ((nInc>>16)+1);
if (maxsamples < 2) maxsamples = 2;
if (nSamples > maxsamples) nSamples = maxsamples;
LONG nDeltaHi = (nInc>>16) * (nSamples - 1);
LONG nDeltaLo = (nInc&0xffff) * (nSamples - 1);
LONG nPosDest = nPos + nDeltaHi + ((nPosLo + nDeltaLo)>>16);
if (nPosDest >= (LONG)pChn->nLength)
{
nSmpCount = (ULONG)(((((LONGLONG)pChn->nLength - nPos) << 16) - nPosLo - 1) / nInc) + 1;
}
}
if (nSmpCount <= 1) return 1;
if (nSmpCount > nSamples) return nSamples;
return nSmpCount;
}
UINT CSoundFile::CreateStereoMix(int count)
//-----------------------------------------
{
LPLONG pOfsL, pOfsR;
DWORD nchused, nchmixed;
if (!count) return 0;
#ifndef FASTSOUNDLIB
if (gnChannels > 2) X86_InitMixBuffer(MixRearBuffer, count*2);
#endif
nchused = nchmixed = 0;
for (UINT nChn=0; nChn<m_nMixChannels; nChn++)
{
const LPMIXINTERFACE *pMixFuncTable;
MODCHANNEL * const pChannel = &Chn[ChnMix[nChn]];
UINT nFlags, nMasterCh;
LONG nSmpCount;
int nsamples;
int *pbuffer;
if (!pChannel->pCurrentSample) continue;
nMasterCh = (ChnMix[nChn] < m_nChannels) ? ChnMix[nChn]+1 : pChannel->nMasterChn;
pOfsR = &gnDryROfsVol;
pOfsL = &gnDryLOfsVol;
nFlags = 0;
if (pChannel->dwFlags & CHN_16BIT) nFlags |= MIXNDX_16BIT;
if (pChannel->dwFlags & CHN_STEREO) nFlags |= MIXNDX_STEREO;
#ifndef NO_FILTER
if (pChannel->dwFlags & CHN_FILTER) nFlags |= MIXNDX_FILTER;
#endif
if (!(pChannel->dwFlags & CHN_NOIDO))
{
// use hq-fir mixer?
if( (gdwSoundSetup & (SNDMIX_HQRESAMPLER|SNDMIX_ULTRAHQSRCMODE)) == (SNDMIX_HQRESAMPLER|SNDMIX_ULTRAHQSRCMODE) )
nFlags += MIXNDX_FIRSRC;
else if( (gdwSoundSetup & (SNDMIX_HQRESAMPLER)) == SNDMIX_HQRESAMPLER )
nFlags += MIXNDX_SPLINESRC;
else
nFlags += MIXNDX_LINEARSRC; // use
}
if ((nFlags < 0x40) && (pChannel->nLeftVol == pChannel->nRightVol)
&& ((!pChannel->nRampLength) || (pChannel->nLeftRamp == pChannel->nRightRamp)))
{
pMixFuncTable = gpFastMixFunctionTable;
} else
{
pMixFuncTable = gpMixFunctionTable;
}
nsamples = count;
#ifndef NO_REVERB
pbuffer = (gdwSoundSetup & SNDMIX_REVERB) ? MixReverbBuffer : MixSoundBuffer;
if (pChannel->dwFlags & CHN_NOREVERB) pbuffer = MixSoundBuffer;
if (pChannel->dwFlags & CHN_REVERB) pbuffer = MixReverbBuffer;
if (pbuffer == MixReverbBuffer)
{
if (!gnReverbSend) memset(MixReverbBuffer, 0, count * 8);
gnReverbSend += count;
}
#else
pbuffer = MixSoundBuffer;
#endif
nchused++;
////////////////////////////////////////////////////
SampleLooping:
UINT nrampsamples = nsamples;
if (pChannel->nRampLength > 0)
{
if ((LONG)nrampsamples > pChannel->nRampLength) nrampsamples = pChannel->nRampLength;
}
if ((nSmpCount = GetSampleCount(pChannel, nrampsamples)) <= 0)
{
// Stopping the channel
pChannel->pCurrentSample = NULL;
pChannel->nLength = 0;
pChannel->nPos = 0;
pChannel->nPosLo = 0;
pChannel->nRampLength = 0;
X86_EndChannelOfs(pChannel, pbuffer, nsamples);
*pOfsR += pChannel->nROfs;
*pOfsL += pChannel->nLOfs;
pChannel->nROfs = pChannel->nLOfs = 0;
pChannel->dwFlags &= ~CHN_PINGPONGFLAG;
continue;
}
// Should we mix this channel ?
UINT naddmix;
if (((nchmixed >= m_nMaxMixChannels) && (!(gdwSoundSetup & SNDMIX_DIRECTTODISK)))
|| ((!pChannel->nRampLength) && (!(pChannel->nLeftVol|pChannel->nRightVol))))
{
LONG delta = (pChannel->nInc * (LONG)nSmpCount) + (LONG)pChannel->nPosLo;
pChannel->nPosLo = delta & 0xFFFF;
pChannel->nPos += (delta >> 16);
pChannel->nROfs = pChannel->nLOfs = 0;
pbuffer += nSmpCount*2;
naddmix = 0;
} else
// Do mixing
{
// Choose function for mixing
LPMIXINTERFACE pMixFunc;
pMixFunc = (pChannel->nRampLength) ? pMixFuncTable[nFlags|MIXNDX_RAMP] : pMixFuncTable[nFlags];
int *pbufmax = pbuffer + (nSmpCount*2);
pChannel->nROfs = - *(pbufmax-2);
pChannel->nLOfs = - *(pbufmax-1);
pMixFunc(pChannel, pbuffer, pbufmax);
pChannel->nROfs += *(pbufmax-2);
pChannel->nLOfs += *(pbufmax-1);
pbuffer = pbufmax;
naddmix = 1;
}
nsamples -= nSmpCount;
if (pChannel->nRampLength)
{
pChannel->nRampLength -= nSmpCount;
if (pChannel->nRampLength <= 0)
{
pChannel->nRampLength = 0;
pChannel->nRightVol = pChannel->nNewRightVol;
pChannel->nLeftVol = pChannel->nNewLeftVol;
pChannel->nRightRamp = pChannel->nLeftRamp = 0;
if ((pChannel->dwFlags & CHN_NOTEFADE) && (!(pChannel->nFadeOutVol)))
{
pChannel->nLength = 0;
pChannel->pCurrentSample = NULL;
}
}
}
if (nsamples > 0) goto SampleLooping;
nchmixed += naddmix;
}
return nchused;
}
#ifdef MSC_VER
#pragma warning (disable:4100)
#endif
// Clip and convert to 8 bit
#ifdef MSC_VER
__declspec(naked) DWORD MPPASMCALL X86_Convert32To8(LPVOID lp16, int *pBuffer, DWORD lSampleCount, LPLONG lpMin, LPLONG lpMax)
//----------------------------------------------------------------------------------------------------------------------------
{
_asm {
push ebx
push esi
push edi
mov ebx, 16[esp] // ebx = 8-bit buffer
mov esi, 20[esp] // esi = pBuffer
mov edi, 24[esp] // edi = lSampleCount
mov eax, 28[esp]
mov ecx, dword ptr [eax] // ecx = clipmin
mov eax, 32[esp]
mov edx, dword ptr [eax] // edx = clipmax
cliploop:
mov eax, dword ptr [esi]
inc ebx
cdq
and edx, (1 << (24-MIXING_ATTENUATION)) - 1
add eax, edx
cmp eax, MIXING_CLIPMIN
jl cliplow
cmp eax, MIXING_CLIPMAX
jg cliphigh
cmp eax, ecx
jl updatemin
cmp eax, edx
jg updatemax
cliprecover:
add esi, 4
sar eax, 24-MIXING_ATTENUATION
xor eax, 0x80
dec edi
mov byte ptr [ebx-1], al
jnz cliploop
mov eax, 28[esp]
mov dword ptr [eax], ecx
mov eax, 32[esp]
mov dword ptr [eax], edx
mov eax, 24[esp]
pop edi
pop esi
pop ebx
ret
updatemin:
mov ecx, eax
jmp cliprecover
updatemax:
mov edx, eax
jmp cliprecover
cliplow:
mov ecx, MIXING_CLIPMIN
mov edx, MIXING_CLIPMAX
mov eax, MIXING_CLIPMIN
jmp cliprecover
cliphigh:
mov ecx, MIXING_CLIPMIN
mov edx, MIXING_CLIPMAX
mov eax, MIXING_CLIPMAX
jmp cliprecover
}
}
#else //MSC_VER
//---GCCFIX: Asm replaced with C function
// The C version was written by Rani Assaf <rani@magic.metawire.com>, I believe
DWORD MPPASMCALL X86_Convert32To8(LPVOID lp8, int *pBuffer, DWORD lSampleCount, LPLONG lpMin, LPLONG lpMax)
{
int vumin = *lpMin, vumax = *lpMax;
unsigned char *p = (unsigned char *)lp8;
for (UINT i=0; i<lSampleCount; i++)
{
int n = pBuffer[i];
if (n < MIXING_CLIPMIN)
n = MIXING_CLIPMIN;
else if (n > MIXING_CLIPMAX)
n = MIXING_CLIPMAX;
if (n < vumin)
vumin = n;
else if (n > vumax)
vumax = n;
p[i] = (n >> (24-MIXING_ATTENUATION)) ^ 0x80; // 8-bit unsigned
}
*lpMin = vumin;
*lpMax = vumax;
return lSampleCount;
}
#endif //MSC_VER, else
#ifdef MSC_VER
// Clip and convert to 16 bit
__declspec(naked) DWORD MPPASMCALL X86_Convert32To16(LPVOID lp16, int *pBuffer, DWORD lSampleCount, LPLONG lpMin, LPLONG lpMax)
//-----------------------------------------------------------------------------------------------------------------------------
{
_asm {
push ebx
push esi
push edi
mov ebx, 16[esp] // ebx = 16-bit buffer
mov eax, 28[esp]
mov esi, 20[esp] // esi = pBuffer
mov ecx, dword ptr [eax] // ecx = clipmin
mov edi, 24[esp] // edi = lSampleCount
mov eax, 32[esp]
push ebp
mov ebp, dword ptr [eax] // edx = clipmax
cliploop:
mov eax, dword ptr [esi]
add ebx, 2
cdq
and edx, (1 << (16-MIXING_ATTENUATION)) - 1
add esi, 4
add eax, edx
cmp eax, MIXING_CLIPMIN
jl cliplow
cmp eax, MIXING_CLIPMAX
jg cliphigh
cmp eax, ecx
jl updatemin
cmp eax, ebp
jg updatemax
cliprecover:
sar eax, 16-MIXING_ATTENUATION
dec edi
mov word ptr [ebx-2], ax
jnz cliploop
mov edx, ebp
pop ebp
mov eax, 28[esp]
mov dword ptr [eax], ecx
mov eax, 32[esp]
mov dword ptr [eax], edx
mov eax, 24[esp]
pop edi
shl eax, 1
pop esi
pop ebx
ret
updatemin:
mov ecx, eax
jmp cliprecover
updatemax:
mov ebp, eax
jmp cliprecover
cliplow:
mov ecx, MIXING_CLIPMIN
mov ebp, MIXING_CLIPMAX
mov eax, MIXING_CLIPMIN
jmp cliprecover
cliphigh:
mov ecx, MIXING_CLIPMIN
mov ebp, MIXING_CLIPMAX
mov eax, MIXING_CLIPMAX
jmp cliprecover
}
}
#else //MSC_VER
//---GCCFIX: Asm replaced with C function
// The C version was written by Rani Assaf <rani@magic.metawire.com>, I believe
DWORD MPPASMCALL X86_Convert32To16(LPVOID lp16, int *pBuffer, DWORD lSampleCount, LPLONG lpMin, LPLONG lpMax)
{
int vumin = *lpMin, vumax = *lpMax;
signed short *p = (signed short *)lp16;
for (UINT i=0; i<lSampleCount; i++)
{
int n = pBuffer[i];
if (n < MIXING_CLIPMIN)
n = MIXING_CLIPMIN;
else if (n > MIXING_CLIPMAX)
n = MIXING_CLIPMAX;
if (n < vumin)
vumin = n;
else if (n > vumax)
vumax = n;
p[i] = n >> (16-MIXING_ATTENUATION); // 16-bit signed
}
*lpMin = vumin;
*lpMax = vumax;
return lSampleCount * 2;
}
#endif //MSC_VER, else
#ifdef MSC_VER
// Clip and convert to 24 bit
__declspec(naked) DWORD MPPASMCALL X86_Convert32To24(LPVOID lp16, int *pBuffer, DWORD lSampleCount, LPLONG lpMin, LPLONG lpMax)
//-----------------------------------------------------------------------------------------------------------------------------
{
_asm {
push ebx
push esi
push edi
mov ebx, 16[esp] // ebx = 8-bit buffer
mov esi, 20[esp] // esi = pBuffer
mov edi, 24[esp] // edi = lSampleCount
mov eax, 28[esp]
mov ecx, dword ptr [eax] // ecx = clipmin
mov eax, 32[esp]
push ebp
mov edx, dword ptr [eax] // edx = clipmax
cliploop:
mov eax, dword ptr [esi]
mov ebp, eax
sar ebp, 31
and ebp, (1 << (8-MIXING_ATTENUATION)) - 1
add eax, ebp
cmp eax, MIXING_CLIPMIN
jl cliplow
cmp eax, MIXING_CLIPMAX
jg cliphigh
cmp eax, ecx
jl updatemin
cmp eax, edx
jg updatemax
cliprecover:
add ebx, 3
sar eax, 8-MIXING_ATTENUATION
add esi, 4
mov word ptr [ebx-3], ax
shr eax, 16
dec edi
mov byte ptr [ebx-1], al
jnz cliploop
pop ebp
mov eax, 28[esp]
mov dword ptr [eax], ecx
mov eax, 32[esp]
mov dword ptr [eax], edx
mov edx, 24[esp]
mov eax, edx
pop edi
shl eax, 1
pop esi
add eax, edx
pop ebx
ret
updatemin:
mov ecx, eax
jmp cliprecover
updatemax:
mov edx, eax
jmp cliprecover
cliplow:
mov ecx, MIXING_CLIPMIN
mov edx, MIXING_CLIPMAX
mov eax, MIXING_CLIPMIN
jmp cliprecover
cliphigh:
mov ecx, MIXING_CLIPMIN
mov edx, MIXING_CLIPMAX
mov eax, MIXING_CLIPMAX
jmp cliprecover
}
}
#else //MSC_VER
//---GCCFIX: Asm replaced with C function
// 24-bit audio not supported.
DWORD MPPASMCALL X86_Convert32To24(LPVOID lp16, int *pBuffer, DWORD lSampleCount, LPLONG lpMin, LPLONG lpMax)
{
return 0;
}
#endif
#ifdef MSC_VER
// Clip and convert to 32 bit
__declspec(naked) DWORD MPPASMCALL X86_Convert32To32(LPVOID lp16, int *pBuffer, DWORD lSampleCount, LPLONG lpMin, LPLONG lpMax)
//-----------------------------------------------------------------------------------------------------------------------------
{
_asm {
push ebx
push esi
push edi
mov ebx, 16[esp] // ebx = 32-bit buffer
mov esi, 20[esp] // esi = pBuffer
mov edi, 24[esp] // edi = lSampleCount
mov eax, 28[esp]
mov ecx, dword ptr [eax] // ecx = clipmin
mov eax, 32[esp]
mov edx, dword ptr [eax] // edx = clipmax
cliploop:
mov eax, dword ptr [esi]
add ebx, 4
add esi, 4
cmp eax, MIXING_CLIPMIN
jl cliplow
cmp eax, MIXING_CLIPMAX
jg cliphigh
cmp eax, ecx
jl updatemin
cmp eax, edx
jg updatemax
cliprecover:
shl eax, MIXING_ATTENUATION
dec edi
mov dword ptr [ebx-4], eax
jnz cliploop
mov eax, 28[esp]
mov dword ptr [eax], ecx
mov eax, 32[esp]
mov dword ptr [eax], edx
mov edx, 24[esp]
pop edi
mov eax, edx
pop esi
shl eax, 2
pop ebx
ret
updatemin:
mov ecx, eax
jmp cliprecover
updatemax:
mov edx, eax
jmp cliprecover
cliplow:
mov ecx, MIXING_CLIPMIN
mov edx, MIXING_CLIPMAX
mov eax, MIXING_CLIPMIN
jmp cliprecover
cliphigh:
mov ecx, MIXING_CLIPMIN
mov edx, MIXING_CLIPMAX
mov eax, MIXING_CLIPMAX
jmp cliprecover
}
}
#else
//---GCCFIX: Asm replaced with C function
// 32-bit audio not supported
DWORD MPPASMCALL X86_Convert32To32(LPVOID lp16, int *pBuffer, DWORD lSampleCount, LPLONG lpMin, LPLONG lpMax)
{
return 0;
}
#endif
#ifdef MSC_VER
void MPPASMCALL X86_InitMixBuffer(int *pBuffer, UINT nSamples)
//------------------------------------------------------------
{
_asm {
mov ecx, nSamples
mov esi, pBuffer
xor eax, eax
mov edx, ecx
shr ecx, 2
and edx, 3
jz unroll4x
loop1x:
add esi, 4
dec edx
mov dword ptr [esi-4], eax
jnz loop1x
unroll4x:
or ecx, ecx
jnz loop4x
jmp done
loop4x:
add esi, 16
dec ecx
mov dword ptr [esi-16], eax
mov dword ptr [esi-12], eax
mov dword ptr [esi-8], eax
mov dword ptr [esi-4], eax
jnz loop4x
done:;
}
}
#else
//---GCCFIX: Asm replaced with C function
// Will fill in later.
void MPPASMCALL X86_InitMixBuffer(int *pBuffer, UINT nSamples)
{
memset(pBuffer, 0, nSamples * sizeof(int));
}
#endif
#ifdef MSC_VER
__declspec(naked) void MPPASMCALL X86_InterleaveFrontRear(int *pFrontBuf, int *pRearBuf, DWORD nSamples)
//------------------------------------------------------------------------------------------------------
{
_asm {
push ebx
push ebp
push esi
push edi
mov ecx, 28[esp] // ecx = samplecount
mov esi, 20[esp] // esi = front buffer
mov edi, 24[esp] // edi = rear buffer
lea esi, [esi+ecx*4] // esi = &front[N]
lea edi, [edi+ecx*4] // edi = &rear[N]
lea ebx, [esi+ecx*4] // ebx = &front[N*2]
interleaveloop:
mov eax, dword ptr [esi-8]
mov edx, dword ptr [esi-4]
sub ebx, 16
mov ebp, dword ptr [edi-8]
mov dword ptr [ebx], eax
mov dword ptr [ebx+4], edx
mov eax, dword ptr [edi-4]
sub esi, 8
sub edi, 8
dec ecx
mov dword ptr [ebx+8], ebp
mov dword ptr [ebx+12], eax
jnz interleaveloop
pop edi
pop esi
pop ebp
pop ebx
ret
}
}
#else
//---GCCFIX: Asm replaced with C function
// Multichannel not supported.
void MPPASMCALL X86_InterleaveFrontRear(int *pFrontBuf, int *pRearBuf, DWORD nSamples)
{
}
#endif
#ifdef MSC_VER
VOID MPPASMCALL X86_MonoFromStereo(int *pMixBuf, UINT nSamples)
//-------------------------------------------------------------
{
_asm {
mov ecx, nSamples
mov esi, pMixBuf
mov edi, esi
stloop:
mov eax, dword ptr [esi]
mov edx, dword ptr [esi+4]
add edi, 4
add esi, 8
add eax, edx
sar eax, 1
dec ecx
mov dword ptr [edi-4], eax
jnz stloop
}
}
#else
//---GCCFIX: Asm replaced with C function
VOID MPPASMCALL X86_MonoFromStereo(int *pMixBuf, UINT nSamples)
{
UINT j;
for(UINT i = 0; i < nSamples; i++)
{
j = i << 1;
pMixBuf[i] = (pMixBuf[j] + pMixBuf[j + 1]) >> 1;
}
}
#endif
#define OFSDECAYSHIFT 8
#define OFSDECAYMASK 0xFF
#ifdef MSC_VER
void MPPASMCALL X86_StereoFill(int *pBuffer, UINT nSamples, LPLONG lpROfs, LPLONG lpLOfs)
//---------------------------------------------------------------------------------------
{
_asm {
mov edi, pBuffer
mov ecx, nSamples
mov eax, lpROfs
mov edx, lpLOfs
mov eax, [eax]
mov edx, [edx]
or ecx, ecx
jz fill_loop
mov ebx, eax
or ebx, edx
jz fill_loop
ofsloop:
mov ebx, eax
mov esi, edx
neg ebx
neg esi
sar ebx, 31
sar esi, 31
and ebx, OFSDECAYMASK
and esi, OFSDECAYMASK
add ebx, eax
add esi, edx
sar ebx, OFSDECAYSHIFT
sar esi, OFSDECAYSHIFT
sub eax, ebx
sub edx, esi
mov ebx, eax
or ebx, edx
jz fill_loop
add edi, 8
dec ecx
mov [edi-8], eax
mov [edi-4], edx
jnz ofsloop
fill_loop:
mov ebx, ecx
and ebx, 3
jz fill4x
fill1x:
mov [edi], eax
mov [edi+4], edx
add edi, 8
dec ebx
jnz fill1x
fill4x:
shr ecx, 2
or ecx, ecx
jz done
fill4xloop:
mov [edi], eax
mov [edi+4], edx
mov [edi+8], eax
mov [edi+12], edx
add edi, 8*4
dec ecx
mov [edi-16], eax
mov [edi-12], edx
mov [edi-8], eax
mov [edi-4], edx
jnz fill4xloop
done:
mov esi, lpROfs
mov edi, lpLOfs
mov [esi], eax
mov [edi], edx
}
}
#else
//---GCCFIX: Asm replaced with C function
#define OFSDECAYSHIFT 8
#define OFSDECAYMASK 0xFF
void MPPASMCALL X86_StereoFill(int *pBuffer, UINT nSamples, LPLONG lpROfs, LPLONG lpLOfs)
//---------------------------------------------------------------------------------------------------------
{
int rofs = *lpROfs;
int lofs = *lpLOfs;
if ((!rofs) && (!lofs))
{
X86_InitMixBuffer(pBuffer, nSamples*2);
return;
}
for (UINT i=0; i<nSamples; i++)
{
int x_r = (rofs + (((-rofs)>>31) & OFSDECAYMASK)) >> OFSDECAYSHIFT;
int x_l = (lofs + (((-lofs)>>31) & OFSDECAYMASK)) >> OFSDECAYSHIFT;
rofs -= x_r;
lofs -= x_l;
pBuffer[i*2] = x_r;
pBuffer[i*2+1] = x_l;
}
*lpROfs = rofs;
*lpLOfs = lofs;
}
#endif
#ifdef MSC_VER
void MPPASMCALL X86_EndChannelOfs(MODCHANNEL *pChannel, int *pBuffer, UINT nSamples)
//----------------------------------------------------------------------------------
{
_asm {
mov esi, pChannel
mov edi, pBuffer
mov ecx, nSamples
mov eax, dword ptr [esi+MODCHANNEL.nROfs]
mov edx, dword ptr [esi+MODCHANNEL.nLOfs]
or ecx, ecx
jz brkloop
ofsloop:
mov ebx, eax
mov esi, edx
neg ebx
neg esi
sar ebx, 31
sar esi, 31
and ebx, OFSDECAYMASK
and esi, OFSDECAYMASK
add ebx, eax
add esi, edx
sar ebx, OFSDECAYSHIFT
sar esi, OFSDECAYSHIFT
sub eax, ebx
sub edx, esi
mov ebx, eax
add dword ptr [edi], eax
add dword ptr [edi+4], edx
or ebx, edx
jz brkloop
add edi, 8
dec ecx
jnz ofsloop
brkloop:
mov esi, pChannel
mov dword ptr [esi+MODCHANNEL.nROfs], eax
mov dword ptr [esi+MODCHANNEL.nLOfs], edx
}
}
#else
//---GCCFIX: Asm replaced with C function
// Will fill in later.
void MPPASMCALL X86_EndChannelOfs(MODCHANNEL *pChannel, int *pBuffer, UINT nSamples)
{
int rofs = pChannel->nROfs;
int lofs = pChannel->nLOfs;
if ((!rofs) && (!lofs)) return;
for (UINT i=0; i<nSamples; i++)
{
int x_r = (rofs + (((-rofs)>>31) & OFSDECAYMASK)) >> OFSDECAYSHIFT;
int x_l = (lofs + (((-lofs)>>31) & OFSDECAYMASK)) >> OFSDECAYSHIFT;
rofs -= x_r;
lofs -= x_l;
pBuffer[i*2] += x_r;
pBuffer[i*2+1] += x_l;
}
pChannel->nROfs = rofs;
pChannel->nLOfs = lofs;
}
#endif
//////////////////////////////////////////////////////////////////////////////////
// Automatic Gain Control
#ifndef NO_AGC
// Limiter
#define MIXING_LIMITMAX (0x08100000)
#define MIXING_LIMITMIN (-MIXING_LIMITMAX)
__declspec(naked) UINT MPPASMCALL X86_AGC(int *pBuffer, UINT nSamples, UINT nAGC)
//-------------------------------------------------------------------------------
{
__asm {
push ebx
push ebp
push esi
push edi
mov esi, 20[esp] // esi = pBuffer+i
mov ecx, 24[esp] // ecx = i
mov edi, 28[esp] // edi = AGC (0..256)
agcloop:
mov eax, dword ptr [esi]
imul edi
shrd eax, edx, AGC_PRECISION
add esi, 4
cmp eax, MIXING_LIMITMIN
jl agcupdate
cmp eax, MIXING_LIMITMAX
jg agcupdate
agcrecover:
dec ecx
mov dword ptr [esi-4], eax
jnz agcloop
mov eax, edi
pop edi
pop esi
pop ebp
pop ebx
ret
agcupdate:
dec edi
jmp agcrecover
}
}
#pragma warning (default:4100)
void CSoundFile::ProcessAGC(int count)
//------------------------------------
{
static DWORD gAGCRecoverCount = 0;
UINT agc = X86_AGC(MixSoundBuffer, count, gnAGC);
// Some kind custom law, so that the AGC stays quite stable, but slowly
// goes back up if the sound level stays below a level inversely proportional
// to the AGC level. (J'me comprends)
if ((agc >= gnAGC) && (gnAGC < AGC_UNITY) && (gnVUMeter < (0xFF - (gnAGC >> (AGC_PRECISION-7))) ))
{
gAGCRecoverCount += count;
UINT agctimeout = gdwMixingFreq + gnAGC;
if (gnChannels >= 2) agctimeout <<= 1;
if (gAGCRecoverCount >= agctimeout)
{
gAGCRecoverCount = 0;
gnAGC++;
}
} else
{
gnAGC = agc;
gAGCRecoverCount = 0;
}
}
void CSoundFile::ResetAGC()
//-------------------------
{
gnAGC = AGC_UNITY;
}
#endif // NO_AGC