From: <man...@us...> - 2013-04-11 18:10:12
|
Revision: 1844 http://sourceforge.net/p/modplug/code/1844 Author: manxorist Date: 2013-04-11 18:09:59 +0000 (Thu, 11 Apr 2013) Log Message: ----------- [Ref] Rename soundlib/Snd_rvb to sounddsp/Reverb. Modified Paths: -------------- trunk/OpenMPT/mptrack/TrackerSettings.h trunk/OpenMPT/mptrack/mptrack_08.vcproj trunk/OpenMPT/mptrack/mptrack_10.vcxproj trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters trunk/OpenMPT/soundlib/Sndfile.h Added Paths: ----------- trunk/OpenMPT/sounddsp/Reverb.cpp trunk/OpenMPT/sounddsp/Reverb.h Removed Paths: ------------- trunk/OpenMPT/soundlib/Snd_rvb.cpp trunk/OpenMPT/soundlib/snd_rvb.h Modified: trunk/OpenMPT/mptrack/TrackerSettings.h =================================================================== --- trunk/OpenMPT/mptrack/TrackerSettings.h 2013-04-11 17:21:26 UTC (rev 1843) +++ trunk/OpenMPT/mptrack/TrackerSettings.h 2013-04-11 18:09:59 UTC (rev 1844) @@ -15,7 +15,7 @@ #include "../soundlib/Resampler.h" #include "../sounddsp/EQ.h" #include "../sounddsp/DSP.h" -#include "../soundlib/snd_rvb.h" +#include "../sounddsp/Reverb.h" ///////////////////////////////////////////////////////////////////////// // Default directories Modified: trunk/OpenMPT/mptrack/mptrack_08.vcproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_08.vcproj 2013-04-11 17:21:26 UTC (rev 1843) +++ trunk/OpenMPT/mptrack/mptrack_08.vcproj 2013-04-11 18:09:59 UTC (rev 1844) @@ -513,16 +513,8 @@ > </File> <File - RelativePath="..\Soundlib\Snd_rvb.cpp" + RelativePath="..\sounddsp\Reverb.cpp" > - <FileConfiguration - Name="Release|Win32" - > - <Tool - Name="VCCLCompilerTool" - AssemblerOutput="4" - /> - </FileConfiguration> </File> <File RelativePath="..\Soundlib\snddev.cpp" @@ -1031,6 +1023,10 @@ > </File> <File + RelativePath="..\sounddsp\Reverb.h" + > + </File> + <File RelativePath=".\Resource.h" > </File> Modified: trunk/OpenMPT/mptrack/mptrack_10.vcxproj =================================================================== --- trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2013-04-11 17:21:26 UTC (rev 1843) +++ trunk/OpenMPT/mptrack/mptrack_10.vcxproj 2013-04-11 18:09:59 UTC (rev 1844) @@ -251,6 +251,7 @@ <ClCompile Include="..\sounddsp\AGC.cpp" /> <ClCompile Include="..\sounddsp\DSP.cpp" /> <ClCompile Include="..\sounddsp\EQ.cpp" /> + <ClCompile Include="..\sounddsp\Reverb.cpp" /> <ClCompile Include="..\soundlib\ITCompression.cpp" /> <ClCompile Include="..\soundlib\ITTools.cpp" /> <ClCompile Include="..\soundlib\MIDIEvents.cpp" /> @@ -331,7 +332,6 @@ <ClCompile Include="..\common\serialization_utils.cpp" /> <ClCompile Include="..\soundlib\snd_flt.cpp" /> <ClCompile Include="..\soundlib\Snd_fx.cpp" /> - <ClCompile Include="..\Soundlib\Snd_rvb.cpp" /> <ClCompile Include="..\Soundlib\snddev.cpp" /> <ClCompile Include="..\soundlib\Sndfile.cpp" /> <ClCompile Include="..\soundlib\Sndmix.cpp" /> @@ -410,6 +410,7 @@ <ClInclude Include="..\sounddsp\AGC.h" /> <ClInclude Include="..\sounddsp\DSP.h" /> <ClInclude Include="..\sounddsp\EQ.h" /> + <ClInclude Include="..\sounddsp\Reverb.h" /> <ClInclude Include="..\soundlib\ChunkReader.h" /> <ClInclude Include="..\soundlib\FileReader.h" /> <ClInclude Include="..\soundlib\ITCompression.h" /> @@ -428,7 +429,6 @@ <ClInclude Include="..\soundlib\RowVisitor.h" /> <ClInclude Include="..\soundlib\SampleFormatConverters.h" /> <ClInclude Include="..\soundlib\SampleIO.h" /> - <ClInclude Include="..\soundlib\snd_rvb.h" /> <ClInclude Include="..\soundlib\Tables.h" /> <ClInclude Include="..\soundlib\WAVTools.h" /> <ClInclude Include="..\soundlib\XMTools.h" /> Modified: trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters =================================================================== --- trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters 2013-04-11 17:21:26 UTC (rev 1843) +++ trunk/OpenMPT/mptrack/mptrack_10.vcxproj.filters 2013-04-11 18:09:59 UTC (rev 1844) @@ -250,9 +250,6 @@ <ClCompile Include="..\Soundlib\snddev.cpp"> <Filter>Source Files</Filter> </ClCompile> - <ClCompile Include="..\Soundlib\Snd_rvb.cpp"> - <Filter>Source Files</Filter> - </ClCompile> <ClCompile Include="..\soundlib\Snd_fx.cpp"> <Filter>Source Files</Filter> </ClCompile> @@ -430,6 +427,9 @@ <ClCompile Include="..\common\Profiler.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\sounddsp\Reverb.cpp"> + <Filter>Source Files\sounddsp</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="AbstractVstEditor.h"> @@ -762,9 +762,6 @@ <ClInclude Include="..\common\mutex.h"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="..\soundlib\snd_rvb.h"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="..\common\mptString.h"> <Filter>Header Files</Filter> </ClInclude> @@ -789,6 +786,9 @@ <ClInclude Include="..\common\Profiler.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\sounddsp\Reverb.h"> + <Filter>Header Files\sounddsp</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <None Include="res\bitmap1.bmp"> Copied: trunk/OpenMPT/sounddsp/Reverb.cpp (from rev 1843, trunk/OpenMPT/soundlib/Snd_rvb.cpp) =================================================================== --- trunk/OpenMPT/sounddsp/Reverb.cpp (rev 0) +++ trunk/OpenMPT/sounddsp/Reverb.cpp 2013-04-11 18:09:59 UTC (rev 1844) @@ -0,0 +1,1096 @@ +/* + * Reverb.cpp + * ---------- + * Purpose: Mixing code for reverb. + * Notes : Ugh... This should really be removed at some point. + * Authors: Olivier Lapicque + * OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + + +#include "stdafx.h" +#include "../soundlib/Sndfile.h" +#include "Reverb.h" + +#ifndef NO_REVERB + +#pragma warning(disable:4725) // Pentium fdiv bug +#pragma warning(disable:4731) // ebp modified + +extern VOID MPPASMCALL X86_StereoFill(int *pBuffer, UINT nSamples, LPLONG lpROfs, LPLONG lpLOfs); + + + +CReverbSettings::CReverbSettings() +//-------------------------------- +{ + m_nReverbType = 0; + m_nReverbDepth = 8; // 50% +} + + +CReverb::CReverb() +//---------------- +{ + + // Shared reverb state + gnReverbSamples = 0; + gnReverbDecaySamples = 0; + gnReverbSend = 0; + gnRvbROfsVol = 0; + gnRvbLOfsVol = 0; + + // Internal reverb state + g_bLastInPresent = 0; + g_bLastOutPresent = 0; + g_nLastRvbIn_xl = 0; + g_nLastRvbIn_xr = 0; + g_nLastRvbIn_yl = 0; + g_nLastRvbIn_yr = 0; + g_nLastRvbOut_xl = 0; + g_nLastRvbOut_xr = 0; + gnDCRRvb_Y1 = 0; + gnDCRRvb_X1 = 0; + + // Reverb mix buffers + MemsetZero(g_RefDelay); + MemsetZero(g_LateReverb); + +} + + +// Misc functions +static LONG OnePoleLowPassCoef(LONG scale, FLOAT g, FLOAT F_c, FLOAT F_s); +static LONG mBToLinear(LONG scale, LONG value_mB); +static FLOAT mBToLinear(LONG value_mB); + +struct SNDMIX_REVERB_PROPERTIES +{ + LONG lRoom; // [-10000, 0] default: -10000 mB + LONG lRoomHF; // [-10000, 0] default: 0 mB + FLOAT flDecayTime; // [0.1, 20.0] default: 1.0 s + FLOAT flDecayHFRatio; // [0.1, 2.0] default: 0.5 + LONG lReflections; // [-10000, 1000] default: -10000 mB + FLOAT flReflectionsDelay; // [0.0, 0.3] default: 0.02 s + LONG lReverb; // [-10000, 2000] default: -10000 mB + FLOAT flReverbDelay; // [0.0, 0.1] default: 0.04 s + FLOAT flDiffusion; // [0.0, 100.0] default: 100.0 % + FLOAT flDensity; // [0.0, 100.0] default: 100.0 % +}; +typedef SNDMIX_REVERB_PROPERTIES* PSNDMIX_REVERB_PROPERTIES; + +typedef struct _SNDMIX_RVBPRESET +{ + SNDMIX_REVERB_PROPERTIES Preset; + LPCSTR lpszName; +} SNDMIX_RVBPRESET, *PSNDMIX_RVBPRESET; + + +static SNDMIX_RVBPRESET gRvbPresets[NUM_REVERBTYPES] = +{ + {{ SNDMIX_REVERB_PRESET_PLATE }, "GM Plate"}, + {{ SNDMIX_REVERB_PRESET_SMALLROOM }, "GM Small Room"}, + {{ SNDMIX_REVERB_PRESET_MEDIUMROOM }, "GM Medium Room"}, + {{ SNDMIX_REVERB_PRESET_LARGEROOM }, "GM Large Room"}, + {{ SNDMIX_REVERB_PRESET_MEDIUMHALL }, "GM Medium Hall"}, + {{ SNDMIX_REVERB_PRESET_LARGEHALL }, "GM Large Hall"}, + {{ SNDMIX_REVERB_PRESET_GENERIC }, "Generic"}, + {{ SNDMIX_REVERB_PRESET_PADDEDCELL }, "Padded Cell"}, + {{ SNDMIX_REVERB_PRESET_ROOM }, "Room"}, + {{ SNDMIX_REVERB_PRESET_BATHROOM }, "Bathroom"}, + {{ SNDMIX_REVERB_PRESET_LIVINGROOM }, "Living Room"}, + {{ SNDMIX_REVERB_PRESET_STONEROOM }, "Stone Room"}, + {{ SNDMIX_REVERB_PRESET_AUDITORIUM }, "Auditorium"}, + {{ SNDMIX_REVERB_PRESET_CONCERTHALL }, "Concert Hall"}, + {{ SNDMIX_REVERB_PRESET_CAVE }, "Cave"}, + {{ SNDMIX_REVERB_PRESET_ARENA }, "Arena"}, + {{ SNDMIX_REVERB_PRESET_HANGAR }, "Hangar"}, + {{ SNDMIX_REVERB_PRESET_CARPETEDHALLWAY }, "Carpeted Hallway"}, + {{ SNDMIX_REVERB_PRESET_HALLWAY }, "Hallway"}, + {{ SNDMIX_REVERB_PRESET_STONECORRIDOR }, "Stone Corridor"}, + {{ SNDMIX_REVERB_PRESET_ALLEY }, "Alley"}, + {{ SNDMIX_REVERB_PRESET_FOREST }, "Forest"}, + {{ SNDMIX_REVERB_PRESET_CITY }, "City"}, + {{ SNDMIX_REVERB_PRESET_MOUNTAINS }, "Mountains"}, + {{ SNDMIX_REVERB_PRESET_QUARRY }, "Quarry"}, + {{ SNDMIX_REVERB_PRESET_PLAIN }, "Plain"}, + {{ SNDMIX_REVERB_PRESET_PARKINGLOT }, "Parking Lot"}, + {{ SNDMIX_REVERB_PRESET_SEWERPIPE }, "Sewer Pipe"}, + {{ SNDMIX_REVERB_PRESET_UNDERWATER }, "Underwater"}, +}; + +LPCSTR GetReverbPresetName(UINT nPreset) +{ + return (nPreset < NUM_REVERBTYPES) ? gRvbPresets[nPreset].lpszName : NULL; +} + +////////////////////////////////////////////////////////////////////////// +// +// I3DL2 environmental reverb support +// + +typedef struct _REFLECTIONPRESET +{ + LONG lDelayFactor; + SHORT sGainLL, sGainRR, sGainLR, sGainRL; +} REFLECTIONPRESET, *PREFLECTIONPRESET; + +const REFLECTIONPRESET gReflectionsPreset[ENVIRONMENT_NUMREFLECTIONS] = +{ + // %Delay, ll, rr, lr, rl + {0, 9830, 6554, 0, 0}, + {10, 6554, 13107, 0, 0}, + {24, -9830, 13107, 0, 0}, + {36, 13107, -6554, 0, 0}, + {54, 16384, 16384, -1638, -1638}, + {61, -13107, 8192, -328, -328}, + {73, -11468, -11468, -3277, 3277}, + {87, 13107, -9830, 4916, -4916} +}; + +//////////////////////////////////////////////////////////////////////////////////// +// +// Implementation +// + +inline long ftol(float f) { return ((long)(f)); } + +static VOID I3dl2_to_Generic( + const SNDMIX_REVERB_PROPERTIES *pReverb, + PENVIRONMENTREVERB pRvb, + FLOAT flOutputFreq, + LONG lMinRefDelay, + LONG lMaxRefDelay, + LONG lMinRvbDelay, + LONG lMaxRvbDelay, + LONG lTankLength) +{ + FLOAT flDelayFactor, flDelayFactorHF, flDecayTimeHF; + LONG lDensity, lTailDiffusion; + + // Common parameters + pRvb->ReverbLevel = pReverb->lReverb; + pRvb->ReflectionsLevel = pReverb->lReflections; + pRvb->RoomHF = pReverb->lRoomHF; + + // HACK: Somewhat normalize the reverb output level + LONG lMaxLevel = (pRvb->ReverbLevel > pRvb->ReflectionsLevel) ? pRvb->ReverbLevel : pRvb->ReflectionsLevel; + if (lMaxLevel < -600) + { + lMaxLevel += 600; + pRvb->ReverbLevel -= lMaxLevel; + pRvb->ReflectionsLevel -= lMaxLevel; + } + + // Pre-Diffusion factor (for both reflections and late reverb) + lDensity = 8192 + ftol(79.31f * pReverb->flDensity); + pRvb->PreDiffusion = lDensity; + + // Late reverb diffusion + lTailDiffusion = ftol((0.15f + pReverb->flDiffusion * (0.36f*0.01f)) * 32767.0f); + if (lTailDiffusion > 0x7f00) lTailDiffusion = 0x7f00; + pRvb->TankDiffusion = lTailDiffusion; + + // Verify reflections and reverb delay parameters + FLOAT flRefDelay = pReverb->flReflectionsDelay; + if (flRefDelay > 0.100f) flRefDelay = 0.100f; + LONG lReverbDelay = ftol(pReverb->flReverbDelay * flOutputFreq); + LONG lReflectionsDelay = ftol(flRefDelay * flOutputFreq); + LONG lReverbDecayTime = ftol(pReverb->flDecayTime * flOutputFreq); + if (lReflectionsDelay < lMinRefDelay) + { + lReverbDelay -= (lMinRefDelay - lReflectionsDelay); + lReflectionsDelay = lMinRefDelay; + } + if (lReflectionsDelay > lMaxRefDelay) + { + lReverbDelay += (lReflectionsDelay - lMaxRefDelay); + lReflectionsDelay = lMaxRefDelay; + } + // Adjust decay time when adjusting reverb delay + if (lReverbDelay < lMinRvbDelay) + { + lReverbDecayTime -= (lMinRvbDelay - lReverbDelay); + lReverbDelay = lMinRvbDelay; + } + if (lReverbDelay > lMaxRvbDelay) + { + lReverbDecayTime += (lReverbDelay - lMaxRvbDelay); + lReverbDelay = lMaxRvbDelay; + } + pRvb->ReverbDelay = lReverbDelay; + pRvb->ReverbDecaySamples = lReverbDecayTime; + // Setup individual reflections delay and gains + for (UINT iRef=0; iRef<ENVIRONMENT_NUMREFLECTIONS; iRef++) + { + PENVIRONMENTREFLECTION pRef = &pRvb->Reflections[iRef]; + pRef->Delay = lReflectionsDelay + (gReflectionsPreset[iRef].lDelayFactor * lReverbDelay + 50)/100; + pRef->GainLL = gReflectionsPreset[iRef].sGainLL; + pRef->GainRL = gReflectionsPreset[iRef].sGainRL; + pRef->GainLR = gReflectionsPreset[iRef].sGainLR; + pRef->GainRR = gReflectionsPreset[iRef].sGainRR; + } + + // Late reverb decay time + if (lTankLength < 10) lTankLength = 10; + flDelayFactor = (lReverbDecayTime <= lTankLength) ? 1.0f : ((FLOAT)lTankLength / (FLOAT)lReverbDecayTime); + pRvb->ReverbDecay = ftol(pow(0.001f, flDelayFactor) * 32768.0f); + + // Late Reverb Decay HF + flDecayTimeHF = (FLOAT)lReverbDecayTime * pReverb->flDecayHFRatio; + flDelayFactorHF = (flDecayTimeHF <= (FLOAT)lTankLength) ? 1.0f : ((FLOAT)lTankLength / flDecayTimeHF); + pRvb->flReverbDamping = pow(0.001f, flDelayFactorHF); +} + + +void CReverb::Shutdown() +//---------------------- +{ + gnRvbLOfsVol = 0; + gnRvbROfsVol = 0; + + // Clear out all reverb state + g_bLastInPresent = FALSE; + g_bLastOutPresent = FALSE; + g_nLastRvbIn_xl = g_nLastRvbIn_xr = 0; + g_nLastRvbIn_yl = g_nLastRvbIn_yr = 0; + g_nLastRvbOut_xl = g_nLastRvbOut_xr = 0; + gnDCRRvb_X1 = 0; + gnDCRRvb_Y1 = 0; + + // Zero internal buffers + MemsetZero(g_LateReverb.Diffusion1); + MemsetZero(g_LateReverb.Diffusion2); + MemsetZero(g_LateReverb.Delay1); + MemsetZero(g_LateReverb.Delay2); + MemsetZero(g_RefDelay.RefDelayBuffer); + MemsetZero(g_RefDelay.PreDifBuffer); + MemsetZero(g_RefDelay.RefOut); +} + + +void CReverb::Initialize(BOOL bReset, DWORD MixingFreq) +//----------------------------------------------------- +{ + if (m_Settings.m_nReverbType >= NUM_REVERBTYPES) m_Settings.m_nReverbType = 0; + static PSNDMIX_REVERB_PROPERTIES spCurrentPreset = NULL; + PSNDMIX_REVERB_PROPERTIES pRvbPreset = &gRvbPresets[m_Settings.m_nReverbType].Preset; + + if ((pRvbPreset != spCurrentPreset) || (bReset)) + { + // Reverb output frequency is half of the dry output rate + FLOAT flOutputFrequency = (FLOAT)MixingFreq; + ENVIRONMENTREVERB rvb; + + // Reset reverb parameters + spCurrentPreset = pRvbPreset; + I3dl2_to_Generic(pRvbPreset, &rvb, flOutputFrequency, + RVBMINREFDELAY, RVBMAXREFDELAY, + RVBMINRVBDELAY, RVBMAXRVBDELAY, + ( RVBDIF1L_LEN + RVBDIF1R_LEN + + RVBDIF2L_LEN + RVBDIF2R_LEN + + RVBDLY1L_LEN + RVBDLY1R_LEN + + RVBDLY2L_LEN + RVBDLY2R_LEN) / 2); + + // Store reverb decay time (in samples) for reverb auto-shutdown + gnReverbDecaySamples = rvb.ReverbDecaySamples; + + // Room attenuation at high frequencies + LONG nRoomLP; + nRoomLP = OnePoleLowPassCoef(32768, mBToLinear(rvb.RoomHF), 5000, flOutputFrequency); + g_RefDelay.nCoeffs[0] = (SHORT)nRoomLP; + g_RefDelay.nCoeffs[1] = (SHORT)nRoomLP; + + // Pre-Diffusion factor (for both reflections and late reverb) + g_RefDelay.nPreDifCoeffs[0] = (SHORT)(rvb.PreDiffusion*2); + g_RefDelay.nPreDifCoeffs[1] = (SHORT)(rvb.PreDiffusion*2); + + // Setup individual reflections delay and gains + for (UINT iRef=0; iRef<8; iRef++) + { + PSWRVBREFLECTION pRef = &g_RefDelay.Reflections[iRef]; + pRef->DelayDest = rvb.Reflections[iRef].Delay; + pRef->Delay = pRef->DelayDest; + pRef->Gains[0] = rvb.Reflections[iRef].GainLL; + pRef->Gains[1] = rvb.Reflections[iRef].GainRL; + pRef->Gains[2] = rvb.Reflections[iRef].GainLR; + pRef->Gains[3] = rvb.Reflections[iRef].GainRR; + } + g_LateReverb.nReverbDelay = rvb.ReverbDelay; + + // Reflections Master Gain + ULONG lReflectionsGain = 0; + if (rvb.ReflectionsLevel > -9000) + { + lReflectionsGain = mBToLinear(32768, rvb.ReflectionsLevel); + } + g_RefDelay.lMasterGain = lReflectionsGain; + + // Late reverb master gain + ULONG lReverbGain = 0; + if (rvb.ReverbLevel > -9000) + { + lReverbGain = mBToLinear(32768, rvb.ReverbLevel); + } + g_LateReverb.lMasterGain = lReverbGain; + + // Late reverb diffusion + ULONG nTailDiffusion = rvb.TankDiffusion; + if (nTailDiffusion > 0x7f00) nTailDiffusion = 0x7f00; + g_LateReverb.nDifCoeffs[0] = (SHORT)nTailDiffusion; + g_LateReverb.nDifCoeffs[1] = (SHORT)nTailDiffusion; + g_LateReverb.nDifCoeffs[2] = (SHORT)nTailDiffusion; + g_LateReverb.nDifCoeffs[3] = (SHORT)nTailDiffusion; + g_LateReverb.Dif2InGains[0] = 0x7000; + g_LateReverb.Dif2InGains[1] = 0x1000; + g_LateReverb.Dif2InGains[2] = 0x1000; + g_LateReverb.Dif2InGains[3] = 0x7000; + + // Late reverb decay time + LONG nReverbDecay = rvb.ReverbDecay; + if (nReverbDecay < 0) nReverbDecay = 0; + if (nReverbDecay > 0x7ff0) nReverbDecay = 0x7ff0; + g_LateReverb.nDecayDC[0] = (SHORT)nReverbDecay; + g_LateReverb.nDecayDC[1] = 0; + g_LateReverb.nDecayDC[2] = 0; + g_LateReverb.nDecayDC[3] = (SHORT)nReverbDecay; + + // Late Reverb Decay HF + FLOAT fReverbDamping = rvb.flReverbDamping * rvb.flReverbDamping; + LONG nDampingLowPass; + + nDampingLowPass = OnePoleLowPassCoef(32768, fReverbDamping, 5000, flOutputFrequency); + if (nDampingLowPass < 0x100) nDampingLowPass = 0x100; + if (nDampingLowPass >= 0x7f00) nDampingLowPass = 0x7f00; + + g_LateReverb.nDecayLP[0] = (SHORT)nDampingLowPass; + g_LateReverb.nDecayLP[1] = 0; + g_LateReverb.nDecayLP[2] = 0; + g_LateReverb.nDecayLP[3] = (SHORT)nDampingLowPass; + } + if (bReset) + { + gnReverbSamples = 0; + Shutdown(); + } + // Wait at least 5 seconds before shutting down the reverb + if (gnReverbDecaySamples < MixingFreq*5) + { + gnReverbDecaySamples = MixingFreq*5; + } +} + + +// [Reverb level 0(quiet)-100(loud)], [type = REVERBTYPE_XXXX] +bool CReverb::SetReverbParameters(UINT nDepth, UINT nType) +//-------------------------------------------------------- +{ + if (nDepth > 100) nDepth = 100; + UINT gain = (nDepth * 16) / 100; + if (gain > 16) gain = 16; + if (gain < 1) gain = 1; + m_Settings.m_nReverbDepth = gain; + if (nType < NUM_REVERBTYPES) m_Settings.m_nReverbType = nType; + return true; +} + + +// Reverb +void CReverb::Process(int *MixSoundBuffer, int *MixReverbBuffer, UINT nSamples, DWORD sysinfo) +//-------------------------------------------------------------------------------------------- +{ + UINT nIn, nOut; + + if ((!gnReverbSend) && (!gnReverbSamples)) return; + if (!gnReverbSend) X86_StereoFill(MixReverbBuffer, nSamples, &gnRvbROfsVol, &gnRvbLOfsVol); + if (!(sysinfo & SYSMIX_ENABLEMMX)) return; + // Dynamically adjust reverb master gains + LONG lMasterGain; + lMasterGain = ((g_RefDelay.lMasterGain * m_Settings.m_nReverbDepth) >> 4); + if (lMasterGain > 0x7fff) lMasterGain = 0x7fff; + g_RefDelay.ReflectionsGain[0] = (SHORT)lMasterGain; + g_RefDelay.ReflectionsGain[1] = (SHORT)lMasterGain; + lMasterGain = ((g_LateReverb.lMasterGain * m_Settings.m_nReverbDepth) >> 4); + if (lMasterGain > 0x10000) lMasterGain = 0x10000; + g_LateReverb.RvbOutGains[0] = (SHORT)((lMasterGain+0x7f) >> 3); // l->l + g_LateReverb.RvbOutGains[1] = (SHORT)((lMasterGain+0xff) >> 4); // r->l + g_LateReverb.RvbOutGains[2] = (SHORT)((lMasterGain+0xff) >> 4); // l->r + g_LateReverb.RvbOutGains[3] = (SHORT)((lMasterGain+0x7f) >> 3); // r->r + // Process Dry/Wet Mix + LONG lMaxRvbGain = (g_RefDelay.lMasterGain > g_LateReverb.lMasterGain) ? g_RefDelay.lMasterGain : g_LateReverb.lMasterGain; + if (lMaxRvbGain > 32768) lMaxRvbGain = 32768; + LONG lDryVol = (36 - m_Settings.m_nReverbDepth)>>1; + if (lDryVol < 8) lDryVol = 8; + if (lDryVol > 16) lDryVol = 16; + lDryVol = 16 - (((16-lDryVol) * lMaxRvbGain) >> 15); + X86_ReverbDryMix(MixSoundBuffer, MixReverbBuffer, lDryVol, nSamples); + // Downsample 2x + 1st stage of lowpass filter + nIn = X86_ReverbProcessPreFiltering1x(MixReverbBuffer, nSamples); + nOut = nIn; + // Main reverb processing: split into small chunks (needed for short reverb delays) + // Reverb Input + Low-Pass stage #2 + Pre-diffusion + if (nIn > 0) MMX_ProcessPreDelay(&g_RefDelay, MixReverbBuffer, nIn); + // Process Reverb Reflections and Late Reverberation + int *pRvbOut = MixReverbBuffer; + UINT nRvbSamples = nOut, nCount = 0; + while (nRvbSamples > 0) + { + UINT nPosRef = g_RefDelay.nRefOutPos & SNDMIX_REVERB_DELAY_MASK; + UINT nPosRvb = (nPosRef - g_LateReverb.nReverbDelay) & SNDMIX_REVERB_DELAY_MASK; + UINT nmax1 = (SNDMIX_REVERB_DELAY_MASK+1) - nPosRef; + UINT nmax2 = (SNDMIX_REVERB_DELAY_MASK+1) - nPosRvb; + nmax1 = (nmax1 < nmax2) ? nmax1 : nmax2; + UINT n = nRvbSamples; + if (n > nmax1) n = nmax1; + if (n > 64) n = 64; + // Reflections output + late reverb delay + MMX_ProcessReflections(&g_RefDelay, &g_RefDelay.RefOut[nPosRef*2], pRvbOut, n); + // Late Reverberation + MMX_ProcessLateReverb(&g_LateReverb, &g_RefDelay.RefOut[nPosRvb*2], pRvbOut, n); + // Update delay positions + g_RefDelay.nRefOutPos = (g_RefDelay.nRefOutPos + n) & SNDMIX_REVERB_DELAY_MASK; + g_RefDelay.nDelayPos = (g_RefDelay.nDelayPos + n) & SNDMIX_REFLECTIONS_DELAY_MASK; + nCount += n*2; + pRvbOut += n*2; + nRvbSamples -= n; + } + // Adjust nDelayPos, in case nIn != nOut + g_RefDelay.nDelayPos = (g_RefDelay.nDelayPos - nOut + nIn) & SNDMIX_REFLECTIONS_DELAY_MASK; + // Upsample 2x + MMX_ReverbProcessPostFiltering1x(MixReverbBuffer, MixSoundBuffer, nSamples); + // Automatically shut down if needed + if (gnReverbSend) gnReverbSamples = gnReverbDecaySamples; + else if (gnReverbSamples > nSamples) gnReverbSamples -= nSamples; + else + { + if (gnReverbSamples) Shutdown(); + gnReverbSamples = 0; + } +} + + +VOID CReverb::X86_ReverbDryMix(int *pDry, int *pWet, int lDryVol, UINT nSamples) +//------------------------------------------------------------------------------ +{ + for (UINT i=0; i<nSamples; i++) + { + pDry[i*2] += (pWet[i*2]>>4) * lDryVol; + pDry[i*2+1] += (pWet[i*2+1]>>4) * lDryVol; + } +} + + +UINT CReverb::X86_ReverbProcessPreFiltering2x(int *pWet, UINT nSamples) +//--------------------------------------------------------------------- +{ + UINT nOutSamples = 0; + int lowpass = g_RefDelay.nCoeffs[0]; + int y1_l = g_nLastRvbIn_yl, y1_r = g_nLastRvbIn_yr; + UINT n = nSamples; + + if (g_bLastInPresent) + { + int x1_l = g_nLastRvbIn_xl, x1_r = g_nLastRvbIn_xr; + int x2_l = pWet[0], x2_r = pWet[1]; + x1_l = (x1_l+x2_l)>>13; + x1_r = (x1_r+x2_r)>>13; + y1_l = x1_l + (((x1_l - y1_l)*lowpass)>>15); + y1_r = x1_r + (((x1_r - y1_r)*lowpass)>>15); + pWet[0] = y1_l; + pWet[1] = y1_r; + pWet+=2; + n--; + nOutSamples = 1; + g_bLastInPresent = FALSE; + } + if (n & 1) + { + n--; + g_nLastRvbIn_xl = pWet[n*2]; + g_nLastRvbIn_xr = pWet[n*2+1]; + g_bLastInPresent = TRUE; + } + n >>= 1; + for (UINT i=0; i<n; i++) + { + int x1_l = pWet[i*4]; + int x2_l = pWet[i*4+2]; + x1_l = (x1_l+x2_l)>>13; + int x1_r = pWet[i*4+1]; + int x2_r = pWet[i*4+3]; + x1_r = (x1_r+x2_r)>>13; + y1_l = x1_l + (((x1_l - y1_l)*lowpass)>>15); + y1_r = x1_r + (((x1_r - y1_r)*lowpass)>>15); + pWet[i*2] = y1_l; + pWet[i*2+1] = y1_r; + } + g_nLastRvbIn_yl = y1_l; + g_nLastRvbIn_yr = y1_r; + return nOutSamples + n; +} + + +UINT CReverb::X86_ReverbProcessPreFiltering1x(int *pWet, UINT nSamples) +//--------------------------------------------------------------------- +{ + int lowpass = g_RefDelay.nCoeffs[0]; + int y1_l = g_nLastRvbIn_yl, y1_r = g_nLastRvbIn_yr; + + for (UINT i=0; i<nSamples; i++) + { + int x_l = pWet[i*2] >> 12; + int x_r = pWet[i*2+1] >> 12; + y1_l = x_l + (((x_l - y1_l)*lowpass)>>15); + y1_r = x_r + (((x_r - y1_r)*lowpass)>>15); + pWet[i*2] = y1_l; + pWet[i*2+1] = y1_r; + } + g_nLastRvbIn_yl = y1_l; + g_nLastRvbIn_yr = y1_r; + return nSamples; +} + + +VOID CReverb::X86_ReverbProcessPostFiltering2x(const int *pRvb, int *pDry, UINT nSamples) +//--------------------------------------------------------------------------------------- +{ + UINT n0 = nSamples, n; + int x1_l = g_nLastRvbOut_xl, x1_r = g_nLastRvbOut_xr; + + if (g_bLastOutPresent) + { + pDry[0] += x1_l; + pDry[1] += x1_r; + pDry += 2; + n0--; + g_bLastOutPresent = FALSE; + } + n = n0 >> 1; + for (UINT i=0; i<n; i++) + { + int x_l = pRvb[i*2], x_r = pRvb[i*2+1]; + pDry[i*4] += (x_l + x1_l)>>1; + pDry[i*4+1] += (x_r + x1_r)>>1; + pDry[i*4+2] += x_l; + pDry[i*4+3] += x_r; + x1_l = x_l; + x1_r = x_r; + } + if (n0 & 1) + { + int x_l = pRvb[n*2], x_r = pRvb[n*2+1]; + pDry[n*4] += (x_l + x1_l)>>1; + pDry[n*4+1] += (x_r + x1_r)>>1; + x1_l = x_l; + x1_r = x_r; + g_bLastOutPresent = TRUE; + } + g_nLastRvbOut_xl = x1_l; + g_nLastRvbOut_xr = x1_r; +} + + +#define DCR_AMOUNT 9 + +// Stereo Add + DC removal +VOID CReverb::MMX_ReverbProcessPostFiltering1x(const int *pRvb, int *pDry, UINT nSamples) +//--------------------------------------------------------------------------------------- +{ + __int64 nDCRRvb_X1 = gnDCRRvb_X1; + __int64 nDCRRvb_Y1 = gnDCRRvb_Y1; + _asm { + movq mm4, nDCRRvb_Y1 // mm4 = [ y1r | y1l ] + movq mm1, nDCRRvb_X1 // mm5 = [ x1r | x1l ] + mov ebx, pDry + mov ecx, pRvb + mov edx, nSamples +stereodcr: + movq mm5, qword ptr [ecx] // mm0 = [ xr | xl ] + movq mm3, qword ptr [ebx] // mm3 = dry mix + add ecx, 8 + psubd mm1, mm5 // mm1 = x(n-1) - x(n) + add ebx, 8 + movq mm0, mm1 + psrad mm0, DCR_AMOUNT+1 + psubd mm0, mm1 + paddd mm4, mm0 + dec edx + paddd mm3, mm4 // add with dry mix + movq mm0, mm4 + psrad mm0, DCR_AMOUNT + movq mm1, mm5 + psubd mm4, mm0 + movq qword ptr [ebx-8], mm3 + jnz stereodcr + movq nDCRRvb_Y1, mm4 + movq nDCRRvb_X1, mm5 + emms + } + gnDCRRvb_X1 = nDCRRvb_X1; + gnDCRRvb_Y1 = nDCRRvb_Y1; +} + + +VOID CReverb::MMX_ReverbDCRemoval(int *pBuffer, UINT nSamples) +//------------------------------------------------------------ +{ + __int64 nDCRRvb_X1 = gnDCRRvb_X1; + __int64 nDCRRvb_Y1 = gnDCRRvb_Y1; + _asm { + movq mm4, nDCRRvb_Y1 // mm4 = [ y1r | y1l ] + movq mm1, nDCRRvb_X1 // mm5 = [ x1r | x1l ] + mov ecx, pBuffer + mov edx, nSamples +stereodcr: + movq mm5, qword ptr [ecx] // mm0 = [ xr | xl ] + add ecx, 8 + psubd mm1, mm5 // mm1 = x(n-1) - x(n) + movq mm0, mm1 + psrad mm0, DCR_AMOUNT+1 + psubd mm0, mm1 + paddd mm4, mm0 + dec edx + movq qword ptr [ecx-8], mm4 + movq mm0, mm4 + psrad mm0, DCR_AMOUNT + movq mm1, mm5 + psubd mm4, mm0 + jnz stereodcr + movq nDCRRvb_Y1, mm4 + movq nDCRRvb_X1, mm5 + emms + } + gnDCRRvb_X1 = nDCRRvb_X1; + gnDCRRvb_Y1 = nDCRRvb_Y1; +} + + +////////////////////////////////////////////////////////////////////////// +// +// Pre-Delay: +// +// 1. Saturate and low-pass the reverb input (stage 2 of roomHF) +// 2. Process pre-diffusion +// 3. Insert the result in the reflections delay buffer +// + +VOID CReverb::MMX_ProcessPreDelay(PSWRVBREFDELAY pPreDelay, const int *pIn, UINT nSamples) +//---------------------------------------------------------------------------------------- +{ + _asm { + mov eax, pPreDelay + mov ecx, pIn + mov esi, nSamples + lea edi, [eax+SWRVBREFDELAY.RefDelayBuffer] + mov ebx, dword ptr [eax+SWRVBREFDELAY.nDelayPos] + mov edx, dword ptr [eax+SWRVBREFDELAY.nPreDifPos] + movd mm6, dword ptr [eax+SWRVBREFDELAY.nCoeffs] + movd mm7, dword ptr [eax+SWRVBREFDELAY.History] + movd mm4, dword ptr [eax+SWRVBREFDELAY.nPreDifCoeffs] + lea eax, [eax+SWRVBREFDELAY.PreDifBuffer] + dec ebx +rvbloop: + movq mm0, qword ptr [ecx] // mm0 = 16-bit unsaturated reverb input [ r | l ] + inc ebx + add ecx, 8 + packssdw mm0, mm0 // mm0 = [ r | l | r | l ] + and ebx, SNDMIX_REFLECTIONS_DELAY_MASK + // Low-pass + psubsw mm7, mm0 + pmulhw mm7, mm6 + movd mm5, dword ptr [eax+edx*4] // mm5 = [ 0 | 0 |rd |ld ] XD(n-D) + paddsw mm7, mm7 + paddsw mm7, mm0 + // Pre-Diffusion + movq mm0, mm7 // mm0 = [ ? | ? | r | l ] X(n) + inc edx + movq mm3, mm5 + and edx, SNDMIX_PREDIFFUSION_DELAY_MASK + pmulhw mm3, mm4 // mm3 = k.Xd(n-D) + movq mm2, mm4 + dec esi + psubsw mm0, mm3 // mm0 = X(n) - k.Xd(n-D) = Xd(n) + pmulhw mm2, mm0 // mm2 = k.Xd(n) + paddsw mm2, mm5 // mm2 = Xd(n-D) + k.Xd(n) + movd dword ptr [eax+edx*4], mm0 + movd dword ptr [edi+ebx*4], mm2 + jnz rvbloop + mov eax, pPreDelay + mov dword ptr [eax+SWRVBREFDELAY.nPreDifPos], edx + movd dword ptr [eax+SWRVBREFDELAY.History], mm7 + emms + } +} + + +//////////////////////////////////////////////////////////////////// +// +// ProcessReflections: +// First stage: +// - process 4 reflections, output to pRefOut +// - output results to pRefOut +// Second stage: +// - process another 3 reflections +// - sum with pRefOut +// - apply reflections master gain and accumulate in the given output +// + +typedef struct _DUMMYREFARRAY +{ + SWRVBREFLECTION Ref1; + SWRVBREFLECTION Ref2; + SWRVBREFLECTION Ref3; + SWRVBREFLECTION Ref4; + SWRVBREFLECTION Ref5; + SWRVBREFLECTION Ref6; + SWRVBREFLECTION Ref7; + SWRVBREFLECTION Ref8; +} DUMMYREFARRAY, *PDUMMYREFARRAY; + + +VOID CReverb::MMX_ProcessReflections(PSWRVBREFDELAY pPreDelay, short int *pRefOut, int *pOut, UINT nSamples) +//---------------------------------------------------------------------------------------------------------- +{ + _asm { + // First stage + push ebp + mov edi, pPreDelay + mov eax, pRefOut + mov ebp, nSamples + push eax + lea esi, [edi+SWRVBREFDELAY.RefDelayBuffer] + mov eax, dword ptr [edi+SWRVBREFDELAY.nDelayPos] + lea edi, [edi+SWRVBREFDELAY.Reflections] + mov ebx, eax + mov ecx, eax + mov edx, eax + sub eax, dword ptr [edi+DUMMYREFARRAY.Ref1.Delay] + movq mm4, qword ptr [edi+DUMMYREFARRAY.Ref1.Gains] + sub ebx, dword ptr [edi+DUMMYREFARRAY.Ref2.Delay] + movq mm5, qword ptr [edi+DUMMYREFARRAY.Ref2.Gains] + sub ecx, dword ptr [edi+DUMMYREFARRAY.Ref3.Delay] + movq mm6, qword ptr [edi+DUMMYREFARRAY.Ref3.Gains] + sub edx, dword ptr [edi+DUMMYREFARRAY.Ref4.Delay] + movq mm7, qword ptr [edi+DUMMYREFARRAY.Ref4.Gains] + pop edi + and eax, SNDMIX_REFLECTIONS_DELAY_MASK + and ebx, SNDMIX_REFLECTIONS_DELAY_MASK + and ecx, SNDMIX_REFLECTIONS_DELAY_MASK + and edx, SNDMIX_REFLECTIONS_DELAY_MASK +refloop1: + movd mm3, dword ptr [esi+edx*4] + movd mm2, dword ptr [esi+ecx*4] + inc edx + inc ecx + movd mm1, dword ptr [esi+ebx*4] + movd mm0, dword ptr [esi+eax*4] + punpckldq mm3, mm3 + punpckldq mm2, mm2 + pmaddwd mm3, mm7 + inc ebx + inc eax + pmaddwd mm2, mm6 + punpckldq mm1, mm1 + punpckldq mm0, mm0 + pmaddwd mm1, mm5 + and eax, SNDMIX_REFLECTIONS_DELAY_MASK + and ebx, SNDMIX_REFLECTIONS_DELAY_MASK + pmaddwd mm0, mm4 + and ecx, SNDMIX_REFLECTIONS_DELAY_MASK + paddd mm2, mm3 + paddd mm0, mm1 + paddd mm0, mm2 + and edx, SNDMIX_REFLECTIONS_DELAY_MASK + psrad mm0, 15 + add edi, 4 + packssdw mm0, mm0 + dec ebp + movd dword ptr [edi-4], mm0 + jnz refloop1 + pop ebp + // Second stage + push ebp + mov edi, pPreDelay + mov eax, pRefOut + mov edx, pOut + mov ebp, nSamples + movd mm7, dword ptr [edi+SWRVBREFDELAY.ReflectionsGain] + pxor mm0, mm0 + push eax + punpcklwd mm7, mm0 // mm7 = [ 0 |g_r| 0 |g_l] + mov eax, dword ptr [edi+SWRVBREFDELAY.nDelayPos] + lea edi, [edi+SWRVBREFDELAY.Reflections] + mov ebx, eax + mov ecx, eax + sub eax, dword ptr [edi+DUMMYREFARRAY.Ref5.Delay] + movq mm4, qword ptr [edi+DUMMYREFARRAY.Ref5.Gains] + sub ebx, dword ptr [edi+DUMMYREFARRAY.Ref6.Delay] + movq mm5, qword ptr [edi+DUMMYREFARRAY.Ref6.Gains] + sub ecx, dword ptr [edi+DUMMYREFARRAY.Ref7.Delay] + movq mm6, qword ptr [edi+DUMMYREFARRAY.Ref7.Gains] + pop edi + and ecx, SNDMIX_REFLECTIONS_DELAY_MASK + and ebx, SNDMIX_REFLECTIONS_DELAY_MASK + and eax, SNDMIX_REFLECTIONS_DELAY_MASK + psrad mm7, 3 // For 28-bit final output: 16+15-3 = 28 +refloop2: + movd mm2, dword ptr [esi+ecx*4] + movd mm1, dword ptr [esi+ebx*4] + movd mm0, dword ptr [esi+eax*4] + movd mm3, dword ptr [edi] // mm3 = output of previous reflections + punpckldq mm2, mm2 + inc ecx + pmaddwd mm2, mm6 + punpckldq mm1, mm1 + inc ebx + pmaddwd mm1, mm5 + punpckldq mm0, mm0 + inc eax + pmaddwd mm0, mm4 + and ecx, SNDMIX_REFLECTIONS_DELAY_MASK + and ebx, SNDMIX_REFLECTIONS_DELAY_MASK + paddd mm0, mm2 + paddd mm0, mm1 + add edi, 4 + psrad mm0, 15 + and eax, SNDMIX_REFLECTIONS_DELAY_MASK + packssdw mm0, mm0 + paddsw mm0, mm3 + add edx, 8 + movd dword ptr [edi-4], mm0 // late reverb stereo input + punpcklwd mm0, mm0 + pmaddwd mm0, mm7 // Apply reflections gain + dec ebp + movq qword ptr [edx-8], mm0 // At this, point, this is the only output of the reverb + jnz refloop2 + pop ebp + emms + } +} + + +////////////////////////////////////////////////////////////////////////// +// +// Late reverberation (with SW reflections) +// + +VOID CReverb::MMX_ProcessLateReverb(PSWLATEREVERB pReverb, short int *pRefOut, int *pMixOut, UINT nSamples) +//--------------------------------------------------------------------------------------------------------- +{ + _asm { + push ebp + mov ebx, pReverb + mov esi, pRefOut + mov edi, pMixOut + mov ebp, nSamples + mov ecx, dword ptr [ebx+SWLATEREVERB.nDelayPos] + movq mm3, qword ptr [ebx+SWLATEREVERB.RvbOutGains] + movq mm5, qword ptr [ebx+SWLATEREVERB.nDifCoeffs] + movq mm6, qword ptr [ebx+SWLATEREVERB.nDecayLP] + movq mm7, qword ptr [ebx+SWLATEREVERB.LPHistory] +rvbloop: + sub ecx, RVBDLY2L_LEN + movd mm0, dword ptr [esi] + lea edx, [ecx+RVBDLY2L_LEN - RVBDLY2R_LEN] + and ecx, RVBDLY_MASK + and edx, RVBDLY_MASK + movd mm1, dword ptr [ebx+SWLATEREVERB.Delay2+ecx*4] + movd mm2, dword ptr [ebx+SWLATEREVERB.Delay2+edx*4] + add ecx, RVBDLY2L_LEN - RVBDIF1R_LEN + punpckldq mm0, mm0 + and ecx, RVBDLY_MASK + punpckldq mm1, mm2 + psraw mm0, 2 // mm0 = stereo input + psubsw mm7, mm1 + movzx eax, word ptr [ebx+SWLATEREVERB.Diffusion1+ecx*4+2] + pmulhw mm7, mm6 + add ecx, RVBDIF1R_LEN - RVBDIF1L_LEN + add esi, 4 + paddsw mm7, mm7 + paddsw mm7, mm1 // mm7 = low-passed decay + movq mm1, qword ptr [ebx+SWLATEREVERB.nDecayDC] + and ecx, RVBDLY_MASK + shl eax, 16 + pmaddwd mm1, mm7 // apply decay gain + movzx edx, word ptr [ebx+SWLATEREVERB.Diffusion1+ecx*4] + add ecx, RVBDIF1L_LEN + psrad mm1, 15 // mm1 = decay [ r | l ] + and ecx, RVBDLY_MASK + packssdw mm1, mm1 + or eax, edx + paddsw mm1, mm0 // mm1 = input + decay [ r | l | r | l ] + movd mm2, eax // mm2 = diffusion1 history [ 0 | 0 | rd| ld] Xd(n-D) + pmulhw mm2, mm5 // mm2 = k.Xd(n-D) + movq mm4, mm1 // mm4 = reverb output + movq mm0, mm5 + psubsw mm1, mm2 // mm1 = X(n) - k.Xd(n-D) = Xd(n) + movd mm2, eax + pmulhw mm0, mm1 // mm0 = k.Xd(n) + movd dword ptr [ebx+SWLATEREVERB.Diffusion1+ecx*4], mm1 + paddsw mm0, mm2 // mm0 = Xd(n-D) + k.Xd(n) + mov eax, ecx + // Insert the diffusion output in the reverb delay line + movd dword ptr [ebx+SWLATEREVERB.Delay1+ecx*4], mm0 + sub ecx, RVBDLY1R_LEN + sub eax, RVBDLY1L_LEN + punpckldq mm0, mm0 + and ecx, RVBDLY_MASK + and eax, RVBDLY_MASK + paddsw mm4, mm0 // accumulate with reverb output + // Input to second diffuser + movd mm0, dword ptr [ebx+SWLATEREVERB.Delay1+ecx*4] + movd mm1, dword ptr [ebx+SWLATEREVERB.Delay1+eax*4] + add ecx, RVBDLY1R_LEN - RVBDIF2R_LEN + and ecx, RVBDLY_MASK + punpckldq mm1, mm0 + movzx eax, word ptr [ebx+SWLATEREVERB.Diffusion2+ecx*4+2] + paddsw mm4, mm1 + pmaddwd mm1, qword ptr [ebx+SWLATEREVERB.Dif2InGains] + add ecx, RVBDIF2R_LEN - RVBDIF2L_LEN + and ecx, RVBDLY_MASK + psrad mm1, 15 + movzx edx, word ptr [ebx+SWLATEREVERB.Diffusion2+ecx*4] + packssdw mm1, mm1 // mm1 = 2nd diffuser input [ r | l | r | l ] + shl eax, 16 + psubsw mm4, mm1 // accumulate with reverb output + or eax, edx + add ecx, RVBDIF2L_LEN + movd mm2, eax // mm2 = diffusion2 history + and ecx, RVBDLY_MASK + pmulhw mm2, mm5 // mm2 = k.Xd(n-D) + movq mm0, mm5 + psubsw mm1, mm2 // mm1 = X(n) - k.Xd(n-D) = Xd(n) + movd mm2, eax + pmulhw mm0, mm1 // mm0 = k.Xd(n) + movd dword ptr [ebx+SWLATEREVERB.Diffusion2+ecx*4], mm1 + movq mm1, qword ptr [edi] + paddsw mm0, mm2 // mm0 = Xd(n-D) + k.Xd(n) + paddsw mm4, mm0 // accumulate with reverb output + movd dword ptr [ebx+SWLATEREVERB.Delay2+ecx*4], mm0 + pmaddwd mm4, mm3 // mm4 = [ r | l ] + inc ecx + add edi, 8 + and ecx, RVBDLY_MASK + paddd mm4, mm1 + dec ebp + movq qword ptr [edi-8], mm4 + jnz rvbloop + pop ebp + movq qword ptr [ebx+SWLATEREVERB.LPHistory], mm7 + mov dword ptr [ebx+SWLATEREVERB.nDelayPos], ecx + emms + } +} + + +// (1-gcos(w)-sqrt(2g(1-cos w) - g2(1-(cos w)^2))) / (1-g) +static LONG OnePoleLowPassCoef(LONG scale, FLOAT g, FLOAT F_c, FLOAT F_s) +//---------------------------------------------------------------- +{ + FLOAT cosw; // cos(2*PI*Fc/Fs) + FLOAT scale_over_1mg; // scale / (1.0f - g); + LONG result; + + if (g > 0.999999f) return 0; + _asm { + fild scale + fld1 + fld g + fld ST(0) + fmulp ST(1), ST(0) + fst g + fsubp ST(1), ST(0) + fdivp ST(1), ST(0) + fstp scale_over_1mg + fld F_c + fld F_s + fdivp ST(1), ST(0) + fldpi + fadd ST(0), ST(0) + fmulp ST(1), ST(0) + fcos + fstp cosw + fld g + fadd ST(0), ST(0) + fld1 + fld cosw + fsubp ST(1), ST(0) + fmulp ST(1), ST(0) // 2g*(1 cos(w)) + fld g + fmul ST(0), ST(0) + fld1 + fld cosw + fmul ST(0), ST(0) + fsubp ST(1), ST(0) + fmulp ST(1), ST(0) // g*g*((1-cos w)^2) + fsubp ST(1), ST(0) + fsqrt + fld g + fmul cosw + faddp ST(1), ST(0) + fld1 + fsubrp ST(1), ST(0) // (1-gcos(w)-sqrt(2g(1-cos w) - g2(1-(cos w)^2))) + fld scale_over_1mg + fmulp ST(1), ST(0) + fistp result + } + return result; +} + + +static LONG mBToLinear(LONG scale, LONG value_mB) +{ + // factor = log2(10)/(100*20) + const float _factor = 3.321928094887362304f / (100.0f * 20.0f); + long result; + + if (!value_mB) return scale; + if (value_mB <= -10000) return 0; + _asm { + fild value_mB // Load dB value + fld _factor // Load the log2(10)/(20*65536) factor + fmulp ST(1), ST(0) // ST(0) = value_dB/(20*65536) + fist result // Store integer exponent + fisub result // ST(0) = -1 <= (value_dB*log2(10)/(65536*20)) <= 1 + f2xm1 // ST(0) = 2^(value_dB*log2(10)/(65536*20))-1 + fild result // load integer exponent + fild scale // Load scale factor + fscale // ST(0) = scale * 2^ST(1) + fstp ST(1) // Remove the integer from the stack + fmul ST(1), ST(0) // multiply with fractional part + faddp ST(1), ST(0) // add 1*scale*integer_part + fistp result // Convert to integer + } + return result; +} + + +static FLOAT mBToLinear(LONG value_mB) +{ + // factor = log2(10)/(100*20) + const float _factor = 3.321928094887362304f / (100.0f * 20.0f); + long result; + float fresult; + + if (!value_mB) return 1; + if (value_mB <= -100000) return 0; + _asm { + fild value_mB // Load dB value + fld _factor // Load the log2(10)/(20*65536) factor + fmulp ST(1), ST(0) // ST(0) = value_dB/(20*65536) + fist result // Store integer exponent + fisub result // ST(0) = -1 <= (value_dB*log2(10)/(65536*20)) <= 1 + f2xm1 // ST(0) = 2^(value_dB*log2(10)/(65536*20))-1 + fild result // load integer exponent + fld1 // Load scale factor + fscale // ST(0) = scale * 2^ST(1) + fstp ST(1) // Remove the integer from the stack + fmul ST(1), ST(0) // multiply with fractional part + faddp ST(1), ST(0) // add 1*scale*integer_part + fstp fresult // Convert to integer + } + return fresult; +} + +#endif // NO_REVERB Copied: trunk/OpenMPT/sounddsp/Reverb.h (from rev 1843, trunk/OpenMPT/soundlib/snd_rvb.h) =================================================================== --- trunk/OpenMPT/sounddsp/Reverb.h (rev 0) +++ trunk/OpenMPT/sounddsp/Reverb.h 2013-04-11 18:09:59 UTC (rev 1844) @@ -0,0 +1,260 @@ +/* + * Reverb.h + * -------- + * Purpose: Mixing code for reverb. + * Notes : Ugh... This should really be removed at some point. + * Authors: Olivier Lapicque + * OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + +#pragma once + +#ifndef NO_REVERB + +///////////////////////////////////////////////////////////////////////////// +// +// SW Reverb structures +// + +// Length-1 (in samples) of the reflections delay buffer: 32K, 371ms@22kHz +#define SNDMIX_REFLECTIONS_DELAY_MASK 0x1fff +#define SNDMIX_PREDIFFUSION_DELAY_MASK 0x7f // 128 samples +#define SNDMIX_REVERB_DELAY_MASK 0xfff // 4K samples (92ms @ 44kHz) + +typedef struct _SWRVBREFLECTION +{ + ULONG Delay, DelayDest; + SHORT Gains[4]; // g_ll, g_rl, g_lr, g_rr +} SWRVBREFLECTION, *PSWRVBREFLECTION; + +typedef struct _SWRVBREFDELAY +{ + ULONG nDelayPos, nPreDifPos, nRefOutPos; + LONG lMasterGain; // reflections linear master gain + SHORT nCoeffs[2]; // room low-pass coefficients + SHORT History[2]; // room low-pass history + SHORT nPreDifCoeffs[2]; // prediffusion coefficients + SHORT ReflectionsGain[2]; // master reflections gain + SWRVBREFLECTION Reflections[8]; // Up to 8 SW Reflections + short int RefDelayBuffer[(SNDMIX_REFLECTIONS_DELAY_MASK+1)*2]; // reflections delay buffer + short int PreDifBuffer[(SNDMIX_PREDIFFUSION_DELAY_MASK+1)*2]; // pre-diffusion + short int RefOut[(SNDMIX_REVERB_DELAY_MASK+1)*2]; // stereo output of reflections +} SWRVBREFDELAY, *PSWRVBREFDELAY; + + +// Late reverberation +// Tank diffusers lengths +#define RVBDIF1L_LEN (149*2) // 6.8ms +#define RVBDIF1R_LEN (223*2) // 10.1ms +#define RVBDIF2L_LEN (421*2) // 19.1ms +#define RVBDIF2R_LEN (647*2) // 29.3ms +// Tank delay lines lengths +#define RVBDLY1L_LEN (683*2) // 30.9ms +#define RVBDLY1R_LEN (811*2) // 36.7ms +#define RVBDLY2L_LEN (773*2) // 35.1ms +#define RVBDLY2R_LEN (1013*2) // 45.9ms +// Tank delay lines mask +#define RVBDLY_MASK 2047 + +// Min/Max reflections delay +#define RVBMINREFDELAY 96 // 96 samples +#define RVBMAXREFDELAY 7500 // 7500 samples +// Min/Max reverb delay +#define RVBMINRVBDELAY 128 // 256 samples (11.6ms @ 22kHz) +#define RVBMAXRVBDELAY 3800 // 1900 samples (86ms @ 24kHz) + +typedef struct _SWLATEREVERB +{ + ULONG nReverbDelay; // Reverb delay (in samples) + ULONG nDelayPos; // Delay line position + SHORT nDifCoeffs[4]; // Reverb diffusion + SHORT nDecayDC[4]; // Reverb DC decay + SHORT nDecayLP[4]; // Reverb HF decay + SHORT LPHistory[4]; // Low-pass history + SHORT Dif2InGains[4]; // 2nd diffuser input gains + SHORT RvbOutGains[4]; // 4x2 Reverb output gains + LONG lMasterGain; // late reverb master gain + LONG lDummyAlign; + // Tank Delay lines + short int Diffusion1[(RVBDLY_MASK+1)*2]; // {dif1_l, dif1_r} + short int Diffusion2[(RVBDLY_MASK+1)*2]; // {dif2_l, dif2_r} + short int Delay1[(RVBDLY_MASK+1)*2]; // {dly1_l, dly1_r} + short int Delay2[(RVBDLY_MASK+1)*2]; // {dly2_l, dly2_r} +} SWLATEREVERB, *PSWLATEREVERB; + +#define ENVIRONMENT_NUMREFLECTIONS 8 + +typedef struct _ENVIRONMENTREFLECTION +{ + SHORT GainLL, GainRR, GainLR, GainRL; // +/- 32K scale + ULONG Delay; // In samples +} ENVIRONMENTREFLECTION, *PENVIRONMENTREFLECTION; + +typedef struct _ENVIRONMENTREVERB +{ + LONG ReverbLevel; // Late reverb gain (mB) + LONG ReflectionsLevel; // Master reflections gain (mB) + LONG RoomHF; // Room gain HF (mB) + ULONG ReverbDecay; // Reverb tank decay (0-7fff scale) + LONG PreDiffusion; // Reverb pre-diffusion amount (+/- 32K scale) + LONG TankDiffusion; // Reverb tank diffusion (+/- 32K scale) + ULONG ReverbDelay; // Reverb delay (in samples) + FLOAT flReverbDamping; // HF tank gain [0.0, 1.0] + LONG ReverbDecaySamples;// Reverb decay time (in samples) + ENVIRONMENTREFLECTION Reflections[ENVIRONMENT_NUMREFLECTIONS]; +} ENVIRONMENTREVERB, *PENVIRONMENTREVERB; + + +//=================== +class CReverbSettings +//=================== +{ +public: + UINT m_nReverbDepth; + UINT m_nReverbType; +public: + CReverbSettings(); +}; + + +//=========== +class CReverb +//=========== +{ +public: + CReverbSettings m_Settings; + + // Shared reverb state + UINT gnReverbSend; + LONG gnRvbROfsVol; + LONG gnRvbLOfsVol; + +private: + + UINT gnReverbSamples; + UINT gnReverbDecaySamples; + + // Internal reverb state + BOOL g_bLastInPresent; + BOOL g_bLastOutPresent; + int g_nLastRvbIn_xl; + int g_nLastRvbIn_xr; + int g_nLastRvbIn_yl; + int g_nLastRvbIn_yr; + int g_nLastRvbOut_xl; + int g_nLastRvbOut_xr; + __int64 gnDCRRvb_Y1; + __int64 gnDCRRvb_X1; + + // Reverb mix buffers + SWRVBREFDELAY g_RefDelay; + SWLATEREVERB g_LateReverb; + +public: + CReverb(); + ~CReverb() {} +public: + void Initialize(BOOL bReset, DWORD MixingFreq); + void Process(int *MixSoundBuffer, int *MixReverbBuffer, UINT nSamples, DWORD sysinfo); + // [Reverb level 0(quiet)-100(loud)], [REVERBTYPE_XXXX] + bool SetReverbParameters(UINT nDepth, UINT nType); +private: + void Shutdown(); + // Pre/Post resampling and filtering + UINT X86_ReverbProcessPreFiltering1x(int *pWet, UINT nSamples); + UINT X86_ReverbProcessPreFiltering2x(int *pWet, UINT nSamples); + VOID MMX_ReverbProcessPostFiltering1x(const int *pRvb, int *pDry, UINT nSamples); + VOID X86_ReverbProcessPostFiltering2x(const int *pRvb, int *pDry, UINT nSamples); + VOID MMX_ReverbDCRemoval(int *pBuffer, UINT nSamples); + VOID X86_ReverbDryMix(int *pDry, int *pWet, int lDryVol, UINT nSamples); + // Process pre-diffusion and pre-delay + VOID MMX_ProcessPreDelay(PSWRVBREFDELAY pPreDelay, const int *pIn, UINT nSamples); + // Process reflections + VOID MMX_ProcessReflections(PSWRVBREFDELAY pPreDelay, short int *pRefOut, int *pMixOut, UINT nSamples); + // Process Late Reverb (SW Reflections): stereo reflections output, 32-bit reverb output, SW reverb gain + VOID MMX_ProcessLateReverb(PSWLATEREVERB pReverb, short int *pRefOut, int *pMixOut, UINT nSamples); +}; + + +///////////////////////////////////////////////////////////////////////////////// +// +// I3DL2 reverb presets +// + +#define SNDMIX_REVERB_PRESET_DEFAULT \ +-10000, 0, 1.00f,0.50f,-10000,0.020f,-10000,0.040f,100.0f,100.0f + +#define SNDMIX_REVERB_PRESET_GENERIC \ + -1000, -100, 1.49f,0.83f, -2602,0.007f, 200,0.011f,100.0f,100.0f +#define SNDMIX_REVERB_PRESET_PADDEDCELL \ + -1000,-6000, 0.17f,0.10f, -1204,0.001f, 207,0.002f,100.0f,100.0f +#define SNDMIX_REVERB_PRESET_ROOM \ + -1000, -454, 0.40f,0.83f, -1646,0.002f, 53,0.003f,100.0f,100.0f +#define SNDMIX_REVERB_PRESET_BATHROOM \ + -1000,-1200, 1.49f,0.54f, -370,0.007f, 1030,0.011f,100.0f, 60.0f +#define SNDMIX_REVERB_PRESET_LIVINGROOM \ + -1000,-6000, 0.50f,0.10f, -1376,0.003f, -1104,0.004f,100.0f,100.0f +#define SNDMIX_REVERB_PRESET_STONEROOM \ + -1000, -300, 2.31f,0.64f, -711,0.012f, 83,0.017f,100.0f,100.0f +#define SNDMIX_REVERB_PRESET_AUDITORIUM \ + -1000, -476, 4.32f,0.59f, -789,0.020f, -289,0.030f,100.0f,100.0f +#define SNDMIX_REVERB_PRESET_CONCERTHALL \ + -1000, -500, 3.92f,0.70f, -1230,0.020f, -2,0.029f,100.0f,100.0f +#define SNDMIX_REVERB_PRESET_CAVE \ + -1000, 0, 2.91f,1.30f, -602,0.015f, -302,0.022f,100.0f,100.0f +#define SNDMIX_REVERB_PRESET_ARENA \ + -1000, -698, 7.24f,0.33f, -1166,0.020f, 16,0.030f,100.0f,100.0f +#define SNDMIX_REVERB_PRESET_HANGAR \ + -1000,-1000,10.05f,0.23f, -602,0.020f, 198,0.030f,100.0f,100.0f +#define SNDMIX_REVERB_PRESET_CARPETEDHALLWAY \ + -1000,-4000, 0.30f,0.10f, -1831,0.002f, -1630,0.030f,100.0f,100.0f +#define SNDMIX_REVERB_PRESET_HALLWAY \ + -1000, -300, 1.49f,0.59f, -1219,0.007f, 441,0.011f,100.0f,100.0f +#define SNDMIX_REVERB_PRESET_STONECORRIDOR \ + -1000, -237, 2.70f,0.79f, -1214,0.013f, 395,0.020f,100.0f,100.0f +#define SNDMIX_REVERB_PRESET_ALLEY \ + -1000, -270, 1.49f,0.86f, -1204,0.007f, -4,0.011f,100.0f,100.0f +#define SNDMIX_REVERB_PRESET_FOREST \ + -1000,-3300, 1.49f,0.54f, -2560,0.162f, -613,0.088f, 79.0f,100.0f +#define SNDMIX_REVERB_PRESET_CITY \ + -1000, -800, 1.49f,0.67f, -2273,0.007f, -2217,0.011f, 50.0f,100.0f +#define SNDMIX_REVERB_PRESET_MOUNTAINS \ + -1000,-2500, 1.49f,0.21f, -2780,0.300f, -2014,0.100f, 27.0f,100.0f +#define SNDMIX_REVERB_PRESET_QUARRY \ + -1000,-1000, 1.49f,0.83f,-10000,0.061f, 500,0.025f,100.0f,100.0f +#define SNDMIX_REVERB_PRESET_PLAIN \ + -1000,-2000, 1.49f,0.50f, -2466,0.179f, -2514,0.100f, 21.0f,100.0f +#define SNDMIX_REVERB_PRESET_PARKINGLOT \ + -1000, 0, 1.65f,1.50f, -1363,0.008f, -1153,0.012f,100.0f,100.0f +#define SNDMIX_REVERB_PRESET_SEWERPIPE \ + -1000,-1000, 2.81f,0.14f, 429,0.014f, 648,0.021f, 80.0f, 60.0f +#define SNDMIX_REVERB_PRESET_UNDERWATER \ + -1000,-4000, 1.49f,0.10f, -449,0.007f, 1700,0.011f,100.0f,100.0f + +// Examples simulating General MIDI 2'musical' reverb presets +// +// Name (Decay time) Description +// +// Small Room (1.1s) A small size room with a length of 5m or so. +// Medium Room (1.3s) A medium size room with a length of 10m or so. +// Large Room (1.5s) A large size room suitable for live performances. +// Medium Hall (1.8s) A medium size concert hall. +// Large Hall (1.8s) A large size concert hall suitable for a full orchestra. +// Plate (1.3s) A plate reverb simulation. + +#define SNDMIX_REVERB_PRESET_SMALLROOM \ + -1000, -600, 1.10f,0.83f, -400,0.005f, 500,0.010f,100.0f,100.0f +#define SNDMIX_REVERB_PRESET_MEDIUMROOM \ + -1000, -600, 1.30f,0.83f, -1000,0.010f, -200,0.020f,100.0f,100.0f +#define SNDMIX_REVERB_PRESET_LARGEROOM \ + -1000, -600, 1.50f,0.83f, -1600,0.020f, -1000,0.040f,100.0f,100.0f +#define SNDMIX_REVERB_PRESET_MEDIUMHALL \ + -1000, -600, 1.80f,0.70f, -1300,0.015f, -800,0.030f,100.0f,100.0f +#define SNDMIX_REVERB_PRESET_LARGEHALL \ + -1000, -600, 1.80f,0.70f, -2000,0.030f, -1400,0.060f,100.0f,100.0f +#define SNDMIX_REVERB_PRESET_PLATE \ + -1000, -200, 1.30f,0.90f, 0,0.002f, 0,0.010f,100.0f, 75.0f + + +#endif // NO_REVERB Deleted: trunk/OpenMPT/soundlib/Snd_rvb.cpp =================================================================== --- trunk/OpenMPT/soundlib/Snd_rvb.cpp 2013-04-11 17:21:26 UTC (rev 1843) +++ trunk/OpenMPT/soundlib/Snd_rvb.cpp 2013-04-11 18:09:59 UTC (rev 1844) @@ -1,1096 +0,0 @@ -/* - * Snd_rvb.cpp - * ----------- - * Purpose: Mixing code for reverb. - * Notes : Ugh... This should really be removed at some point. - * Authors: Olivier Lapicque - * OpenMPT Devs - * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. - */ - - -#include "stdafx.h" -#include "sndfile.h" -#include "snd_rvb.h" - -#ifndef NO_REVERB - -#pragma warning(disable:4725) // Pentium fdiv bug -#pragma warning(disable:4731) // ebp modified - -extern VOID MPPASMCALL X86_StereoFill(int *pBuffer, UINT nSamples, LPLONG lpROfs, LPLONG lpLOfs); - - - -CReverbSettings::CReverbSettings() -//-------------------------------- -{ - m_nReverbType = 0; - m_nReverbDepth = 8; // 50% -} - - -CReverb::CReverb() -//---------------- -{ - - // Shared reverb state - gnReverbSamples = 0; - gnReverbDecaySamples = 0; - gnReverbSend = 0; - gnRvbROfsVol = 0; - gnRvbLOfsVol = 0; - - // Internal reverb state - g_bLastInPresent = 0; - g_bLastOutPresent = 0; - g_nLastRvbIn_xl = 0; - g_nLastRvbIn_xr = 0; - g_nLastRvbIn_yl = 0; - g_nLastRvbIn_yr = 0; - g_nLastRvbOut_xl = 0; - g_nLastRvbOut_xr = 0; - gnDCRRvb_Y1 = 0; - gnDCRRvb_X1 = 0; - - // Reverb mix buffers - MemsetZero(g_RefDelay); - MemsetZero(g_LateReverb); - -} - - -// Misc functions -static LONG OnePoleLowPassCoef(LONG scale, FLOAT g, FLOAT F_c, FLOAT F_s); -static LONG mBToLinear(LONG scale, LONG value_mB); -static FLOAT mBToLinear(LONG value_mB); - -struct SNDMIX_REVERB_PROPERTIES -{ - LONG lRoom; // [-10000, 0] default: -10000 mB - LONG lRoomHF; // [-10000, 0] default: 0 mB - FLOAT flDecayTime; // [0.1, 20.0] default: 1.0 s - FLOAT flDecayHFRatio; // [0.1, 2.0] default: 0.5 - LONG lReflections; // [-10000, 1000] default: -10000 mB - FLOAT flReflectionsDelay; // [0.0, 0.3] default: 0.02 s - LONG lReverb; // [-10000, 2000] default: -10000 mB - FLOAT flReverbDelay; // [0.0, 0.1] default: 0.04 s - FLOAT flDiffusion; // [0.0, 100.0] default: 100.0 % - FLOAT flDensity; // [0.0, 100.0] default: 100.0 % -}; -typedef SNDMIX_REVERB_PROPERTIES* PSNDMIX_REVERB_PROPERTIES; - -typedef struct _SNDMIX_RVBPRESET -{ - SNDMIX_REVERB_PROPERTIES Preset; - LPCSTR lpszName; -} SNDMIX_RVBPRESET, *PSNDMIX_RVBPRESET; - - -static SNDMIX_RVBPRESET gRvbPresets[NUM_REVERBTYPES] = -{ - {{ SNDMIX_REVERB_PRESET_PLATE }, "GM Plate"}, - {{ SNDMIX_REVERB_PRESET_SMALLROOM }, "GM Small Room"}, - {{ SNDMIX_REVERB_PRESET_MEDIUMROOM }, "GM Medium Room"}, - {{ SNDMIX_REVERB_PRESET_LARGEROOM }, "GM Large Room"}, - {{ SNDMIX_REVERB_PRESET_MEDIUMHALL }, "GM Medium Hall"}, - {{ SNDMIX_REVERB_PRESET_LARGEHALL }, "GM Large Hall"}, - {{ SNDMIX_REVERB_PRESET_GENERIC }, "Generic"}, - {{ SNDMIX_REVERB_PRESET_PADDEDCELL }, "Padded Cell"}, - {{ SNDMIX_REVERB_PRESET_ROOM }, "Room"}, - {{ SNDMIX_REVERB_PRESET_BATHROOM }, "Bathroom"}, - {{ SNDMIX_REVERB_PRESET_LIVINGROOM }, "Living Room"}, - {{ SNDMIX_REVERB_PRESET_STONEROOM }, "Stone Room"}, - {{ SNDMIX_REVERB_PRESET_AUDITORIUM }, "Auditorium"}, - {{ SNDMIX_REVERB_PRESET_CONCERTHALL }, "Concert Hall"}, - {{ SNDMIX_REVERB_PRESET_CAVE }, "Cave"}, - {{ SNDMIX_REVERB_PRESET_ARENA }, "Arena"}, - {{ SNDMIX_REVERB_PRESET_HANGAR }, "Hangar"}, - {{ SNDMIX_REVERB_PRESET_CARPETEDHALLWAY }, "Carpeted Hallway"}, - {{ SNDMIX_REVERB_PRESET_HALLWAY }, "Hallway"}, - {{ SNDMIX_REVERB_PRESET_STONECORRIDOR }, "Stone Corridor"}, - {{ SNDMIX_REVERB_PRESET_ALLEY }, "Alley"}, - {{ SNDMIX_REVERB_PRESET_FOREST }, "Forest"}, - {{ SNDMIX_REVERB_PRESET_CITY }, "City"}, - {{ SNDMIX_REVERB_PRESET_MOUNTAINS }, "Mountains"}, - {{ SNDMIX_REVERB_PRESET_QUARRY }, "Quarry"}, - {{ SNDMIX_REVERB_PRESET_PLAIN }, "Plain"}, - {{ SNDMIX_REVERB_PRESET_PARKINGLOT }, "Parking Lot"}, - {{ SNDMIX_REVERB_PRESET_SEWERPIPE }, "Sewer Pipe"}, - {{ SNDMIX_REVERB_PRESET_UNDERWATER }, "Underwater"}, -}; - -LPCSTR GetReverbPresetName(UINT nPreset) -{ - return (nPreset < NUM_REVERBTYPES) ? gRvbPresets[nPreset].lpszName : NULL; -} - -////////////////////////////////////////////////////////////////////////// -// -// I3DL2 environmental reverb support -// - -typedef struct _REFLECTIONPRESET -{ - LONG lDelayFactor; - SHORT sGainLL, sGainRR, sGainLR, sGainRL; -} REFLECTIONPRESET, *PREFLECTIONPRESET; - -const REFLECTIONPRESET gReflectionsPreset[ENVIRONMENT_NUMREFLECTIONS] = -{ - // %Delay, ll, rr, lr, rl - {0, 9830, 6554, 0, 0}, - {10, 6554, 13107, 0, 0}, - {24, -9830, 13107, 0, 0}, - {36, 13107, -6554, 0, 0}, - {54, 16384, 16384, -1638, -1638}, - {61, -13107, 8192, -328, -328}, - {73, -11468, -11468, -3277, 3277}, - {87, 13107, -9830, 4916, -4916} -}; - -//////////////////////////////////////////////////////////////////////////////////// -// -// Implementation -// - -inline long ftol(float f) { return ((long)(f)); } - -static VOID I3dl2_to_Generic( - const SNDMIX_REVERB_PROPERTIES *pReverb, - PENVIRONMENTREVERB pRvb, - FLOAT flOutputFreq, - LONG lMinRefDelay, - LONG lMaxRefDelay, - LONG lMinRvbDelay, - LONG lMaxRvbDelay, - LONG lTankLength) -{ - FLOAT flDelayFactor, flDelayFactorHF, flDecayTimeHF; - LONG lDensity, lTailDiffusion; - - // Common parameters - pRvb->ReverbLevel = pReverb->lReverb; - pRvb->ReflectionsLevel = pReverb->lReflections; - pRvb->RoomHF = pReverb->lRoomHF; - - // HACK: Somewhat normalize the reverb output level - LONG lMaxLevel = (pRvb->ReverbLevel > pRvb->ReflectionsLevel) ? pRvb->ReverbLevel : pRvb->ReflectionsLevel; - if (lMaxLevel < -600) - { - lMaxLevel += 600; - pRvb->ReverbLevel -= lMaxLevel; - pRvb->ReflectionsLevel -= lMaxLevel; - } - - // Pre-Diffusion factor (for both reflections and late reverb) - lDensity = 8192 + ftol(79.31f * pReverb->flDensity); - pRvb->PreDiffusion = lDensity; - - // Late reverb diffusion - lTailDiffusion = ftol((0.15f + pReverb->flDiffusion * (0.36f*0.01f)) * 32767.0f); - if (lTailDiffusion > 0x7f00) lTailDiffusion = 0x7f00; - pRvb->TankDiffusion = lTailDiffusion; - - // Verify reflections and reverb delay parameters - FLOAT flRefDelay = pReverb->flReflectionsDelay; - if (flRefDelay > 0.100f) flRefDelay = 0.100f; - LONG lReverbDelay = ftol(pReverb->flReverbDelay * flOutputFreq); - LONG lReflectionsDelay = ftol(flRefDelay * flOutputFreq); - LONG lReverbDecayTime = ftol(pReverb->flDecayTime * flOutputFreq); - if (lReflectionsDelay < lMinRefDelay) - { - lReverbDelay -= (lMinRefDelay - lReflectionsDelay); - lReflectionsDelay = lMinRefDelay; - } - if (lReflectionsDelay > lMaxRefDelay) - { - lReverbDelay += (lReflectionsDelay - lMaxRefDelay); - lReflectionsDelay = lMaxRefDelay; - } - // Adjust decay time when adjusting reverb delay - if (lReverbDelay < lMinRvbDelay) - { - lReverbDecayTime -= (lMinRvbDelay - lReverbDelay); - lReverbDelay = lMinRvbDelay; - } - if (lReverbDelay > lMaxRvbDelay) - { - lReverbDecayTime += (lReverbDelay - lMaxRvbDelay); - lReverbDelay = lMaxRvbDelay; - } - pRvb->ReverbDelay = lReverbDelay; - pRvb->ReverbDecaySamples = lReverbDecayTime; - // Setup individual reflections delay and gains - for (UINT iRef=0; iRef<ENVIRONMENT_NUMREFLECTIONS; iRef++) - { - PENVIRONMENTREFLECTION pRef = &pRvb->Reflections[iRef]; - pRef->Delay = lReflectionsDelay + (gReflectionsPreset[iRef].lDelayFactor * lReverbDelay + 50)/100; - pRef->GainLL = gReflectionsPreset[iRef].sGainLL; - pRef->GainRL = gReflectionsPreset[iRef].sGainRL; - pRef->GainLR = gReflectionsPreset[iRef].sGainLR; - pRef->GainRR = gReflectionsPreset[iRef].sGainRR; - } - - // Late reverb decay time - if (lTankLength < 10) lTankLength = 10; - flDelayFactor = (lReverbDecayTime <= lTankLength) ? 1.0f : ((FLOAT)lTankLength / (FLOAT)lReverbDecayTime); - pRvb->ReverbDecay = ftol(pow(0.001f, flDelayFactor) * 32768.0f); - - // Late Reverb Decay HF - flDecayTimeHF = (FLOAT)lReverbDecayTime * pReverb->flDecayHFRatio; - flDelayFactorHF = (flDecayTimeHF <= (FLOAT)lTankLength) ? 1.0f : ((FLOAT)lTankLength / flDecayTimeHF); - pRvb->flReverbDamping = pow(0.001f, flDelayFactorHF); -} - - -void CReverb::Shutdown() -//---------------------- -{ - gnRvbLOfsVol = 0; - gnRvbROfsVol = 0; - - // Clear out all reverb state - g_bLastInPresent = FALSE; - g_bLastOutPresent = FALSE; - g_nLastRvbIn_xl = g_nLastRvbIn_xr = 0; - g_nLastRvbIn_yl = g_nLastRvbIn_yr = 0; - g_nLastRvbOut_xl = g_nLastRvbOut_xr = 0; - gnDCRRvb_X1 = 0; - gnDCRRvb_Y1 = 0; - - // Zero internal buffers - MemsetZero(g_LateReverb.Diffusion1); - MemsetZero(g_LateReverb.Diffusion2); - MemsetZero(g_LateReverb.Delay1); - MemsetZero(g_LateReverb.Delay2); - MemsetZero(g_RefDelay.RefDelayBuffer); - MemsetZero(g_RefDelay.PreDifBuffer); - MemsetZero(g_RefDelay.RefOut); -} - - -void CReverb::Initialize(BOOL bReset, DWORD MixingFreq) -//----------------------------------------------------- -{ - if (m_Settings.m_nReverbType >= NUM_REVERBTYPES) m_Settings.m_nReverbType = 0; - static PSNDMIX_REVERB_PROPERTIES spCurrentPreset = NULL; - PSNDMIX_REVERB_PROPERTIES pRvbPreset = &gRvbPresets[m_Settings.m_nReverbType].Preset; - - if ((pRvbPreset != spCurrentPreset) || (bReset)) - { - // Reverb output frequency is half of the dry output rate - FLOAT flOutputFrequency = (FLOAT)MixingFreq; - ENVIRONMENTREVERB rvb; - - // Reset reverb parameters - spCurrentPreset = pRvbPreset; - I3dl2_to_Generic(pRvbPreset, &rvb, flOutputFrequency, - RVBMINREFDELAY, RVBMAXREFDELAY, - RVBMINRVBDELAY, RVBMAXRVBDELAY, - ( RVBDIF1L_LEN + RVBDIF1R_LEN - + RVBDIF2L_LEN + RVBDIF2R_LEN - + RVBDLY1L_LEN + RVBDLY1R_LEN - + RVBDLY2L_LEN + RVBDLY2R_LEN) / 2); - - // Store reverb decay time (in samples) for reverb auto-shutdown - gnReverbDecaySamples = rvb.ReverbDecaySamples; - - // Room attenuation at high frequencies - LONG nRoomLP; - nRoomLP = OnePoleLowPassCoef(32768, mBToLinear(rvb.RoomHF), 5000, flOutputFrequency); - g_RefDelay.nCoeffs[0] = (SHORT)nRoomLP; - g_RefDelay.nCoeffs[1] = (SHORT)nRoomLP; - - // Pre-Diffusion factor (for both reflections and late reverb) - g_RefDelay.nPreDifCoeffs[0] = (SHORT)(rvb.PreDiffusion*2); - g_RefDelay.nPreDifCoeffs[1] = (SHORT)(rvb.PreDiffusion*2); - - // Setup individual reflections delay and gains - for (UINT iRef=0; iRef<8; iRef++) - { - PSWRVBREFLECTION pRef = &g_RefDelay.Reflections[iRef]; - pRef->DelayDest = rvb.Reflections[iRef].Delay; - pR... [truncated message content] |