The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
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.

157 lines
5.2KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - Raw Material Software Limited
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-licence
  10. Privacy Policy: www.juce.com/juce-privacy-policy
  11. Or: You may also use this code under the terms of the GPL v3 (see
  12. www.gnu.org/licenses).
  13. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  14. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  15. DISCLAIMED.
  16. ==============================================================================
  17. */
  18. namespace juce::dsp
  19. {
  20. /**
  21. Adds a DC offset (voltage bias) to the audio samples.
  22. This is a useful preprocessor for asymmetric waveshaping when a waveshaper is
  23. bookended by a bias on input and a DC-offset removing high pass filter on output.
  24. This is an extremely simple bias implementation that simply adds a value to a signal.
  25. More complicated bias behaviours exist in real circuits - for your homework ;).
  26. @tags{DSP}
  27. */
  28. template <typename FloatType>
  29. class Bias
  30. {
  31. public:
  32. Bias() noexcept = default;
  33. //==============================================================================
  34. /** Sets the DC bias
  35. @param newBias DC offset in range [-1, 1]
  36. */
  37. void setBias (FloatType newBias) noexcept
  38. {
  39. jassert (newBias >= static_cast<FloatType> (-1) && newBias <= static_cast<FloatType> (1));
  40. bias.setTargetValue (newBias);
  41. }
  42. //==============================================================================
  43. /** Returns the DC bias
  44. @return DC bias, which should be in the range [-1, 1]
  45. */
  46. FloatType getBias() const noexcept { return bias.getTargetValue(); }
  47. /** Sets the length of the ramp used for smoothing gain changes. */
  48. void setRampDurationSeconds (double newDurationSeconds) noexcept
  49. {
  50. if (! approximatelyEqual (rampDurationSeconds, newDurationSeconds))
  51. {
  52. rampDurationSeconds = newDurationSeconds;
  53. updateRamp();
  54. }
  55. }
  56. double getRampDurationSeconds() const noexcept { return rampDurationSeconds; }
  57. //==============================================================================
  58. /** Called before processing starts */
  59. void prepare (const ProcessSpec& spec) noexcept
  60. {
  61. sampleRate = spec.sampleRate;
  62. updateRamp();
  63. }
  64. void reset() noexcept
  65. {
  66. bias.reset (sampleRate, rampDurationSeconds);
  67. }
  68. //==============================================================================
  69. /** Returns the result of processing a single sample. */
  70. template <typename SampleType>
  71. SampleType processSample (SampleType inputSample) noexcept
  72. {
  73. return inputSample + bias.getNextValue();
  74. }
  75. //==============================================================================
  76. /** Processes the input and output buffers supplied in the processing context. */
  77. template <typename ProcessContext>
  78. void process (const ProcessContext& context) noexcept
  79. {
  80. auto&& inBlock = context.getInputBlock();
  81. auto&& outBlock = context.getOutputBlock();
  82. jassert (inBlock.getNumChannels() == outBlock.getNumChannels());
  83. jassert (inBlock.getNumSamples() == outBlock.getNumSamples());
  84. auto len = inBlock.getNumSamples();
  85. auto numChannels = inBlock.getNumChannels();
  86. if (context.isBypassed)
  87. {
  88. bias.skip (static_cast<int> (len));
  89. if (context.usesSeparateInputAndOutputBlocks())
  90. outBlock.copyFrom (inBlock);
  91. return;
  92. }
  93. if (numChannels == 1)
  94. {
  95. auto* src = inBlock.getChannelPointer (0);
  96. auto* dst = outBlock.getChannelPointer (0);
  97. for (size_t i = 0; i < len; ++i)
  98. dst[i] = src[i] + bias.getNextValue();
  99. }
  100. else
  101. {
  102. JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6255 6386)
  103. auto* biases = static_cast<FloatType*> (alloca (sizeof (FloatType) * len));
  104. for (size_t i = 0; i < len; ++i)
  105. biases[i] = bias.getNextValue();
  106. for (size_t chan = 0; chan < numChannels; ++chan)
  107. FloatVectorOperations::add (outBlock.getChannelPointer (chan),
  108. inBlock.getChannelPointer (chan),
  109. biases, static_cast<int> (len));
  110. JUCE_END_IGNORE_WARNINGS_MSVC
  111. }
  112. }
  113. private:
  114. //==============================================================================
  115. SmoothedValue<FloatType> bias;
  116. double sampleRate = 0, rampDurationSeconds = 0;
  117. void updateRamp() noexcept
  118. {
  119. if (sampleRate > 0)
  120. bias.reset (sampleRate, rampDurationSeconds);
  121. }
  122. };
  123. } // namespace juce::dsp