Compressor.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /*
  2. * Compressor.cpp
  3. * ---------------
  4. * Purpose: Implementation of the DMO Compressor DSP (for non-Windows platforms)
  5. * Notes : The original plugin's integer and floating point code paths only
  6. * behave identically when feeding floating point numbers in range
  7. * [-32768, +32768] rather than the usual [-1, +1] into the plugin.
  8. * Authors: OpenMPT Devs
  9. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  10. */
  11. #include "stdafx.h"
  12. #ifndef NO_PLUGINS
  13. #include "../../Sndfile.h"
  14. #include "Compressor.h"
  15. #include "DMOUtils.h"
  16. #include "mpt/base/numbers.hpp"
  17. #endif // !NO_PLUGINS
  18. OPENMPT_NAMESPACE_BEGIN
  19. #ifndef NO_PLUGINS
  20. namespace DMO
  21. {
  22. IMixPlugin* Compressor::Create(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
  23. {
  24. return new (std::nothrow) Compressor(factory, sndFile, mixStruct);
  25. }
  26. Compressor::Compressor(VSTPluginLib &factory, CSoundFile &sndFile, SNDMIXPLUGIN *mixStruct)
  27. : IMixPlugin(factory, sndFile, mixStruct)
  28. {
  29. m_param[kCompGain] = 0.5f;
  30. m_param[kCompAttack] = 0.02f;
  31. m_param[kCompRelease] = 150.0f / 2950.0f;
  32. m_param[kCompThreshold] = 2.0f / 3.0f;
  33. m_param[kCompRatio] = 0.02f;
  34. m_param[kCompPredelay] = 1.0f;
  35. m_mixBuffer.Initialize(2, 2);
  36. InsertIntoFactoryList();
  37. }
  38. void Compressor::Process(float *pOutL, float *pOutR, uint32 numFrames)
  39. {
  40. if(!m_bufSize || !m_mixBuffer.Ok())
  41. return;
  42. const float *in[2] = { m_mixBuffer.GetInputBuffer(0), m_mixBuffer.GetInputBuffer(1) };
  43. float *out[2] = { m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1) };
  44. for(uint32 i = numFrames; i != 0; i--)
  45. {
  46. float leftIn = *(in[0])++;
  47. float rightIn = *(in[1])++;
  48. m_buffer[m_bufPos * 2] = leftIn;
  49. m_buffer[m_bufPos * 2 + 1] = rightIn;
  50. leftIn = std::abs(leftIn);
  51. rightIn = std::abs(rightIn);
  52. float mono = (leftIn + rightIn) * (0.5f * 32768.0f * 32768.0f);
  53. float monoLog = std::abs(logGain(mono, 31, 5)) * (1.0f / float(1u << 31));
  54. float newPeak = monoLog + (m_peak - monoLog) * ((m_peak <= monoLog) ? m_attack : m_release);
  55. m_peak = newPeak;
  56. if(newPeak < m_threshold)
  57. newPeak = m_threshold;
  58. float compGain = (m_threshold - newPeak) * m_ratio + 0.9999999f;
  59. // Computes 2 ^ (2 ^ (log2(x) - 26) - 1) (x = 0...2^31)
  60. uint32 compGainInt = static_cast<uint32>(compGain * 2147483648.0f);
  61. uint32 compGainPow = compGainInt << 5;
  62. compGainInt >>= 26;
  63. if(compGainInt) // compGainInt >= 2^26
  64. {
  65. compGainPow |= 0x80000000u;
  66. compGainInt--;
  67. }
  68. compGainPow >>= (31 - compGainInt);
  69. int32 readOffset = m_predelay + m_bufPos * 4096 + m_bufSize - 1;
  70. readOffset /= 4096;
  71. readOffset %= m_bufSize;
  72. float outGain = (compGainPow * (1.0f / 2147483648.0f)) * m_gain;
  73. *(out[0])++ = m_buffer[readOffset * 2] * outGain;
  74. *(out[1])++ = m_buffer[readOffset * 2 + 1] * outGain;
  75. if(m_bufPos-- == 0)
  76. m_bufPos += m_bufSize;
  77. }
  78. ProcessMixOps(pOutL, pOutR, m_mixBuffer.GetOutputBuffer(0), m_mixBuffer.GetOutputBuffer(1), numFrames);
  79. }
  80. PlugParamValue Compressor::GetParameter(PlugParamIndex index)
  81. {
  82. if(index < kCompNumParameters)
  83. {
  84. return m_param[index];
  85. }
  86. return 0;
  87. }
  88. void Compressor::SetParameter(PlugParamIndex index, PlugParamValue value)
  89. {
  90. if(index < kCompNumParameters)
  91. {
  92. value = mpt::safe_clamp(value, 0.0f, 1.0f);
  93. m_param[index] = value;
  94. RecalculateCompressorParams();
  95. }
  96. }
  97. void Compressor::Resume()
  98. {
  99. m_isResumed = true;
  100. PositionChanged();
  101. RecalculateCompressorParams();
  102. }
  103. void Compressor::PositionChanged()
  104. {
  105. m_bufSize = Util::muldiv(m_SndFile.GetSampleRate(), 200, 1000);
  106. try
  107. {
  108. m_buffer.assign(m_bufSize * 2, 0.0f);
  109. } catch(mpt::out_of_memory e)
  110. {
  111. mpt::delete_out_of_memory(e);
  112. m_bufSize = 0;
  113. }
  114. m_bufPos = 0;
  115. m_peak = 0.0f;
  116. }
  117. #ifdef MODPLUG_TRACKER
  118. CString Compressor::GetParamName(PlugParamIndex param)
  119. {
  120. switch(param)
  121. {
  122. case kCompGain: return _T("Gain");
  123. case kCompAttack: return _T("Attack");
  124. case kCompRelease: return _T("Release");
  125. case kCompThreshold: return _T("Threshold");
  126. case kCompRatio: return _T("Ratio");
  127. case kCompPredelay: return _T("Predelay");
  128. }
  129. return CString();
  130. }
  131. CString Compressor::GetParamLabel(PlugParamIndex param)
  132. {
  133. switch(param)
  134. {
  135. case kCompGain:
  136. case kCompThreshold:
  137. return _T("dB");
  138. case kCompAttack:
  139. case kCompRelease:
  140. case kCompPredelay:
  141. return _T("ms");
  142. }
  143. return CString();
  144. }
  145. CString Compressor::GetParamDisplay(PlugParamIndex param)
  146. {
  147. float value = m_param[param];
  148. switch(param)
  149. {
  150. case kCompGain:
  151. value = GainInDecibel();
  152. break;
  153. case kCompAttack:
  154. value = AttackTime();
  155. break;
  156. case kCompRelease:
  157. value = ReleaseTime();
  158. break;
  159. case kCompThreshold:
  160. value = ThresholdInDecibel();
  161. break;
  162. case kCompRatio:
  163. value = CompressorRatio();
  164. break;
  165. case kCompPredelay:
  166. value = PreDelay();
  167. break;
  168. }
  169. CString s;
  170. s.Format(_T("%.2f"), value);
  171. return s;
  172. }
  173. #endif // MODPLUG_TRACKER
  174. void Compressor::RecalculateCompressorParams()
  175. {
  176. const float sampleRate = m_SndFile.GetSampleRate() / 1000.0f;
  177. m_gain = std::pow(10.0f, GainInDecibel() / 20.0f);
  178. m_attack = std::pow(10.0f, -1.0f / (AttackTime() * sampleRate));
  179. m_release = std::pow(10.0f, -1.0f / (ReleaseTime() * sampleRate));
  180. const float _2e31 = float(1u << 31);
  181. const float _2e26 = float(1u << 26);
  182. m_threshold = std::min((_2e31 - 1.0f), (std::log(std::pow(10.0f, ThresholdInDecibel() / 20.0f) * _2e31) * _2e26) / mpt::numbers::ln2_v<float> + _2e26) * (1.0f / _2e31);
  183. m_ratio = 1.0f - (1.0f / CompressorRatio());
  184. m_predelay = static_cast<int32>((PreDelay() * sampleRate) + 2.0f);
  185. }
  186. } // namespace DMO
  187. #else
  188. MPT_MSVC_WORKAROUND_LNK4221(Compressor)
  189. #endif // !NO_PLUGINS
  190. OPENMPT_NAMESPACE_END