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.

191 lines
7.7KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. #include "../JuceLibraryCode/JuceHeader.h"
  18. #include "../../GenericEditor.h"
  19. //==============================================================================
  20. /**
  21. */
  22. class Spatializer : public AudioProcessor
  23. {
  24. public:
  25. struct SpeakerPosition
  26. {
  27. float radius, phi;
  28. };
  29. struct SpeakerLayout
  30. {
  31. AudioChannelSet set;
  32. Array<SpeakerPosition> positions;
  33. };
  34. // this needs at least c++11
  35. static Array<SpeakerLayout> speakerPositions;
  36. //==============================================================================
  37. Spatializer() : currentSpeakerLayout (0)
  38. {
  39. // clear the default bus arrangements which were created by the base class
  40. busArrangement.inputBuses .clear();
  41. busArrangement.outputBuses.clear();
  42. // add mono in and default out
  43. busArrangement.inputBuses .add (AudioProcessorBus ("Input", AudioChannelSet::mono()));
  44. busArrangement.outputBuses.add (AudioProcessorBus ("Output", speakerPositions[currentSpeakerLayout].set));
  45. addParameter (radius = new AudioParameterFloat ("radius", "Radius", 0.0f, 1.0f, 0.5f));
  46. addParameter (phi = new AudioParameterFloat ("phi", "Phi", 0.0f, 1.0f, 0.0f));
  47. }
  48. ~Spatializer() {}
  49. //==============================================================================
  50. bool setPreferredBusArrangement (bool isInputBus, int busIndex,
  51. const AudioChannelSet& preferred) override
  52. {
  53. // we only allow mono in
  54. if (isInputBus && preferred != AudioChannelSet::mono())
  55. return false;
  56. // the output must be one of the supported speaker layouts
  57. if (! isInputBus)
  58. {
  59. int i;
  60. for (i = 0; i < speakerPositions.size(); ++i)
  61. if (speakerPositions[i].set == preferred) break;
  62. if (i >= speakerPositions.size())
  63. return false;
  64. currentSpeakerLayout = i;
  65. }
  66. return AudioProcessor::setPreferredBusArrangement (isInputBus, busIndex, preferred);
  67. }
  68. //==============================================================================
  69. void prepareToPlay (double sampleRate, int samplesPerBlock) override
  70. {
  71. scratchBuffer.setSize (1, samplesPerBlock);
  72. }
  73. void releaseResources() override {}
  74. void processBlock (AudioSampleBuffer& buffer, MidiBuffer&) override
  75. {
  76. // copy the input into a scratch buffer
  77. AudioSampleBuffer scratch (scratchBuffer.getArrayOfWritePointers(), 1, buffer.getNumSamples());
  78. scratch.copyFrom(0, 0, buffer, 0, 0, buffer.getNumSamples());
  79. const Array<SpeakerPosition>& positions = speakerPositions.getReference (currentSpeakerLayout).positions;
  80. const float* inputBuffer = scratch.getReadPointer (0);
  81. const float kMaxDistanceGain = -20.0f;
  82. for (int speakerIdx = 0; speakerIdx < positions.size(); ++speakerIdx)
  83. {
  84. const SpeakerPosition& speakerPos = positions.getReference (speakerIdx);
  85. float fltDistance = distance (polarToCartesian (speakerPos.radius, speakerPos.phi), polarToCartesian (*radius, (*phi) * 2.0f * float_Pi));
  86. float gainInDb = kMaxDistanceGain * (fltDistance / 2.0f);
  87. float gain = std::pow (10.0f, (gainInDb / 20.0f));
  88. busArrangement.getBusBuffer(buffer, false, 0).copyFrom(speakerIdx, 0, inputBuffer, buffer.getNumSamples(), gain);
  89. }
  90. }
  91. //==============================================================================
  92. AudioProcessorEditor* createEditor() override { return new GenericEditor (*this); }
  93. bool hasEditor() const override { return true; }
  94. //==============================================================================
  95. const String getName() const override { return "Gain PlugIn"; }
  96. bool acceptsMidi() const override { return false; }
  97. bool producesMidi() const override { return false; }
  98. double getTailLengthSeconds() const override { return 0; }
  99. //==============================================================================
  100. int getNumPrograms() override { return 1; }
  101. int getCurrentProgram() override { return 0; }
  102. void setCurrentProgram (int) override {}
  103. const String getProgramName (int) override { return String(); }
  104. void changeProgramName (int , const String& ) override { }
  105. //==============================================================================
  106. void getStateInformation (MemoryBlock& destData) override
  107. {
  108. MemoryOutputStream stream (destData, true);
  109. stream.writeFloat (*radius);
  110. stream.writeFloat (*phi);
  111. }
  112. void setStateInformation (const void* data, int sizeInBytes) override
  113. {
  114. MemoryInputStream stream (data, sizeInBytes, false);
  115. radius->setValueNotifyingHost (stream.readFloat());
  116. phi->setValueNotifyingHost (stream.readFloat());
  117. }
  118. private:
  119. //==============================================================================
  120. AudioParameterFloat* radius;
  121. AudioParameterFloat* phi;
  122. int currentSpeakerLayout;
  123. AudioSampleBuffer scratchBuffer;
  124. static Point<float> polarToCartesian (float r, float phi) noexcept
  125. {
  126. return Point<float> (r * std::cos (phi), r * std::sin (phi));
  127. }
  128. static float distance (Point<float> a, Point<float> b) noexcept
  129. {
  130. return std::sqrt (std::pow (a.x - b.x, 2.0f) + std::pow (a.y - b.y, 2.0f));
  131. }
  132. //==============================================================================
  133. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Spatializer)
  134. };
  135. // this needs at least c++11
  136. Array<Spatializer::SpeakerLayout> Spatializer::speakerPositions =
  137. {
  138. Spatializer::SpeakerLayout { AudioChannelSet::stereo(), { SpeakerPosition { 1.0f, -0.25f * float_Pi }, SpeakerPosition { 1.0f, 0.25f * float_Pi } }},
  139. Spatializer::SpeakerLayout { AudioChannelSet::quadraphonic(), { SpeakerPosition { 1.0f, -0.25f * float_Pi }, SpeakerPosition { 1.0f, 0.25f * float_Pi }, SpeakerPosition {1.0f, -0.75f * float_Pi}, SpeakerPosition {1.0f, 0.75f * float_Pi}}},
  140. Spatializer::SpeakerLayout { AudioChannelSet::create5point0(), {SpeakerPosition { 1.0f, 0.0f}, SpeakerPosition { 1.0f, -0.25f * float_Pi }, SpeakerPosition { 1.0f, 0.25f * float_Pi }, SpeakerPosition {1.0f, -0.75f * float_Pi}, SpeakerPosition {1.0f, 0.75f * float_Pi}}}
  141. };
  142. //==============================================================================
  143. // This creates new instances of the plugin..
  144. AudioProcessor* JUCE_CALLTYPE createPluginFilter()
  145. {
  146. return new Spatializer();
  147. }