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