🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

192 lines
6.6 KiB

  1. /**
  2. * This file is part of the OpenAL Soft cross platform audio library
  3. *
  4. * Copyright (C) 2013 by Anis A. Hireche
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions are met:
  8. *
  9. * * Redistributions of source code must retain the above copyright notice,
  10. * this list of conditions and the following disclaimer.
  11. *
  12. * * Redistributions in binary form must reproduce the above copyright notice,
  13. * this list of conditions and the following disclaimer in the documentation
  14. * and/or other materials provided with the distribution.
  15. *
  16. * * Neither the name of Spherical-Harmonic-Transform nor the names of its
  17. * contributors may be used to endorse or promote products derived from
  18. * this software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  21. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  22. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  23. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  24. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  25. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  26. * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  27. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  28. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  29. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  30. * POSSIBILITY OF SUCH DAMAGE.
  31. */
  32. #include "config.h"
  33. #include <array>
  34. #include <cstdlib>
  35. #include <iterator>
  36. #include <utility>
  37. #include "alc/effects/base.h"
  38. #include "almalloc.h"
  39. #include "alnumeric.h"
  40. #include "alspan.h"
  41. #include "core/ambidefs.h"
  42. #include "core/bufferline.h"
  43. #include "core/devformat.h"
  44. #include "core/device.h"
  45. #include "core/effectslot.h"
  46. #include "core/mixer.h"
  47. #include "core/mixer/defs.h"
  48. #include "intrusive_ptr.h"
  49. struct ContextBase;
  50. namespace {
  51. #define AMP_ENVELOPE_MIN 0.5f
  52. #define AMP_ENVELOPE_MAX 2.0f
  53. #define ATTACK_TIME 0.1f /* 100ms to rise from min to max */
  54. #define RELEASE_TIME 0.2f /* 200ms to drop from max to min */
  55. struct CompressorState final : public EffectState {
  56. /* Effect gains for each channel */
  57. float mGain[MaxAmbiChannels][MAX_OUTPUT_CHANNELS]{};
  58. /* Effect parameters */
  59. bool mEnabled{true};
  60. float mAttackMult{1.0f};
  61. float mReleaseMult{1.0f};
  62. float mEnvFollower{1.0f};
  63. void deviceUpdate(const DeviceBase *device, const Buffer &buffer) override;
  64. void update(const ContextBase *context, const EffectSlot *slot, const EffectProps *props,
  65. const EffectTarget target) override;
  66. void process(const size_t samplesToDo, const al::span<const FloatBufferLine> samplesIn,
  67. const al::span<FloatBufferLine> samplesOut) override;
  68. DEF_NEWDEL(CompressorState)
  69. };
  70. void CompressorState::deviceUpdate(const DeviceBase *device, const Buffer&)
  71. {
  72. /* Number of samples to do a full attack and release (non-integer sample
  73. * counts are okay).
  74. */
  75. const float attackCount{static_cast<float>(device->Frequency) * ATTACK_TIME};
  76. const float releaseCount{static_cast<float>(device->Frequency) * RELEASE_TIME};
  77. /* Calculate per-sample multipliers to attack and release at the desired
  78. * rates.
  79. */
  80. mAttackMult = std::pow(AMP_ENVELOPE_MAX/AMP_ENVELOPE_MIN, 1.0f/attackCount);
  81. mReleaseMult = std::pow(AMP_ENVELOPE_MIN/AMP_ENVELOPE_MAX, 1.0f/releaseCount);
  82. }
  83. void CompressorState::update(const ContextBase*, const EffectSlot *slot,
  84. const EffectProps *props, const EffectTarget target)
  85. {
  86. mEnabled = props->Compressor.OnOff;
  87. mOutTarget = target.Main->Buffer;
  88. auto set_gains = [slot,target](auto &gains, al::span<const float,MaxAmbiChannels> coeffs)
  89. { ComputePanGains(target.Main, coeffs.data(), slot->Gain, gains); };
  90. SetAmbiPanIdentity(std::begin(mGain), slot->Wet.Buffer.size(), set_gains);
  91. }
  92. void CompressorState::process(const size_t samplesToDo,
  93. const al::span<const FloatBufferLine> samplesIn, const al::span<FloatBufferLine> samplesOut)
  94. {
  95. for(size_t base{0u};base < samplesToDo;)
  96. {
  97. float gains[256];
  98. const size_t td{minz(256, samplesToDo-base)};
  99. /* Generate the per-sample gains from the signal envelope. */
  100. float env{mEnvFollower};
  101. if(mEnabled)
  102. {
  103. for(size_t i{0u};i < td;++i)
  104. {
  105. /* Clamp the absolute amplitude to the defined envelope limits,
  106. * then attack or release the envelope to reach it.
  107. */
  108. const float amplitude{clampf(std::fabs(samplesIn[0][base+i]), AMP_ENVELOPE_MIN,
  109. AMP_ENVELOPE_MAX)};
  110. if(amplitude > env)
  111. env = minf(env*mAttackMult, amplitude);
  112. else if(amplitude < env)
  113. env = maxf(env*mReleaseMult, amplitude);
  114. /* Apply the reciprocal of the envelope to normalize the volume
  115. * (compress the dynamic range).
  116. */
  117. gains[i] = 1.0f / env;
  118. }
  119. }
  120. else
  121. {
  122. /* Same as above, except the amplitude is forced to 1. This helps
  123. * ensure smooth gain changes when the compressor is turned on and
  124. * off.
  125. */
  126. for(size_t i{0u};i < td;++i)
  127. {
  128. const float amplitude{1.0f};
  129. if(amplitude > env)
  130. env = minf(env*mAttackMult, amplitude);
  131. else if(amplitude < env)
  132. env = maxf(env*mReleaseMult, amplitude);
  133. gains[i] = 1.0f / env;
  134. }
  135. }
  136. mEnvFollower = env;
  137. /* Now compress the signal amplitude to output. */
  138. auto changains = std::addressof(mGain[0]);
  139. for(const auto &input : samplesIn)
  140. {
  141. const float *outgains{*(changains++)};
  142. for(FloatBufferLine &output : samplesOut)
  143. {
  144. const float gain{*(outgains++)};
  145. if(!(std::fabs(gain) > GainSilenceThreshold))
  146. continue;
  147. for(size_t i{0u};i < td;i++)
  148. output[base+i] += input[base+i] * gains[i] * gain;
  149. }
  150. }
  151. base += td;
  152. }
  153. }
  154. struct CompressorStateFactory final : public EffectStateFactory {
  155. al::intrusive_ptr<EffectState> create() override
  156. { return al::intrusive_ptr<EffectState>{new CompressorState{}}; }
  157. };
  158. } // namespace
  159. EffectStateFactory *CompressorStateFactory_getFactory()
  160. {
  161. static CompressorStateFactory CompressorFactory{};
  162. return &CompressorFactory;
  163. }