/* * This program is free software; you can redistribute it and 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. * * Authors: Olivier Lapicque * Markus Fick spline + fir-resampler */ #include "stdafx.h" #include "sndfile.h" #include #ifdef WIN32 #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 WIN32 #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< _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<>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)_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<> 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; nChnpCurrentSample) 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 WIN32 #pragma warning (disable:4100) #endif // Clip and convert to 8 bit #ifdef WIN32 __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 //WIN32 //---GCCFIX: Asm replaced with C function // The C version was written by Rani Assaf , I believe __declspec(naked) 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 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 //WIN32, else #ifdef WIN32 // 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 //WIN32 //---GCCFIX: Asm replaced with C function // The C version was written by Rani Assaf , I believe __declspec(naked) 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 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 //WIN32, else #ifdef WIN32 // 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 //WIN32 //---GCCFIX: Asm replaced with C function // 24-bit audio not supported. __declspec(naked) DWORD MPPASMCALL X86_Convert32To24(LPVOID lp16, int *pBuffer, DWORD lSampleCount, LPLONG lpMin, LPLONG lpMax) { return 0; } #endif #ifdef WIN32 // 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 __declspec(naked) DWORD MPPASMCALL X86_Convert32To32(LPVOID lp16, int *pBuffer, DWORD lSampleCount, LPLONG lpMin, LPLONG lpMax) { return 0; } #endif #ifdef WIN32 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 WIN32 __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. __declspec(naked) void MPPASMCALL X86_InterleaveFrontRear(int *pFrontBuf, int *pRearBuf, DWORD nSamples) { } #endif #ifdef WIN32 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 WIN32 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 __declspec(naked) 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>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 WIN32 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>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