cog/Frameworks/OpenMPT/OpenMPT/soundlib/plugins/dmo/Echo.cpp

208 lines
4.6 KiB
C++

/*
* Echo.cpp
* --------
* Purpose: Implementation of the DMO Echo 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 "Echo.h"
#endif // !NO_PLUGINS
OPENMPT_NAMESPACE_BEGIN
#ifndef NO_PLUGINS
namespace DMO
{
IMixPlugin* Echo::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
{
return new (std::nothrow) Echo(factory, sndFile, mixStruct);
}
Echo::Echo(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
: IMixPlugin(factory, sndFile, mixStruct)
, m_bufferSize(0)
, m_writePos(0)
, m_sampleRate(sndFile.GetSampleRate())
, m_initialFeedback(0.0f)
{
m_param[kEchoWetDry] = 0.5f;
m_param[kEchoFeedback] = 0.5f;
m_param[kEchoLeftDelay] = (500.0f - 1.0f) / 1999.0f;
m_param[kEchoRightDelay] = (500.0f - 1.0f) / 1999.0f;
m_param[kEchoPanDelay] = 0.0f;
m_mixBuffer.Initialize(2, 2);
InsertIntoFactoryList();
}
void Echo::Process(float *pOutL, float *pOutR, uint32 numFrames)
{
if(!m_bufferSize || !m_mixBuffer.Ok())
return;
const float wetMix = m_param[kEchoWetDry], dryMix = 1 - wetMix;
const float *in[2] = { m_mixBuffer.GetInputBuffer(0), m_mixBuffer.GetInputBuffer(1) };
float *out[2] = { m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1) };
for(uint32 i = numFrames; i != 0; i--)
{
for(uint8 channel = 0; channel < 2; channel++)
{
const uint8 readChannel = (m_crossEcho ? (1 - channel) : channel);
int readPos = m_writePos - m_delayTime[readChannel];
if(readPos < 0)
readPos += m_bufferSize;
float chnInput = *(in[channel])++;
float chnDelay = m_delayLine[readPos * 2 + readChannel];
// Calculate the delay
float chnOutput = chnInput * m_initialFeedback;
chnOutput += chnDelay * m_param[kEchoFeedback];
// Prevent denormals
if(std::abs(chnOutput) < 1e-24f)
chnOutput = 0.0f;
m_delayLine[m_writePos * 2 + channel] = chnOutput;
// Output samples now
*(out[channel])++ = (chnInput * dryMix + chnDelay * wetMix);
}
m_writePos++;
if(m_writePos == m_bufferSize)
m_writePos = 0;
}
ProcessMixOps(pOutL, pOutR, m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1), numFrames);
}
PlugParamValue Echo::GetParameter(PlugParamIndex index)
{
if(index < kEchoNumParameters)
{
return m_param[index];
}
return 0;
}
void Echo::SetParameter(PlugParamIndex index, PlugParamValue value)
{
if(index < kEchoNumParameters)
{
value = mpt::safe_clamp(value, 0.0f, 1.0f);
if(index == kEchoPanDelay)
value = mpt::round(value);
m_param[index] = value;
RecalculateEchoParams();
}
}
void Echo::Resume()
{
m_isResumed = true;
m_sampleRate = m_SndFile.GetSampleRate();
RecalculateEchoParams();
PositionChanged();
}
void Echo::PositionChanged()
{
m_bufferSize = m_sampleRate * 2u;
try
{
m_delayLine.assign(m_bufferSize * 2, 0);
} catch(mpt::out_of_memory e)
{
mpt::delete_out_of_memory(e);
m_bufferSize = 0;
}
m_writePos = 0;
}
#ifdef MODPLUG_TRACKER
CString Echo::GetParamName(PlugParamIndex param)
{
switch(param)
{
case kEchoWetDry: return _T("WetDryMix");
case kEchoFeedback: return _T("Feedback");
case kEchoLeftDelay: return _T("LeftDelay");
case kEchoRightDelay: return _T("RightDelay");
case kEchoPanDelay: return _T("PanDelay");
}
return CString();
}
CString Echo::GetParamLabel(PlugParamIndex param)
{
switch(param)
{
case kEchoFeedback:
return _T("%");
case kEchoLeftDelay:
case kEchoRightDelay:
return _T("ms");
default:
return CString{};
}
}
CString Echo::GetParamDisplay(PlugParamIndex param)
{
CString s;
switch(param)
{
case kEchoWetDry:
s.Format(_T("%.1f : %.1f"), m_param[param] * 100.0f, 100.0f - m_param[param] * 100.0f);
break;
case kEchoFeedback:
s.Format(_T("%.2f"), m_param[param] * 100.0f);
break;
case kEchoLeftDelay:
case kEchoRightDelay:
s.Format(_T("%.2f"), 1.0f + m_param[param] * 1999.0f);
break;
case kEchoPanDelay:
s = (m_param[param] <= 0.5) ? _T("No") : _T("Yes");
}
return s;
}
#endif // MODPLUG_TRACKER
void Echo::RecalculateEchoParams()
{
m_initialFeedback = std::sqrt(1.0f - (m_param[kEchoFeedback] * m_param[kEchoFeedback]));
m_delayTime[0] = static_cast<uint32>((1.0f + m_param[kEchoLeftDelay] * 1999.0f) / 1000.0f * m_sampleRate);
m_delayTime[1] = static_cast<uint32>((1.0f + m_param[kEchoRightDelay] * 1999.0f) / 1000.0f * m_sampleRate);
m_crossEcho = (m_param[kEchoPanDelay]) > 0.5f;
}
} // namespace DMO
#else
MPT_MSVC_WORKAROUND_LNK4221(Echo)
#endif // !NO_PLUGINS
OPENMPT_NAMESPACE_END