I3DL2Reverb.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. /*
  2. * I3DL2Reverb.cpp
  3. * ---------------
  4. * Purpose: Implementation of the DMO I3DL2Reverb 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. #include "stdafx.h"
  10. #ifndef NO_PLUGINS
  11. #include "../../Sndfile.h"
  12. #include "I3DL2Reverb.h"
  13. #ifdef MODPLUG_TRACKER
  14. #include "../../../sounddsp/Reverb.h"
  15. #endif // MODPLUG_TRACKER
  16. #include "mpt/base/numbers.hpp"
  17. #endif // !NO_PLUGINS
  18. OPENMPT_NAMESPACE_BEGIN
  19. #ifndef NO_PLUGINS
  20. namespace DMO
  21. {
  22. void I3DL2Reverb::DelayLine::Init(int32 ms, int32 padding, uint32 sampleRate, int32 delayTap)
  23. {
  24. m_length = Util::muldiv(sampleRate, ms, 1000) + padding;
  25. m_position = 0;
  26. SetDelayTap(delayTap);
  27. assign(m_length, 0.0f);
  28. }
  29. void I3DL2Reverb::DelayLine::SetDelayTap(int32 delayTap)
  30. {
  31. if(m_length > 0)
  32. m_delayPosition = (delayTap + m_position + m_length) % m_length;
  33. }
  34. void I3DL2Reverb::DelayLine::Advance()
  35. {
  36. if(--m_position < 0)
  37. m_position += m_length;
  38. if(--m_delayPosition < 0)
  39. m_delayPosition += m_length;
  40. }
  41. MPT_FORCEINLINE void I3DL2Reverb::DelayLine::Set(float value)
  42. {
  43. at(m_position) = value;
  44. }
  45. float I3DL2Reverb::DelayLine::Get(int32 offset) const
  46. {
  47. offset = (offset + m_position) % m_length;
  48. if(offset < 0)
  49. offset += m_length;
  50. return at(offset);
  51. }
  52. MPT_FORCEINLINE float I3DL2Reverb::DelayLine::Get() const
  53. {
  54. return at(m_delayPosition);
  55. }
  56. IMixPlugin* I3DL2Reverb::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
  57. {
  58. return new (std::nothrow) I3DL2Reverb(factory, sndFile, mixStruct);
  59. }
  60. I3DL2Reverb::I3DL2Reverb(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
  61. : IMixPlugin(factory, sndFile, mixStruct)
  62. {
  63. m_param[kI3DL2ReverbRoom] = 0.9f;
  64. m_param[kI3DL2ReverbRoomHF] = 0.99f;
  65. m_param[kI3DL2ReverbRoomRolloffFactor] = 0.0f;
  66. m_param[kI3DL2ReverbDecayTime] = 0.07f;
  67. m_param[kI3DL2ReverbDecayHFRatio] = 0.3842105f;
  68. m_param[kI3DL2ReverbReflections] = 0.672545433f;
  69. m_param[kI3DL2ReverbReflectionsDelay] = 0.233333333f;
  70. m_param[kI3DL2ReverbReverb] = 0.85f;
  71. m_param[kI3DL2ReverbReverbDelay] = 0.11f;
  72. m_param[kI3DL2ReverbDiffusion] = 1.0f;
  73. m_param[kI3DL2ReverbDensity] = 1.0f;
  74. m_param[kI3DL2ReverbHFReference] = (5000.0f - 20.0f) / 19980.0f;
  75. m_param[kI3DL2ReverbQuality] = 2.0f / 3.0f;
  76. SetCurrentProgram(m_program);
  77. m_mixBuffer.Initialize(2, 2);
  78. InsertIntoFactoryList();
  79. }
  80. void I3DL2Reverb::Process(float *pOutL, float *pOutR, uint32 numFrames)
  81. {
  82. if(m_recalcParams)
  83. {
  84. auto sampleRate = m_effectiveSampleRate;
  85. RecalculateI3DL2ReverbParams();
  86. // Resize and clear delay lines if quality has changed
  87. if(sampleRate != m_effectiveSampleRate)
  88. PositionChanged();
  89. }
  90. if(!m_ok || !m_mixBuffer.Ok())
  91. return;
  92. const float *in[2] = { m_mixBuffer.GetInputBuffer(0), m_mixBuffer.GetInputBuffer(1) };
  93. float *out[2] = { m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1) };
  94. uint32 frames = numFrames;
  95. if(!(m_quality & kFullSampleRate) && m_remain && frames > 0)
  96. {
  97. // Remaining frame from previous render call
  98. frames--;
  99. *(out[0]++) = m_prevL;
  100. *(out[1]++) = m_prevR;
  101. in[0]++;
  102. in[1]++;
  103. m_remain = false;
  104. }
  105. while(frames > 0)
  106. {
  107. // Apply room filter and insert into early reflection delay lines
  108. const float inL = *(in[0]++);
  109. const float inRoomL = (m_filterHist[12] - inL) * m_roomFilter + inL;
  110. m_filterHist[12] = inRoomL;
  111. m_delayLines[15].Set(inRoomL);
  112. const float inR = *(in[1]++);
  113. const float inRoomR = (m_filterHist[13] - inR) * m_roomFilter + inR;
  114. m_filterHist[13] = inRoomR;
  115. m_delayLines[16].Set(inRoomR);
  116. // Early reflections (left)
  117. float earlyL = m_delayLines[15].Get(m_earlyTaps[0][1]) * 0.68f
  118. - m_delayLines[15].Get(m_earlyTaps[0][2]) * 0.5f
  119. - m_delayLines[15].Get(m_earlyTaps[0][3]) * 0.62f
  120. - m_delayLines[15].Get(m_earlyTaps[0][4]) * 0.5f
  121. - m_delayLines[15].Get(m_earlyTaps[0][5]) * 0.62f;
  122. if(m_quality & kMoreDelayLines)
  123. {
  124. float earlyL2 = earlyL;
  125. earlyL = m_delayLines[13].Get() + earlyL * 0.618034f;
  126. m_delayLines[13].Set(earlyL2 - earlyL * 0.618034f);
  127. }
  128. const float earlyRefOutL = earlyL * m_ERLevel;
  129. m_filterHist[15] = m_delayLines[15].Get(m_earlyTaps[0][0]) + m_filterHist[15];
  130. m_filterHist[16] = m_delayLines[16].Get(m_earlyTaps[1][0]) + m_filterHist[16];
  131. // Lots of slightly different copy-pasta ahead
  132. float reverbL1, reverbL2, reverbL3, reverbR1, reverbR2, reverbR3;
  133. reverbL1 = -m_filterHist[15] * 0.707f;
  134. reverbL2 = m_filterHist[16] * 0.707f + reverbL1;
  135. reverbR2 = reverbL1 - m_filterHist[16] * 0.707f;
  136. m_filterHist[5] = (m_filterHist[5] - m_delayLines[5].Get()) * m_delayCoeffs[5][1] + m_delayLines[5].Get();
  137. reverbL1 = m_filterHist[5] * m_delayCoeffs[5][0] + reverbL2 * m_diffusion;
  138. m_delayLines[5].Set(reverbL2 - reverbL1 * m_diffusion);
  139. reverbL2 = reverbL1;
  140. reverbL3 = -0.15f * reverbL1;
  141. m_filterHist[4] = (m_filterHist[4] - m_delayLines[4].Get()) * m_delayCoeffs[4][1] + m_delayLines[4].Get();
  142. reverbL1 = m_filterHist[4] * m_delayCoeffs[4][0] + reverbL2 * m_diffusion;
  143. m_delayLines[4].Set(reverbL2 - reverbL1 * m_diffusion);
  144. reverbL2 = reverbL1;
  145. reverbL3 -= reverbL1 * 0.2f;
  146. if(m_quality & kMoreDelayLines)
  147. {
  148. m_filterHist[3] = (m_filterHist[3] - m_delayLines[3].Get()) * m_delayCoeffs[3][1] + m_delayLines[3].Get();
  149. reverbL1 = m_filterHist[3] * m_delayCoeffs[3][0] + reverbL2 * m_diffusion;
  150. m_delayLines[3].Set(reverbL2 - reverbL1 * m_diffusion);
  151. reverbL2 = reverbL1;
  152. reverbL3 += 0.35f * reverbL1;
  153. m_filterHist[2] = (m_filterHist[2] - m_delayLines[2].Get()) * m_delayCoeffs[2][1] + m_delayLines[2].Get();
  154. reverbL1 = m_filterHist[2] * m_delayCoeffs[2][0] + reverbL2 * m_diffusion;
  155. m_delayLines[2].Set(reverbL2 - reverbL1 * m_diffusion);
  156. reverbL2 = reverbL1;
  157. reverbL3 -= reverbL1 * 0.38f;
  158. }
  159. m_delayLines[17].Set(reverbL2);
  160. reverbL1 = m_delayLines[17].Get() * m_delayCoeffs[12][0];
  161. m_filterHist[17] = (m_filterHist[17] - reverbL1) * m_delayCoeffs[12][1] + reverbL1;
  162. m_filterHist[1] = (m_filterHist[1] - m_delayLines[1].Get()) * m_delayCoeffs[1][1] + m_delayLines[1].Get();
  163. reverbL1 = m_filterHist[17] * m_diffusion + m_filterHist[1] * m_delayCoeffs[1][0];
  164. m_delayLines[1].Set(m_filterHist[17] - reverbL1 * m_diffusion);
  165. reverbL2 = reverbL1;
  166. float reverbL4 = reverbL1 * 0.38f;
  167. m_filterHist[0] = (m_filterHist[0] - m_delayLines[0].Get()) * m_delayCoeffs[0][1] + m_delayLines[0].Get();
  168. reverbL1 = m_filterHist[0] * m_delayCoeffs[0][0] + reverbL2 * m_diffusion;
  169. m_delayLines[0].Set(reverbL2 - reverbL1 * m_diffusion);
  170. reverbL3 -= reverbL1 * 0.38f;
  171. m_filterHist[15] = reverbL1;
  172. // Early reflections (right)
  173. float earlyR = m_delayLines[16].Get(m_earlyTaps[1][1]) * 0.707f
  174. - m_delayLines[16].Get(m_earlyTaps[1][2]) * 0.6f
  175. - m_delayLines[16].Get(m_earlyTaps[1][3]) * 0.5f
  176. - m_delayLines[16].Get(m_earlyTaps[1][4]) * 0.6f
  177. - m_delayLines[16].Get(m_earlyTaps[1][5]) * 0.5f;
  178. if(m_quality & kMoreDelayLines)
  179. {
  180. float earlyR2 = earlyR;
  181. earlyR = m_delayLines[14].Get() + earlyR * 0.618034f;
  182. m_delayLines[14].Set(earlyR2 - earlyR * 0.618034f);
  183. }
  184. const float earlyRefOutR = earlyR * m_ERLevel;
  185. m_filterHist[11] = (m_filterHist[11] - m_delayLines[11].Get()) * m_delayCoeffs[11][1] + m_delayLines[11].Get();
  186. reverbR1 = m_filterHist[11] * m_delayCoeffs[11][0] + reverbR2 * m_diffusion;
  187. m_delayLines[11].Set(reverbR2 - reverbR1 * m_diffusion);
  188. reverbR2 = reverbR1;
  189. m_filterHist[10] = (m_filterHist[10] - m_delayLines[10].Get()) * m_delayCoeffs[10][1] + m_delayLines[10].Get();
  190. reverbR1 = m_filterHist[10] * m_delayCoeffs[10][0] + reverbR2 * m_diffusion;
  191. m_delayLines[10].Set(reverbR2 - reverbR1 * m_diffusion);
  192. reverbR3 = reverbL4 - reverbR2 * 0.15f - reverbR1 * 0.2f;
  193. reverbR2 = reverbR1;
  194. if(m_quality & kMoreDelayLines)
  195. {
  196. m_filterHist[9] = (m_filterHist[9] - m_delayLines[9].Get()) * m_delayCoeffs[9][1] + m_delayLines[9].Get();
  197. reverbR1 = m_filterHist[9] * m_delayCoeffs[9][0] + reverbR2 * m_diffusion;
  198. m_delayLines[9].Set(reverbR2 - reverbR1 * m_diffusion);
  199. reverbR2 = reverbR1;
  200. reverbR3 += reverbR1 * 0.35f;
  201. m_filterHist[8] = (m_filterHist[8] - m_delayLines[8].Get()) * m_delayCoeffs[8][1] + m_delayLines[8].Get();
  202. reverbR1 = m_filterHist[8] * m_delayCoeffs[8][0] + reverbR2 * m_diffusion;
  203. m_delayLines[8].Set(reverbR2 - reverbR1 * m_diffusion);
  204. reverbR2 = reverbR1;
  205. reverbR3 -= reverbR1 * 0.38f;
  206. }
  207. m_delayLines[18].Set(reverbR2);
  208. reverbR1 = m_delayLines[18].Get() * m_delayCoeffs[12][0];
  209. m_filterHist[18] = (m_filterHist[18] - reverbR1) * m_delayCoeffs[12][1] + reverbR1;
  210. m_filterHist[7] = (m_filterHist[7] - m_delayLines[7].Get()) * m_delayCoeffs[7][1] + m_delayLines[7].Get();
  211. reverbR1 = m_filterHist[18] * m_diffusion + m_filterHist[7] * m_delayCoeffs[7][0];
  212. m_delayLines[7].Set(m_filterHist[18] - reverbR1 * m_diffusion);
  213. reverbR2 = reverbR1;
  214. float lateRevOutL = (reverbL3 + reverbR1 * 0.38f) * m_ReverbLevelL;
  215. m_filterHist[6] = (m_filterHist[6] - m_delayLines[6].Get()) * m_delayCoeffs[6][1] + m_delayLines[6].Get();
  216. reverbR1 = m_filterHist[6] * m_delayCoeffs[6][0] + reverbR2 * m_diffusion;
  217. m_delayLines[6].Set(reverbR2 - reverbR1 * m_diffusion);
  218. m_filterHist[16] = reverbR1;
  219. float lateRevOutR = (reverbR3 - reverbR1 * 0.38f) * m_ReverbLevelR;
  220. float outL = earlyRefOutL + lateRevOutL;
  221. float outR = earlyRefOutR + lateRevOutR;
  222. for(auto &line : m_delayLines)
  223. line.Advance();
  224. if(!(m_quality & kFullSampleRate))
  225. {
  226. *(out[0]++) = (outL + m_prevL) * 0.5f;
  227. *(out[1]++) = (outR + m_prevR) * 0.5f;
  228. m_prevL = outL;
  229. m_prevR = outR;
  230. in[0]++;
  231. in[1]++;
  232. if(frames-- == 1)
  233. {
  234. m_remain = true;
  235. break;
  236. }
  237. }
  238. *(out[0]++) = outL;
  239. *(out[1]++) = outR;
  240. frames--;
  241. }
  242. ProcessMixOps(pOutL, pOutR, m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1), numFrames);
  243. }
  244. int32 I3DL2Reverb::GetNumPrograms() const
  245. {
  246. #ifdef MODPLUG_TRACKER
  247. return NUM_REVERBTYPES;
  248. #else
  249. return 0;
  250. #endif
  251. }
  252. void I3DL2Reverb::SetCurrentProgram(int32 program)
  253. {
  254. #ifdef MODPLUG_TRACKER
  255. if(program < static_cast<int32>(NUM_REVERBTYPES))
  256. {
  257. m_program = program;
  258. const auto &preset = *GetReverbPreset(m_program);
  259. m_param[kI3DL2ReverbRoom] = (preset.lRoom + 10000) / 10000.0f;
  260. m_param[kI3DL2ReverbRoomHF] = (preset.lRoomHF + 10000) / 10000.0f;
  261. m_param[kI3DL2ReverbRoomRolloffFactor] = 0.0f;
  262. m_param[kI3DL2ReverbDecayTime] = (preset.flDecayTime - 0.1f) / 19.9f;
  263. m_param[kI3DL2ReverbDecayHFRatio] = (preset.flDecayHFRatio - 0.1f) / 1.9f;
  264. m_param[kI3DL2ReverbReflections] = (preset.lReflections + 10000) / 11000.0f;
  265. m_param[kI3DL2ReverbReflectionsDelay] = preset.flReflectionsDelay / 0.3f;
  266. m_param[kI3DL2ReverbReverb] = (preset.lReverb + 10000) / 12000.0f;
  267. m_param[kI3DL2ReverbReverbDelay] = preset.flReverbDelay / 0.1f;
  268. m_param[kI3DL2ReverbDiffusion] = preset.flDiffusion / 100.0f;
  269. m_param[kI3DL2ReverbDensity] = preset.flDensity / 100.0f;
  270. m_param[kI3DL2ReverbHFReference] = (5000.0f - 20.0f) / 19980.0f;
  271. RecalculateI3DL2ReverbParams();
  272. }
  273. #else
  274. MPT_UNUSED_VARIABLE(program);
  275. #endif
  276. }
  277. PlugParamValue I3DL2Reverb::GetParameter(PlugParamIndex index)
  278. {
  279. if(index < kI3DL2ReverbNumParameters)
  280. {
  281. return m_param[index];
  282. }
  283. return 0;
  284. }
  285. void I3DL2Reverb::SetParameter(PlugParamIndex index, PlugParamValue value)
  286. {
  287. if(index < kI3DL2ReverbNumParameters)
  288. {
  289. value = mpt::safe_clamp(value, 0.0f, 1.0f);
  290. if(index == kI3DL2ReverbQuality)
  291. value = mpt::round(value * 3.0f) / 3.0f;
  292. m_param[index] = value;
  293. m_recalcParams = true;
  294. }
  295. }
  296. void I3DL2Reverb::Resume()
  297. {
  298. RecalculateI3DL2ReverbParams();
  299. PositionChanged();
  300. m_isResumed = true;
  301. }
  302. void I3DL2Reverb::PositionChanged()
  303. {
  304. MemsetZero(m_filterHist);
  305. m_prevL = 0;
  306. m_prevR = 0;
  307. m_remain = false;
  308. try
  309. {
  310. uint32 sampleRate = static_cast<uint32>(m_effectiveSampleRate);
  311. m_delayLines[0].Init(67, 5, sampleRate, m_delayTaps[0]);
  312. m_delayLines[1].Init(62, 5, sampleRate, m_delayTaps[1]);
  313. m_delayLines[2].Init(53, 5, sampleRate, m_delayTaps[2]);
  314. m_delayLines[3].Init(43, 5, sampleRate, m_delayTaps[3]);
  315. m_delayLines[4].Init(32, 5, sampleRate, m_delayTaps[4]);
  316. m_delayLines[5].Init(22, 5, sampleRate, m_delayTaps[5]);
  317. m_delayLines[6].Init(75, 5, sampleRate, m_delayTaps[6]);
  318. m_delayLines[7].Init(69, 5, sampleRate, m_delayTaps[7]);
  319. m_delayLines[8].Init(60, 5, sampleRate, m_delayTaps[8]);
  320. m_delayLines[9].Init(48, 5, sampleRate, m_delayTaps[9]);
  321. m_delayLines[10].Init(36, 5, sampleRate, m_delayTaps[10]);
  322. m_delayLines[11].Init(25, 5, sampleRate, m_delayTaps[11]);
  323. m_delayLines[12].Init(0, 0, 0); // Dummy for array index consistency with both tap and coefficient arrays
  324. m_delayLines[13].Init(3, 0, sampleRate, m_delayTaps[13]);
  325. m_delayLines[14].Init(3, 0, sampleRate, m_delayTaps[14]);
  326. m_delayLines[15].Init(407, 1, sampleRate);
  327. m_delayLines[16].Init(400, 1, sampleRate);
  328. m_delayLines[17].Init(10, 0, sampleRate, -1);
  329. m_delayLines[18].Init(10, 0, sampleRate, -1);
  330. m_ok = true;
  331. } catch(mpt::out_of_memory e)
  332. {
  333. m_ok = false;
  334. mpt::delete_out_of_memory(e);
  335. }
  336. }
  337. #ifdef MODPLUG_TRACKER
  338. CString I3DL2Reverb::GetParamName(PlugParamIndex param)
  339. {
  340. switch(param)
  341. {
  342. case kI3DL2ReverbRoom: return _T("Room");
  343. case kI3DL2ReverbRoomHF: return _T("RoomHF");
  344. case kI3DL2ReverbRoomRolloffFactor: return _T("RoomRolloffFactor");
  345. case kI3DL2ReverbDecayTime: return _T("DecayTime");
  346. case kI3DL2ReverbDecayHFRatio: return _T("DecayHFRatio");
  347. case kI3DL2ReverbReflections: return _T("Reflections");
  348. case kI3DL2ReverbReflectionsDelay: return _T("ReflectionsDelay");
  349. case kI3DL2ReverbReverb: return _T("Reverb");
  350. case kI3DL2ReverbReverbDelay: return _T("ReverbDelay");
  351. case kI3DL2ReverbDiffusion: return _T("Diffusion");
  352. case kI3DL2ReverbDensity: return _T("Density");
  353. case kI3DL2ReverbHFReference: return _T("HFRefrence");
  354. case kI3DL2ReverbQuality: return _T("Quality");
  355. }
  356. return CString();
  357. }
  358. CString I3DL2Reverb::GetParamLabel(PlugParamIndex param)
  359. {
  360. switch(param)
  361. {
  362. case kI3DL2ReverbRoom:
  363. case kI3DL2ReverbRoomHF:
  364. case kI3DL2ReverbReflections:
  365. case kI3DL2ReverbReverb:
  366. return _T("dB");
  367. case kI3DL2ReverbDecayTime:
  368. case kI3DL2ReverbReflectionsDelay:
  369. case kI3DL2ReverbReverbDelay:
  370. return _T("s");
  371. case kI3DL2ReverbDiffusion:
  372. case kI3DL2ReverbDensity:
  373. return _T("%");
  374. case kI3DL2ReverbHFReference:
  375. return _T("Hz");
  376. }
  377. return CString();
  378. }
  379. CString I3DL2Reverb::GetParamDisplay(PlugParamIndex param)
  380. {
  381. static constexpr const TCHAR * const modes[] = { _T("LQ"), _T("LQ+"), _T("HQ"), _T("HQ+") };
  382. float value = m_param[param];
  383. switch(param)
  384. {
  385. case kI3DL2ReverbRoom: value = Room() * 0.01f; break;
  386. case kI3DL2ReverbRoomHF: value = RoomHF() * 0.01f; break;
  387. case kI3DL2ReverbRoomRolloffFactor: value = RoomRolloffFactor(); break;
  388. case kI3DL2ReverbDecayTime: value = DecayTime(); break;
  389. case kI3DL2ReverbDecayHFRatio: value = DecayHFRatio(); break;
  390. case kI3DL2ReverbReflections: value = Reflections() * 0.01f; break;
  391. case kI3DL2ReverbReflectionsDelay: value = ReflectionsDelay(); break;
  392. case kI3DL2ReverbReverb: value = Reverb() * 0.01f; break;
  393. case kI3DL2ReverbReverbDelay: value = ReverbDelay(); break;
  394. case kI3DL2ReverbDiffusion: value = Diffusion(); break;
  395. case kI3DL2ReverbDensity: value = Density(); break;
  396. case kI3DL2ReverbHFReference: value = HFReference(); break;
  397. case kI3DL2ReverbQuality: return modes[Quality() % 4u];
  398. }
  399. CString s;
  400. s.Format(_T("%.2f"), value);
  401. return s;
  402. }
  403. CString I3DL2Reverb::GetCurrentProgramName()
  404. {
  405. return GetProgramName(m_program);
  406. }
  407. CString I3DL2Reverb::GetProgramName(int32 program)
  408. {
  409. return mpt::ToCString(GetReverbPresetName(program));
  410. }
  411. #endif // MODPLUG_TRACKER
  412. void I3DL2Reverb::RecalculateI3DL2ReverbParams()
  413. {
  414. m_quality = Quality();
  415. m_effectiveSampleRate = static_cast<float>(m_SndFile.GetSampleRate() / ((m_quality & kFullSampleRate) ? 1u : 2u));
  416. // Diffusion
  417. m_diffusion = Diffusion() * (0.618034f / 100.0f);
  418. // Early Reflection Level
  419. m_ERLevel = std::min(std::pow(10.0f, (Room() + Reflections()) / (100.0f * 20.0f)), 1.0f) * 0.761f;
  420. // Room Filter
  421. float roomHF = std::pow(10.0f, RoomHF() / 100.0f / 10.0f);
  422. if(roomHF == 1.0f)
  423. {
  424. m_roomFilter = 0.0f;
  425. } else
  426. {
  427. float freq = std::cos(HFReference() * (2.0f * mpt::numbers::pi_v<float>) / m_effectiveSampleRate);
  428. float roomFilter = (freq * (roomHF + roomHF) - 2.0f + std::sqrt(freq * (roomHF * roomHF * freq * 4.0f) + roomHF * 8.0f - roomHF * roomHF * 4.0f - roomHF * freq * 8.0f)) / (roomHF + roomHF - 2.0f);
  429. m_roomFilter = Clamp(roomFilter, 0.0f, 1.0f);
  430. }
  431. SetDelayTaps();
  432. SetDecayCoeffs();
  433. m_recalcParams = false;
  434. }
  435. void I3DL2Reverb::SetDelayTaps()
  436. {
  437. // Early reflections
  438. static constexpr float delays[] =
  439. {
  440. 1.0000f, 1.0000f, 0.0000f, 0.1078f, 0.1768f, 0.2727f,
  441. 0.3953f, 0.5386f, 0.6899f, 0.8306f, 0.9400f, 0.9800f,
  442. };
  443. const float sampleRate = m_effectiveSampleRate;
  444. const float reflectionsDelay = ReflectionsDelay();
  445. const float reverbDelay = std::max(ReverbDelay(), 5.0f / 1000.0f);
  446. m_earlyTaps[0][0] = static_cast<int32>((reverbDelay + reflectionsDelay + 7.0f / 1000.0f) * sampleRate);
  447. for(uint32 i = 1; i < 12; i++)
  448. {
  449. m_earlyTaps[i % 2u][i / 2u] = static_cast<int32>((reverbDelay * delays[i] + reflectionsDelay) * sampleRate);
  450. }
  451. // Late reflections
  452. float density = std::min((Density() / 100.0f + 0.1f) * 0.9091f, 1.0f);
  453. float delayL = density * 67.0f / 1000.0f * sampleRate;
  454. float delayR = density * 75.0f / 1000.0f * sampleRate;
  455. for(int i = 0, power = 0; i < 6; i++)
  456. {
  457. power += i;
  458. float factor = std::pow(0.93f, static_cast<float>(power));
  459. m_delayTaps[i + 0] = static_cast<int32>(delayL * factor);
  460. m_delayTaps[i + 6] = static_cast<int32>(delayR * factor);
  461. }
  462. m_delayTaps[12] = static_cast<int32>(10.0f / 1000.0f * sampleRate);
  463. // Early reflections (extra delay lines)
  464. m_delayTaps[13] = static_cast<int32>(3.25f / 1000.0f * sampleRate);
  465. m_delayTaps[14] = static_cast<int32>(3.53f / 1000.0f * sampleRate);
  466. for(std::size_t d = 0; d < std::size(m_delayTaps); d++)
  467. m_delayLines[d].SetDelayTap(m_delayTaps[d]);
  468. }
  469. void I3DL2Reverb::SetDecayCoeffs()
  470. {
  471. float levelLtmp = 1.0f, levelRtmp = 1.0f;
  472. float levelL = 0.0f, levelR = 0.0f;
  473. levelLtmp *= CalcDecayCoeffs(5);
  474. levelRtmp *= CalcDecayCoeffs(11);
  475. levelL += levelLtmp * 0.0225f;
  476. levelR += levelRtmp * 0.0225f;
  477. levelLtmp *= CalcDecayCoeffs(4);
  478. levelRtmp *= CalcDecayCoeffs(10);
  479. levelL += levelLtmp * 0.04f;
  480. levelR += levelRtmp * 0.04f;
  481. if(m_quality & kMoreDelayLines)
  482. {
  483. levelLtmp *= CalcDecayCoeffs(3);
  484. levelRtmp *= CalcDecayCoeffs(9);
  485. levelL += levelLtmp * 0.1225f;
  486. levelR += levelRtmp * 0.1225f;
  487. levelLtmp *= CalcDecayCoeffs(2);
  488. levelRtmp *= CalcDecayCoeffs(8);
  489. levelL += levelLtmp * 0.1444f;
  490. levelR += levelRtmp * 0.1444f;
  491. }
  492. CalcDecayCoeffs(12);
  493. levelLtmp *= m_delayCoeffs[12][0] * m_delayCoeffs[12][0];
  494. levelRtmp *= m_delayCoeffs[12][0] * m_delayCoeffs[12][0];
  495. levelLtmp *= CalcDecayCoeffs(1);
  496. levelRtmp *= CalcDecayCoeffs(7);
  497. levelL += levelRtmp * 0.1444f;
  498. levelR += levelLtmp * 0.1444f;
  499. levelLtmp *= CalcDecayCoeffs(0);
  500. levelRtmp *= CalcDecayCoeffs(6);
  501. levelL += levelLtmp * 0.1444f;
  502. levelR += levelRtmp * 0.1444f;
  503. // Final Reverb Level
  504. float level = std::min(std::pow(10.0f, (Room() + Reverb()) / (100.0f * 20.0f)), 1.0f);
  505. float monoInv = 1.0f - ((levelLtmp + levelRtmp) * 0.5f);
  506. m_ReverbLevelL = level * std::sqrt(monoInv / levelL);
  507. m_ReverbLevelR = level * std::sqrt(monoInv / levelR);
  508. }
  509. float I3DL2Reverb::CalcDecayCoeffs(int32 index)
  510. {
  511. float hfRef = (2.0f * mpt::numbers::pi_v<float>) / m_effectiveSampleRate * HFReference();
  512. float decayHFRatio = DecayHFRatio();
  513. if(decayHFRatio > 1.0f)
  514. hfRef = mpt::numbers::pi_v<float>;
  515. float c1 = std::pow(10.0f, ((m_delayTaps[index] / m_effectiveSampleRate) * -60.0f / DecayTime()) / 20.0f);
  516. float c2 = 0.0f;
  517. float c21 = (std::pow(c1, 2.0f - 2.0f / decayHFRatio) - 1.0f) / (1.0f - std::cos(hfRef));
  518. if(c21 != 0 && std::isfinite(c21))
  519. {
  520. float c22 = -2.0f * c21 - 2.0f;
  521. float c23sq = c22 * c22 - c21 * c21 * 4.0f;
  522. float c23 = c23sq > 0.0f ? std::sqrt(c23sq) : 0.0f;
  523. c2 = (c23 - c22) / (c21 + c21);
  524. if(std::abs(c2) > 1.0f)
  525. c2 = (-c22 - c23) / (c21 + c21);
  526. c2 = mpt::sanitize_nan(c2);
  527. }
  528. m_delayCoeffs[index][0] = c1;
  529. m_delayCoeffs[index][1] = c2;
  530. c1 *= c1;
  531. float diff2 = m_diffusion * m_diffusion;
  532. return diff2 + c1 / (1.0f - diff2 * c1) * (1.0f - diff2) * (1.0f - diff2);
  533. }
  534. } // namespace DMO
  535. #else
  536. MPT_MSVC_WORKAROUND_LNK4221(I3DL2Reverb)
  537. #endif // !NO_PLUGINS
  538. OPENMPT_NAMESPACE_END