winamp/Src/external_dependencies/openmpt-trunk/soundlib/plugins/dmo/WavesReverb.cpp
2024-09-24 14:54:57 +02:00

262 lines
7.4 KiB
C++

/*
* WavesReverb.cpp
* ---------------
* Purpose: Implementation of the DMO WavesReverb DSP (for non-Windows platforms)
* Notes : (currently none)
* Authors: OpenMPT Devs
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
*/
#include "stdafx.h"
#ifndef NO_PLUGINS
#include "../../Sndfile.h"
#include "WavesReverb.h"
#endif // !NO_PLUGINS
OPENMPT_NAMESPACE_BEGIN
#ifndef NO_PLUGINS
namespace DMO
{
IMixPlugin* WavesReverb::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
{
return new (std::nothrow) WavesReverb(factory, sndFile, mixStruct);
}
WavesReverb::WavesReverb(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
: IMixPlugin(factory, sndFile, mixStruct)
{
m_param[kRvbInGain] = 1.0f;
m_param[kRvbReverbMix] = 1.0f;
m_param[kRvbReverbTime] = 1.0f / 3.0f;
m_param[kRvbHighFreqRTRatio] = 0.0f;
m_mixBuffer.Initialize(2, 2);
InsertIntoFactoryList();
}
void WavesReverb::Process(float *pOutL, float *pOutR, uint32 numFrames)
{
if(!m_mixBuffer.Ok())
return;
const float *in[2] = { m_mixBuffer.GetInputBuffer(0), m_mixBuffer.GetInputBuffer(1) };
float *out[2] = { m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1) };
uint32 combPos = m_state.combPos, allpassPos = m_state.allpassPos;
uint32 delay0 = (m_delay[0] + combPos + 1) & 0xFFF;
uint32 delay1 = (m_delay[1] + combPos + 1) & 0xFFF;
uint32 delay2 = (m_delay[2] + combPos + 1) & 0xFFF;
uint32 delay3 = (m_delay[3] + combPos + 1) & 0xFFF;
uint32 delay4 = (m_delay[4] + allpassPos) & 0x3FF;
uint32 delay5 = (m_delay[5] + allpassPos) & 0x3FF;
float delay0old = m_state.comb[delay0][0];
float delay1old = m_state.comb[delay1][1];
float delay2old = m_state.comb[delay2][2];
float delay3old = m_state.comb[delay3][3];
for(uint32 i = numFrames; i != 0; i--)
{
const float leftIn = *(in[0])++ + 1e-30f; // Prevent denormals
const float rightIn = *(in[1])++ + 1e-30f; // Prevent denormals
// Advance buffer index for the four comb filters
delay0 = (delay0 - 1) & 0xFFF;
delay1 = (delay1 - 1) & 0xFFF;
delay2 = (delay2 - 1) & 0xFFF;
delay3 = (delay3 - 1) & 0xFFF;
float &delay0new = m_state.comb[delay0][0];
float &delay1new = m_state.comb[delay1][1];
float &delay2new = m_state.comb[delay2][2];
float &delay3new = m_state.comb[delay3][3];
float r1, r2;
r1 = delay1new * 0.61803401f + m_state.allpass1[delay4][0] * m_coeffs[0];
r2 = m_state.allpass1[delay4][1] * m_coeffs[0] - delay0new * 0.61803401f;
m_state.allpass1[allpassPos][0] = r2 * 0.61803401f + delay0new;
m_state.allpass1[allpassPos][1] = delay1new - r1 * 0.61803401f;
delay0new = r1;
delay1new = r2;
r1 = delay3new * 0.61803401f + m_state.allpass2[delay5][0] * m_coeffs[1];
r2 = m_state.allpass2[delay5][1] * m_coeffs[1] - delay2new * 0.61803401f;
m_state.allpass2[allpassPos][0] = r2 * 0.61803401f + delay2new;
m_state.allpass2[allpassPos][1] = delay3new - r1 * 0.61803401f;
delay2new = r1;
delay3new = r2;
*(out[0])++ = (leftIn * m_dryFactor) + delay0new + delay2new;
*(out[1])++ = (rightIn * m_dryFactor) + delay1new + delay3new;
const float leftWet = leftIn * m_wetFactor;
const float rightWet = rightIn * m_wetFactor;
m_state.comb[combPos][0] = (delay0new * m_coeffs[2]) + (delay0old * m_coeffs[3]) + leftWet;
m_state.comb[combPos][1] = (delay1new * m_coeffs[4]) + (delay1old * m_coeffs[5]) + rightWet;
m_state.comb[combPos][2] = (delay2new * m_coeffs[6]) + (delay2old * m_coeffs[7]) - rightWet;
m_state.comb[combPos][3] = (delay3new * m_coeffs[8]) + (delay3old * m_coeffs[9]) + leftWet;
delay0old = delay0new;
delay1old = delay1new;
delay2old = delay2new;
delay3old = delay3new;
// Advance buffer index
combPos = (combPos - 1) & 0xFFF;
allpassPos = (allpassPos - 1) & 0x3FF;
delay4 = (delay4 - 1) & 0x3FF;
delay5 = (delay5 - 1) & 0x3FF;
}
m_state.combPos = combPos;
m_state.allpassPos = allpassPos;
ProcessMixOps(pOutL, pOutR, m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1), numFrames);
}
PlugParamValue WavesReverb::GetParameter(PlugParamIndex index)
{
if(index < kRvbNumParameters)
{
return m_param[index];
}
return 0;
}
void WavesReverb::SetParameter(PlugParamIndex index, PlugParamValue value)
{
if(index < kRvbNumParameters)
{
value = mpt::safe_clamp(value, 0.0f, 1.0f);
m_param[index] = value;
RecalculateWavesReverbParams();
}
}
void WavesReverb::Resume()
{
m_isResumed = true;
// Recalculate delays
uint32 delay0 = mpt::saturate_round<uint32>(m_SndFile.GetSampleRate() * 0.045f);
uint32 delay1 = mpt::saturate_round<uint32>(delay0 * 1.18920707f); // 2^0.25
uint32 delay2 = mpt::saturate_round<uint32>(delay1 * 1.18920707f);
uint32 delay3 = mpt::saturate_round<uint32>(delay2 * 1.18920707f);
uint32 delay4 = mpt::saturate_round<uint32>((delay0 + delay2) * 0.11546667f);
uint32 delay5 = mpt::saturate_round<uint32>((delay1 + delay3) * 0.11546667f);
// Comb delays
m_delay[0] = delay0 - delay4;
m_delay[1] = delay2 - delay4;
m_delay[2] = delay1 - delay5;
m_delay[3] = delay3 - delay5;
// Allpass delays
m_delay[4] = delay4;
m_delay[5] = delay5;
RecalculateWavesReverbParams();
PositionChanged();
}
void WavesReverb::PositionChanged()
{
MemsetZero(m_state);
}
#ifdef MODPLUG_TRACKER
CString WavesReverb::GetParamName(PlugParamIndex param)
{
switch(param)
{
case kRvbInGain: return _T("InGain");
case kRvbReverbMix: return _T("ReverbMix");
case kRvbReverbTime: return _T("ReverbTime");
case kRvbHighFreqRTRatio: return _T("HighFreqRTRatio");
}
return CString();
}
CString WavesReverb::GetParamLabel(PlugParamIndex param)
{
switch(param)
{
case kRvbInGain:
case kRvbReverbMix:
return _T("dB");
case kRvbReverbTime:
return _T("ms");
}
return CString();
}
CString WavesReverb::GetParamDisplay(PlugParamIndex param)
{
float value = m_param[param];
switch(param)
{
case kRvbInGain:
case kRvbReverbMix:
value = GainInDecibel(value);
break;
case kRvbReverbTime:
value = ReverbTime();
break;
case kRvbHighFreqRTRatio:
value = HighFreqRTRatio();
break;
}
CString s;
s.Format(_T("%.2f"), value);
return s;
}
#endif // MODPLUG_TRACKER
void WavesReverb::RecalculateWavesReverbParams()
{
// Recalculate filters
const double ReverbTimeSmp = -3000.0 / (m_SndFile.GetSampleRate() * ReverbTime());
const double ReverbTimeSmpHF = ReverbTimeSmp * (1.0 / HighFreqRTRatio() - 1.0);
m_coeffs[0] = static_cast<float>(std::pow(10.0, m_delay[4] * ReverbTimeSmp));
m_coeffs[1] = static_cast<float>(std::pow(10.0, m_delay[5] * ReverbTimeSmp));
double sum = 0.0;
for(uint32 pair = 0; pair < 4; pair++)
{
double gain1 = std::pow(10.0, m_delay[pair] * ReverbTimeSmp);
double gain2 = (1.0 - std::pow(10.0, (m_delay[pair] + m_delay[4 + pair / 2]) * ReverbTimeSmpHF)) * 0.5;
double gain3 = gain1 * m_coeffs[pair / 2];
double gain4 = gain3 * (((gain3 + 1.0) * gain3 + 1.0) * gain3 + 1.0) + 1.0;
m_coeffs[2 + pair * 2] = static_cast<float>(gain1 * (1.0 - gain2));
m_coeffs[3 + pair * 2] = static_cast<float>(gain1 * gain2);
sum += gain4 * gain4;
}
double inGain = std::pow(10.0, GainInDecibel(m_param[kRvbInGain]) * 0.05);
double reverbMix = std::pow(10.0, GainInDecibel(m_param[kRvbReverbMix]) * 0.1);
m_dryFactor = static_cast<float>(std::sqrt(1.0 - reverbMix) * inGain);
m_wetFactor = static_cast<float>(std::sqrt(reverbMix) * (4.0 / std::sqrt(sum) * inGain));
}
} // namespace DMO
#else
MPT_MSVC_WORKAROUND_LNK4221(WavesReverb)
#endif // !NO_PLUGINS
OPENMPT_NAMESPACE_END