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.

154 lines
5.8KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  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 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. /**
  20. Applies a gain to audio samples as single samples or AudioBlocks.
  21. */
  22. template <typename SampleType>
  23. class Oscillator
  24. {
  25. public:
  26. /** The NumericType is the underlying primitive type used by the SampleType (which
  27. could be either a primitive or vector)
  28. */
  29. using NumericType = typename SampleTypeHelpers::ElementType<SampleType>::Type;
  30. /** Creates an oscillator with a periodic input function (-pi..pi).
  31. If lookup table is not zero, then the function will be approximated
  32. with a lookup table.
  33. */
  34. Oscillator (const std::function<NumericType (NumericType)>& function, size_t lookupTableNumPoints = 0)
  35. : generator (function), frequency (440.0f)
  36. {
  37. if (lookupTableNumPoints != 0)
  38. {
  39. auto table = new LookupTableTransform<NumericType> (generator, static_cast <NumericType> (-1.0 * double_Pi),
  40. static_cast<NumericType> (double_Pi), lookupTableNumPoints);
  41. lookupTable = table;
  42. generator = [table] (NumericType x) { return (*table) (x); };
  43. }
  44. }
  45. //==============================================================================
  46. /** Applies a new gain as a linear value. */
  47. void setFrequency (NumericType newGain) noexcept { frequency.setValue (newGain); }
  48. /** Returns the current gain as a linear value. */
  49. NumericType getFrequency() const noexcept { return frequency.getTargetValue(); }
  50. //==============================================================================
  51. /** Called before processing starts. */
  52. void prepare (const ProcessSpec& spec) noexcept
  53. {
  54. sampleRate = static_cast<NumericType> (spec.sampleRate);
  55. rampBuffer.resize ((int) spec.maximumBlockSize);
  56. reset();
  57. }
  58. /** Resets the internal state of the gain */
  59. void reset() noexcept
  60. {
  61. pos = 0.0;
  62. if (sampleRate > 0)
  63. frequency.reset (sampleRate, 0.05);
  64. }
  65. //==============================================================================
  66. /** Returns the result of processing a single sample. */
  67. SampleType JUCE_VECTOR_CALLTYPE processSample (SampleType) noexcept
  68. {
  69. auto increment = static_cast<NumericType> (2.0 * double_Pi) * frequency.getNextValue() / sampleRate;
  70. auto value = generator (pos - static_cast<NumericType> (double_Pi));
  71. pos = std::fmod (pos + increment, static_cast<NumericType> (2.0 * double_Pi));
  72. return value;
  73. }
  74. /** Processes the input and output buffers supplied in the processing context. */
  75. template <typename ProcessContext>
  76. void process (const ProcessContext& context) noexcept
  77. {
  78. auto&& outBlock = context.getOutputBlock();
  79. // this is an output-only processory
  80. jassert (context.getInputBlock().getNumChannels() == 0 || (! context.usesSeparateInputAndOutputBlocks()));
  81. jassert (outBlock.getNumSamples() <= static_cast<size_t> (rampBuffer.size()));
  82. auto len = outBlock.getNumSamples();
  83. auto numChannels = outBlock.getNumChannels();
  84. auto baseIncrement = static_cast<NumericType> (2.0 * double_Pi) / sampleRate;
  85. if (frequency.isSmoothing())
  86. {
  87. auto* buffer = rampBuffer.getRawDataPointer();
  88. for (size_t i = 0; i < len; ++i)
  89. {
  90. buffer[i] = pos - static_cast<NumericType> (double_Pi);
  91. pos = std::fmod (pos + (baseIncrement * frequency.getNextValue()), static_cast<NumericType> (2.0 * double_Pi));
  92. }
  93. for (size_t ch = 0; ch < numChannels; ++ch)
  94. {
  95. auto* dst = outBlock.getChannelPointer (ch);
  96. for (size_t i = 0; i < len; ++i)
  97. dst[i] = generator (buffer[i]);
  98. }
  99. }
  100. else
  101. {
  102. auto freq = baseIncrement * frequency.getNextValue();
  103. for (size_t ch = 0; ch < numChannels; ++ch)
  104. {
  105. auto p = pos;
  106. auto* dst = outBlock.getChannelPointer (ch);
  107. for (size_t i = 0; i < len; ++i)
  108. {
  109. dst[i] = generator (p - static_cast<NumericType> (double_Pi));
  110. p = std::fmod (p + freq, static_cast<NumericType> (2.0 * double_Pi));
  111. }
  112. }
  113. pos = std::fmod (pos + freq * static_cast<NumericType> (len), static_cast<NumericType> (2.0 * double_Pi));
  114. }
  115. }
  116. private:
  117. //==============================================================================
  118. std::function<NumericType (NumericType)> generator;
  119. ScopedPointer<LookupTableTransform<NumericType>> lookupTable;
  120. Array<NumericType> rampBuffer;
  121. LinearSmoothedValue<NumericType> frequency {static_cast<NumericType> (440.0)};
  122. NumericType sampleRate = 48000.0, pos = 0.0;
  123. };