compressor.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /**
  2. * OpenAL cross platform audio library
  3. * Copyright (C) 2013 by Anis A. Hireche
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Library General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Library General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Library General Public
  15. * License along with this library; if not, write to the
  16. * Free Software Foundation, Inc.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18. * Or go to http://www.gnu.org/copyleft/lgpl.html
  19. */
  20. #include "config.h"
  21. #include <cstdlib>
  22. #include "alcmain.h"
  23. #include "alcontext.h"
  24. #include "alu.h"
  25. #include "effectslot.h"
  26. #include "vecmat.h"
  27. namespace {
  28. #define AMP_ENVELOPE_MIN 0.5f
  29. #define AMP_ENVELOPE_MAX 2.0f
  30. #define ATTACK_TIME 0.1f /* 100ms to rise from min to max */
  31. #define RELEASE_TIME 0.2f /* 200ms to drop from max to min */
  32. struct CompressorState final : public EffectState {
  33. /* Effect gains for each channel */
  34. float mGain[MaxAmbiChannels][MAX_OUTPUT_CHANNELS]{};
  35. /* Effect parameters */
  36. bool mEnabled{true};
  37. float mAttackMult{1.0f};
  38. float mReleaseMult{1.0f};
  39. float mEnvFollower{1.0f};
  40. void deviceUpdate(const ALCdevice *device, const Buffer &buffer) override;
  41. void update(const ALCcontext *context, const EffectSlot *slot, const EffectProps *props,
  42. const EffectTarget target) override;
  43. void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
  44. const al::span<FloatBufferLine> samplesOut) override;
  45. DEF_NEWDEL(CompressorState)
  46. };
  47. void CompressorState::deviceUpdate(const ALCdevice *device, const Buffer&)
  48. {
  49. /* Number of samples to do a full attack and release (non-integer sample
  50. * counts are okay).
  51. */
  52. const float attackCount{static_cast<float>(device->Frequency) * ATTACK_TIME};
  53. const float releaseCount{static_cast<float>(device->Frequency) * RELEASE_TIME};
  54. /* Calculate per-sample multipliers to attack and release at the desired
  55. * rates.
  56. */
  57. mAttackMult = std::pow(AMP_ENVELOPE_MAX/AMP_ENVELOPE_MIN, 1.0f/attackCount);
  58. mReleaseMult = std::pow(AMP_ENVELOPE_MIN/AMP_ENVELOPE_MAX, 1.0f/releaseCount);
  59. }
  60. void CompressorState::update(const ALCcontext*, const EffectSlot *slot,
  61. const EffectProps *props, const EffectTarget target)
  62. {
  63. mEnabled = props->Compressor.OnOff;
  64. mOutTarget = target.Main->Buffer;
  65. auto set_gains = [slot,target](auto &gains, al::span<const float,MaxAmbiChannels> coeffs)
  66. { ComputePanGains(target.Main, coeffs.data(), slot->Gain, gains); };
  67. SetAmbiPanIdentity(std::begin(mGain), slot->Wet.Buffer.size(), set_gains);
  68. }
  69. void CompressorState::process(const size_t samplesToDo,
  70. const al::span<const FloatBufferLine> samplesIn, const al::span<FloatBufferLine> samplesOut)
  71. {
  72. for(size_t base{0u};base < samplesToDo;)
  73. {
  74. float gains[256];
  75. const size_t td{minz(256, samplesToDo-base)};
  76. /* Generate the per-sample gains from the signal envelope. */
  77. float env{mEnvFollower};
  78. if(mEnabled)
  79. {
  80. for(size_t i{0u};i < td;++i)
  81. {
  82. /* Clamp the absolute amplitude to the defined envelope limits,
  83. * then attack or release the envelope to reach it.
  84. */
  85. const float amplitude{clampf(std::fabs(samplesIn[0][base+i]), AMP_ENVELOPE_MIN,
  86. AMP_ENVELOPE_MAX)};
  87. if(amplitude > env)
  88. env = minf(env*mAttackMult, amplitude);
  89. else if(amplitude < env)
  90. env = maxf(env*mReleaseMult, amplitude);
  91. /* Apply the reciprocal of the envelope to normalize the volume
  92. * (compress the dynamic range).
  93. */
  94. gains[i] = 1.0f / env;
  95. }
  96. }
  97. else
  98. {
  99. /* Same as above, except the amplitude is forced to 1. This helps
  100. * ensure smooth gain changes when the compressor is turned on and
  101. * off.
  102. */
  103. for(size_t i{0u};i < td;++i)
  104. {
  105. const float amplitude{1.0f};
  106. if(amplitude > env)
  107. env = minf(env*mAttackMult, amplitude);
  108. else if(amplitude < env)
  109. env = maxf(env*mReleaseMult, amplitude);
  110. gains[i] = 1.0f / env;
  111. }
  112. }
  113. mEnvFollower = env;
  114. /* Now compress the signal amplitude to output. */
  115. auto changains = std::addressof(mGain[0]);
  116. for(const auto &input : samplesIn)
  117. {
  118. const float *outgains{*(changains++)};
  119. for(FloatBufferLine &output : samplesOut)
  120. {
  121. const float gain{*(outgains++)};
  122. if(!(std::fabs(gain) > GainSilenceThreshold))
  123. continue;
  124. for(size_t i{0u};i < td;i++)
  125. output[base+i] += input[base+i] * gains[i] * gain;
  126. }
  127. }
  128. base += td;
  129. }
  130. }
  131. struct CompressorStateFactory final : public EffectStateFactory {
  132. al::intrusive_ptr<EffectState> create() override
  133. { return al::intrusive_ptr<EffectState>{new CompressorState{}}; }
  134. };
  135. } // namespace
  136. EffectStateFactory *CompressorStateFactory_getFactory()
  137. {
  138. static CompressorStateFactory CompressorFactory{};
  139. return &CompressorFactory;
  140. }