1 /*
2  * WavesReverb.cpp
3  * ---------------
4  * Purpose: Implementation of the DMO WavesReverb DSP (for non-Windows platforms)
5  * Notes  : (currently none)
6  * Authors: OpenMPT Devs
7  * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
8  */
9 
10 
11 #include "stdafx.h"
12 
13 #ifndef NO_PLUGINS
14 #include "../../Sndfile.h"
15 #include "WavesReverb.h"
16 #endif // !NO_PLUGINS
17 
18 OPENMPT_NAMESPACE_BEGIN
19 
20 #ifndef NO_PLUGINS
21 
22 namespace DMO
23 {
24 
Create(VSTPluginLib & factory,CSoundFile & sndFile,SNDMIXPLUGIN * mixStruct)25 IMixPlugin* WavesReverb::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
26 {
27 	return new (std::nothrow) WavesReverb(factory, sndFile, mixStruct);
28 }
29 
30 
WavesReverb(VSTPluginLib & factory,CSoundFile & sndFile,SNDMIXPLUGIN * mixStruct)31 WavesReverb::WavesReverb(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
32 	: IMixPlugin(factory, sndFile, mixStruct)
33 {
34 	m_param[kRvbInGain] = 1.0f;
35 	m_param[kRvbReverbMix] = 1.0f;
36 	m_param[kRvbReverbTime] = 1.0f / 3.0f;
37 	m_param[kRvbHighFreqRTRatio] = 0.0f;
38 
39 	m_mixBuffer.Initialize(2, 2);
40 	InsertIntoFactoryList();
41 }
42 
43 
Process(float * pOutL,float * pOutR,uint32 numFrames)44 void WavesReverb::Process(float *pOutL, float *pOutR, uint32 numFrames)
45 {
46 	if(!m_mixBuffer.Ok())
47 		return;
48 
49 	const float *in[2] = { m_mixBuffer.GetInputBuffer(0), m_mixBuffer.GetInputBuffer(1) };
50 	float *out[2] = { m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1) };
51 
52 	uint32 combPos = m_state.combPos, allpassPos = m_state.allpassPos;
53 	uint32 delay0 = (m_delay[0] + combPos + 1) & 0xFFF;
54 	uint32 delay1 = (m_delay[1] + combPos + 1) & 0xFFF;
55 	uint32 delay2 = (m_delay[2] + combPos + 1) & 0xFFF;
56 	uint32 delay3 = (m_delay[3] + combPos + 1) & 0xFFF;
57 	uint32 delay4 = (m_delay[4] + allpassPos) & 0x3FF;
58 	uint32 delay5 = (m_delay[5] + allpassPos) & 0x3FF;
59 	float delay0old = m_state.comb[delay0][0];
60 	float delay1old = m_state.comb[delay1][1];
61 	float delay2old = m_state.comb[delay2][2];
62 	float delay3old = m_state.comb[delay3][3];
63 
64 	for(uint32 i = numFrames; i != 0; i--)
65 	{
66 		const float leftIn  = *(in[0])++ + 1e-30f;	// Prevent denormals
67 		const float rightIn = *(in[1])++ + 1e-30f;	// Prevent denormals
68 
69 		// Advance buffer index for the four comb filters
70 		delay0 = (delay0 - 1) & 0xFFF;
71 		delay1 = (delay1 - 1) & 0xFFF;
72 		delay2 = (delay2 - 1) & 0xFFF;
73 		delay3 = (delay3 - 1) & 0xFFF;
74 		float &delay0new = m_state.comb[delay0][0];
75 		float &delay1new = m_state.comb[delay1][1];
76 		float &delay2new = m_state.comb[delay2][2];
77 		float &delay3new = m_state.comb[delay3][3];
78 
79 		float r1, r2;
80 
81 		r1 = delay1new * 0.61803401f + m_state.allpass1[delay4][0] * m_coeffs[0];
82 		r2 = m_state.allpass1[delay4][1] * m_coeffs[0] - delay0new * 0.61803401f;
83 		m_state.allpass1[allpassPos][0] = r2 * 0.61803401f + delay0new;
84 		m_state.allpass1[allpassPos][1] = delay1new - r1 * 0.61803401f;
85 		delay0new = r1;
86 		delay1new = r2;
87 
88 		r1 = delay3new * 0.61803401f + m_state.allpass2[delay5][0] * m_coeffs[1];
89 		r2 = m_state.allpass2[delay5][1] * m_coeffs[1] - delay2new * 0.61803401f;
90 		m_state.allpass2[allpassPos][0] = r2 * 0.61803401f + delay2new;
91 		m_state.allpass2[allpassPos][1] = delay3new - r1 * 0.61803401f;
92 		delay2new = r1;
93 		delay3new = r2;
94 
95 		*(out[0])++ = (leftIn  * m_dryFactor) + delay0new + delay2new;
96 		*(out[1])++ = (rightIn * m_dryFactor) + delay1new + delay3new;
97 
98 		const float leftWet  = leftIn  * m_wetFactor;
99 		const float rightWet = rightIn * m_wetFactor;
100 		m_state.comb[combPos][0] = (delay0new * m_coeffs[2]) + (delay0old * m_coeffs[3]) + leftWet;
101 		m_state.comb[combPos][1] = (delay1new * m_coeffs[4]) + (delay1old * m_coeffs[5]) + rightWet;
102 		m_state.comb[combPos][2] = (delay2new * m_coeffs[6]) + (delay2old * m_coeffs[7]) - rightWet;
103 		m_state.comb[combPos][3] = (delay3new * m_coeffs[8]) + (delay3old * m_coeffs[9]) + leftWet;
104 
105 		delay0old = delay0new;
106 		delay1old = delay1new;
107 		delay2old = delay2new;
108 		delay3old = delay3new;
109 
110 		// Advance buffer index
111 		combPos = (combPos - 1) & 0xFFF;
112 		allpassPos = (allpassPos - 1) & 0x3FF;
113 		delay4 = (delay4 - 1) & 0x3FF;
114 		delay5 = (delay5 - 1) & 0x3FF;
115 	}
116 	m_state.combPos = combPos;
117 	m_state.allpassPos = allpassPos;
118 
119 	ProcessMixOps(pOutL, pOutR, m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1), numFrames);
120 }
121 
122 
GetParameter(PlugParamIndex index)123 PlugParamValue WavesReverb::GetParameter(PlugParamIndex index)
124 {
125 	if(index < kDistNumParameters)
126 	{
127 		return m_param[index];
128 	}
129 	return 0;
130 }
131 
132 
SetParameter(PlugParamIndex index,PlugParamValue value)133 void WavesReverb::SetParameter(PlugParamIndex index, PlugParamValue value)
134 {
135 	if(index < kDistNumParameters)
136 	{
137 		value = mpt::safe_clamp(value, 0.0f, 1.0f);
138 		m_param[index] = value;
139 		RecalculateWavesReverbParams();
140 	}
141 }
142 
143 
Resume()144 void WavesReverb::Resume()
145 {
146 	m_isResumed = true;
147 	// Recalculate delays
148 	uint32 delay0 = mpt::saturate_round<uint32>(m_SndFile.GetSampleRate() * 0.045f);
149 	uint32 delay1 = mpt::saturate_round<uint32>(delay0 * 1.18920707f);	// 2^0.25
150 	uint32 delay2 = mpt::saturate_round<uint32>(delay1 * 1.18920707f);
151 	uint32 delay3 = mpt::saturate_round<uint32>(delay2 * 1.18920707f);
152 	uint32 delay4 = mpt::saturate_round<uint32>((delay0 + delay2) * 0.11546667f);
153 	uint32 delay5 = mpt::saturate_round<uint32>((delay1 + delay3) * 0.11546667f);
154 	// Comb delays
155 	m_delay[0] = delay0 - delay4;
156 	m_delay[1] = delay2 - delay4;
157 	m_delay[2] = delay1 - delay5;
158 	m_delay[3] = delay3 - delay5;
159 	// Allpass delays
160 	m_delay[4] = delay4;
161 	m_delay[5] = delay5;
162 
163 	RecalculateWavesReverbParams();
164 	PositionChanged();
165 }
166 
167 
PositionChanged()168 void WavesReverb::PositionChanged()
169 {
170 	MemsetZero(m_state);
171 }
172 
173 
174 #ifdef MODPLUG_TRACKER
175 
GetParamName(PlugParamIndex param)176 CString WavesReverb::GetParamName(PlugParamIndex param)
177 {
178 	switch(param)
179 	{
180 	case kRvbInGain: return _T("InGain");
181 	case kRvbReverbMix: return _T("ReverbMix");
182 	case kRvbReverbTime: return _T("ReverbTime");
183 	case kRvbHighFreqRTRatio: return _T("HighFreqRTRatio");
184 	}
185 	return CString();
186 }
187 
188 
GetParamLabel(PlugParamIndex param)189 CString WavesReverb::GetParamLabel(PlugParamIndex param)
190 {
191 	switch(param)
192 	{
193 	case kRvbInGain:
194 	case kRvbReverbMix:
195 		return _T("dB");
196 	case kRvbReverbTime:
197 		return _T("ms");
198 	}
199 	return CString();
200 }
201 
202 
GetParamDisplay(PlugParamIndex param)203 CString WavesReverb::GetParamDisplay(PlugParamIndex param)
204 {
205 	float value = m_param[param];
206 	switch(param)
207 	{
208 	case kRvbInGain:
209 	case kRvbReverbMix:
210 		value = GainInDecibel(value);
211 		break;
212 	case kRvbReverbTime:
213 		value = ReverbTime();
214 		break;
215 	case kRvbHighFreqRTRatio:
216 		value = HighFreqRTRatio();
217 		break;
218 	}
219 	CString s;
220 	s.Format(_T("%.2f"), value);
221 	return s;
222 }
223 
224 #endif // MODPLUG_TRACKER
225 
226 
RecalculateWavesReverbParams()227 void WavesReverb::RecalculateWavesReverbParams()
228 {
229 	// Recalculate filters
230 	const double ReverbTimeSmp = -3000.0 / (m_SndFile.GetSampleRate() * ReverbTime());
231 	const double ReverbTimeSmpHF = ReverbTimeSmp * (1.0 / HighFreqRTRatio() - 1.0);
232 
233 	m_coeffs[0] = static_cast<float>(std::pow(10.0, m_delay[4] * ReverbTimeSmp));
234 	m_coeffs[1] = static_cast<float>(std::pow(10.0, m_delay[5] * ReverbTimeSmp));
235 
236 	double sum = 0.0;
237 	for(uint32 pair = 0; pair < 4; pair++)
238 	{
239 		double gain1 = std::pow(10.0, m_delay[pair] * ReverbTimeSmp);
240 		double gain2 = (1.0 - std::pow(10.0, (m_delay[pair] + m_delay[4 + pair / 2]) * ReverbTimeSmpHF)) * 0.5;
241 		double gain3 = gain1 * m_coeffs[pair / 2];
242 		double gain4 = gain3 * (((gain3 + 1.0) * gain3 + 1.0) * gain3 + 1.0) + 1.0;
243 		m_coeffs[2 + pair * 2] = static_cast<float>(gain1 * (1.0 - gain2));
244 		m_coeffs[3 + pair * 2] = static_cast<float>(gain1 * gain2);
245 		sum += gain4 * gain4;
246 	}
247 
248 	double inGain = std::pow(10.0, GainInDecibel(m_param[kRvbInGain]) * 0.05);
249 	double reverbMix = std::pow(10.0, GainInDecibel(m_param[kRvbReverbMix]) * 0.1);
250 	m_dryFactor = static_cast<float>(std::sqrt(1.0 - reverbMix) * inGain);
251 	m_wetFactor = static_cast<float>(std::sqrt(reverbMix) * (4.0 / std::sqrt(sum) * inGain));
252 }
253 
254 } // namespace DMO
255 
256 #else
257 MPT_MSVC_WORKAROUND_LNK4221(WavesReverb)
258 
259 #endif // !NO_PLUGINS
260 
261 OPENMPT_NAMESPACE_END
262