EQ.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*
  2. * EQ.cpp
  3. * ------
  4. * Purpose: Mixing code for equalizer.
  5. * Notes : Ugh... This should really be removed at some point.
  6. * Authors: Olivier Lapicque
  7. * OpenMPT Devs
  8. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  9. */
  10. #include "stdafx.h"
  11. #include "EQ.h"
  12. #include "mpt/audio/span.hpp"
  13. #include "mpt/base/numbers.hpp"
  14. #include "openmpt/base/Types.hpp"
  15. #include "openmpt/soundbase/MixSample.hpp"
  16. #include "openmpt/soundbase/MixSampleConvert.hpp"
  17. #ifndef NO_EQ
  18. #include "../misc/mptCPU.h"
  19. #endif
  20. #include <algorithm>
  21. #include <array>
  22. #include <cstddef>
  23. #if defined(MPT_ENABLE_ARCH_INTRINSICS_SSE)
  24. #include <xmmintrin.h>
  25. #endif
  26. OPENMPT_NAMESPACE_BEGIN
  27. #ifndef NO_EQ
  28. static constexpr float EQ_BANDWIDTH = 2.0f;
  29. static constexpr std::array<uint32, 33> gEqLinearToDB =
  30. {
  31. 16, 19, 22, 25, 28, 31, 34, 37,
  32. 40, 43, 46, 49, 52, 55, 58, 61,
  33. 64, 76, 88, 100, 112, 124, 136, 148,
  34. 160, 172, 184, 196, 208, 220, 232, 244, 256
  35. };
  36. static constexpr std::array<EQBANDSETTINGS, MAX_EQ_BANDS> gEQDefaults =
  37. {{
  38. // Default: Flat EQ
  39. {0,0,0,0,0, 1, 120},
  40. {0,0,0,0,0, 1, 600},
  41. {0,0,0,0,0, 1, 1200},
  42. {0,0,0,0,0, 1, 3000},
  43. {0,0,0,0,0, 1, 6000},
  44. {0,0,0,0,0, 1, 10000}
  45. }};
  46. template <std::size_t channels, typename Tbuf>
  47. static void EQFilter(Tbuf & buf, const std::array<EQBANDSETTINGS, MAX_EQ_BANDS> &bands, std::array<std::array<EQBANDSTATE, MAX_EQ_BANDS>, MAX_EQ_CHANNELS> &states)
  48. {
  49. for(std::size_t frame = 0; frame < buf.size_frames(); ++frame)
  50. {
  51. for(std::size_t channel = 0; channel < channels; ++channel)
  52. {
  53. float sample = mix_sample_cast<float>(buf(channel, frame));
  54. for(std::size_t b = 0; b < std::size(bands); ++b)
  55. {
  56. const EQBANDSETTINGS &band = bands[b];
  57. if(band.Gain != 1.0f)
  58. {
  59. EQBANDSTATE &bandState = states[channel][b];
  60. float x = sample;
  61. float y = band.a1 * bandState.x1 + band.a2 * bandState.x2 + band.a0 * x + band.b1 * bandState.y1 + band.b2 * bandState.y2;
  62. bandState.x2 = bandState.x1;
  63. bandState.y2 = bandState.y1;
  64. bandState.x1 = x;
  65. bandState.y1 = y;
  66. sample = y;
  67. }
  68. }
  69. buf(channel, frame) = mix_sample_cast<typename Tbuf::sample_type>(sample);
  70. }
  71. }
  72. }
  73. template <typename TMixSample>
  74. void CEQ::ProcessTemplate(TMixSample *frontBuffer, TMixSample *rearBuffer, std::size_t countFrames, std::size_t numChannels)
  75. {
  76. #if defined(MPT_ENABLE_ARCH_INTRINSICS_SSE)
  77. unsigned int old_csr = 0;
  78. if(CPU::HasFeatureSet(CPU::feature::sse))
  79. {
  80. old_csr = _mm_getcsr();
  81. _mm_setcsr((old_csr & ~(_MM_DENORMALS_ZERO_MASK | _MM_FLUSH_ZERO_MASK)) | _MM_DENORMALS_ZERO_ON | _MM_FLUSH_ZERO_ON);
  82. }
  83. #endif
  84. if(numChannels == 1)
  85. {
  86. mpt::audio_span_interleaved<TMixSample> buf{ frontBuffer, 1, countFrames };
  87. EQFilter<1>(buf, m_Bands, m_ChannelState);
  88. } else if(numChannels == 2)
  89. {
  90. mpt::audio_span_interleaved<TMixSample> buf{ frontBuffer, 2, countFrames };
  91. EQFilter<2>(buf, m_Bands, m_ChannelState);
  92. } else if(numChannels == 4)
  93. {
  94. std::array<TMixSample*, 4> buffers = { &frontBuffer[0], &frontBuffer[1], &rearBuffer[0], &rearBuffer[1] };
  95. mpt::audio_span_planar_strided<TMixSample> buf{ buffers.data(), 4, countFrames, 2 };
  96. EQFilter<4>(buf, m_Bands, m_ChannelState);
  97. }
  98. #if defined(MPT_ENABLE_ARCH_INTRINSICS_SSE)
  99. if(CPU::HasFeatureSet(CPU::feature::sse))
  100. {
  101. _mm_setcsr(old_csr);
  102. }
  103. #endif
  104. }
  105. void CEQ::Process(MixSampleInt *frontBuffer, MixSampleInt *rearBuffer, std::size_t countFrames, std::size_t numChannels)
  106. {
  107. ProcessTemplate<MixSampleInt>(frontBuffer, rearBuffer, countFrames, numChannels);
  108. }
  109. void CEQ::Process(MixSampleFloat *frontBuffer, MixSampleFloat *rearBuffer, std::size_t countFrames, std::size_t numChannels)
  110. {
  111. ProcessTemplate<MixSampleFloat>(frontBuffer, rearBuffer, countFrames, numChannels);
  112. }
  113. CEQ::CEQ()
  114. : m_Bands(gEQDefaults)
  115. {
  116. return;
  117. }
  118. void CEQ::Initialize(bool bReset, uint32 MixingFreq)
  119. {
  120. float fMixingFreq = static_cast<float>(MixingFreq);
  121. // Gain = 0.5 (-6dB) .. 2 (+6dB)
  122. for(std::size_t band = 0; band < MAX_EQ_BANDS; ++band)
  123. {
  124. float k, k2, r, f;
  125. float v0, v1;
  126. bool b = bReset;
  127. f = m_Bands[band].CenterFrequency / fMixingFreq;
  128. if(f > 0.45f)
  129. {
  130. m_Bands[band].Gain = 1.0f;
  131. }
  132. k = f * mpt::numbers::pi_v<float>;
  133. k = k + k*f;
  134. k2 = k*k;
  135. v0 = m_Bands[band].Gain;
  136. v1 = 1;
  137. if(m_Bands[band].Gain < 1.0f)
  138. {
  139. v0 *= (0.5f/EQ_BANDWIDTH);
  140. v1 *= (0.5f/EQ_BANDWIDTH);
  141. } else
  142. {
  143. v0 *= (1.0f/EQ_BANDWIDTH);
  144. v1 *= (1.0f/EQ_BANDWIDTH);
  145. }
  146. r = (1 + v0*k + k2) / (1 + v1*k + k2);
  147. if(r != m_Bands[band].a0)
  148. {
  149. m_Bands[band].a0 = r;
  150. b = true;
  151. }
  152. r = 2 * (k2 - 1) / (1 + v1*k + k2);
  153. if(r != m_Bands[band].a1)
  154. {
  155. m_Bands[band].a1 = r;
  156. b = true;
  157. }
  158. r = (1 - v0*k + k2) / (1 + v1*k + k2);
  159. if(r != m_Bands[band].a2)
  160. {
  161. m_Bands[band].a2 = r;
  162. b = true;
  163. }
  164. r = - 2 * (k2 - 1) / (1 + v1*k + k2);
  165. if(r != m_Bands[band].b1)
  166. {
  167. m_Bands[band].b1 = r;
  168. b = true;
  169. }
  170. r = - (1 - v1*k + k2) / (1 + v1*k + k2);
  171. if(r != m_Bands[band].b2)
  172. {
  173. m_Bands[band].b2 = r;
  174. b = true;
  175. }
  176. if(b)
  177. {
  178. for(std::size_t channel = 0; channel < MAX_EQ_CHANNELS; ++channel)
  179. {
  180. m_ChannelState[channel][band] = EQBANDSTATE{};
  181. }
  182. }
  183. }
  184. }
  185. void CEQ::SetEQGains(const uint32 *pGains, const uint32 *pFreqs, bool bReset, uint32 MixingFreq)
  186. {
  187. for(std::size_t i = 0; i < MAX_EQ_BANDS; ++i)
  188. {
  189. m_Bands[i].Gain = static_cast<float>(gEqLinearToDB[std::clamp(pGains[i], static_cast<uint32>(0), static_cast<uint32>(std::size(gEqLinearToDB) - 1))]) / 64.0f;
  190. m_Bands[i].CenterFrequency = static_cast<float>(pFreqs[i]);
  191. }
  192. Initialize(bReset, MixingFreq);
  193. }
  194. #else
  195. MPT_MSVC_WORKAROUND_LNK4221(EQ)
  196. #endif // !NO_EQ
  197. OPENMPT_NAMESPACE_END