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.

281 lines
10KB

  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. #include "PluginProcessor.h"
  20. #include "PluginEditor.h"
  21. #include "SinewaveSynth.h"
  22. AudioProcessor* JUCE_CALLTYPE createPluginFilter();
  23. //==============================================================================
  24. JuceDemoPluginAudioProcessor::JuceDemoPluginAudioProcessor()
  25. : AudioProcessor (getBusesProperties())
  26. {
  27. lastPosInfo.resetToDefault();
  28. // This creates our parameters. We'll keep some raw pointers to them in this class,
  29. // so that we can easily access them later, but the base class will take care of
  30. // deleting them for us.
  31. addParameter (gainParam = new AudioParameterFloat ("gain", "Gain", 0.0f, 1.0f, 0.9f));
  32. addParameter (delayParam = new AudioParameterFloat ("delay", "Delay Feedback", 0.0f, 1.0f, 0.5f));
  33. initialiseSynth();
  34. }
  35. JuceDemoPluginAudioProcessor::~JuceDemoPluginAudioProcessor()
  36. {
  37. }
  38. void JuceDemoPluginAudioProcessor::initialiseSynth()
  39. {
  40. const int numVoices = 8;
  41. // Add some voices...
  42. for (int i = numVoices; --i >= 0;)
  43. synth.addVoice (new SineWaveVoice());
  44. // ..and give the synth a sound to play
  45. synth.addSound (new SineWaveSound());
  46. }
  47. //==============================================================================
  48. bool JuceDemoPluginAudioProcessor::isBusesLayoutSupported (const BusesLayout& layouts) const
  49. {
  50. // Only mono/stereo and input/output must have same layout
  51. const AudioChannelSet& mainOutput = layouts.getMainOutputChannelSet();
  52. const AudioChannelSet& mainInput = layouts.getMainInputChannelSet();
  53. // input and output layout must either be the same or the input must be disabled altogether
  54. if (! mainInput.isDisabled() && mainInput != mainOutput)
  55. return false;
  56. // do not allow disabling the main buses
  57. if (mainOutput.isDisabled())
  58. return false;
  59. // only allow stereo and mono
  60. if (mainOutput.size() > 2)
  61. return false;
  62. return true;
  63. }
  64. AudioProcessor::BusesProperties JuceDemoPluginAudioProcessor::getBusesProperties()
  65. {
  66. return BusesProperties().withInput ("Input", AudioChannelSet::stereo(), true)
  67. .withOutput ("Output", AudioChannelSet::stereo(), true);
  68. }
  69. //==============================================================================
  70. void JuceDemoPluginAudioProcessor::prepareToPlay (double newSampleRate, int /*samplesPerBlock*/)
  71. {
  72. // Use this method as the place to do any pre-playback
  73. // initialisation that you need..
  74. synth.setCurrentPlaybackSampleRate (newSampleRate);
  75. keyboardState.reset();
  76. if (isUsingDoublePrecision())
  77. {
  78. delayBufferDouble.setSize (2, 12000);
  79. delayBufferFloat.setSize (1, 1);
  80. }
  81. else
  82. {
  83. delayBufferFloat.setSize (2, 12000);
  84. delayBufferDouble.setSize (1, 1);
  85. }
  86. reset();
  87. }
  88. void JuceDemoPluginAudioProcessor::releaseResources()
  89. {
  90. // When playback stops, you can use this as an opportunity to free up any
  91. // spare memory, etc.
  92. keyboardState.reset();
  93. }
  94. void JuceDemoPluginAudioProcessor::reset()
  95. {
  96. // Use this method as the place to clear any delay lines, buffers, etc, as it
  97. // means there's been a break in the audio's continuity.
  98. delayBufferFloat.clear();
  99. delayBufferDouble.clear();
  100. }
  101. template <typename FloatType>
  102. void JuceDemoPluginAudioProcessor::process (AudioBuffer<FloatType>& buffer,
  103. MidiBuffer& midiMessages,
  104. AudioBuffer<FloatType>& delayBuffer)
  105. {
  106. const int numSamples = buffer.getNumSamples();
  107. // Now pass any incoming midi messages to our keyboard state object, and let it
  108. // add messages to the buffer if the user is clicking on the on-screen keys
  109. keyboardState.processNextMidiBuffer (midiMessages, 0, numSamples, true);
  110. // and now get our synth to process these midi events and generate its output.
  111. synth.renderNextBlock (buffer, midiMessages, 0, numSamples);
  112. // Apply our delay effect to the new output..
  113. applyDelay (buffer, delayBuffer);
  114. // In case we have more outputs than inputs, we'll clear any output
  115. // channels that didn't contain input data, (because these aren't
  116. // guaranteed to be empty - they may contain garbage).
  117. for (int i = getTotalNumInputChannels(); i < getTotalNumOutputChannels(); ++i)
  118. buffer.clear (i, 0, numSamples);
  119. applyGain (buffer, delayBuffer); // apply our gain-change to the outgoing data..
  120. // Now ask the host for the current time so we can store it to be displayed later...
  121. updateCurrentTimeInfoFromHost();
  122. }
  123. template <typename FloatType>
  124. void JuceDemoPluginAudioProcessor::applyGain (AudioBuffer<FloatType>& buffer, AudioBuffer<FloatType>& delayBuffer)
  125. {
  126. ignoreUnused (delayBuffer);
  127. const float gainLevel = *gainParam;
  128. for (int channel = 0; channel < getTotalNumOutputChannels(); ++channel)
  129. buffer.applyGain (channel, 0, buffer.getNumSamples(), gainLevel);
  130. }
  131. template <typename FloatType>
  132. void JuceDemoPluginAudioProcessor::applyDelay (AudioBuffer<FloatType>& buffer, AudioBuffer<FloatType>& delayBuffer)
  133. {
  134. const int numSamples = buffer.getNumSamples();
  135. const float delayLevel = *delayParam;
  136. int delayPos = 0;
  137. for (int channel = 0; channel < getTotalNumOutputChannels(); ++channel)
  138. {
  139. auto channelData = buffer.getWritePointer (channel);
  140. auto delayData = delayBuffer.getWritePointer (jmin (channel, delayBuffer.getNumChannels() - 1));
  141. delayPos = delayPosition;
  142. for (int i = 0; i < numSamples; ++i)
  143. {
  144. auto in = channelData[i];
  145. channelData[i] += delayData[delayPos];
  146. delayData[delayPos] = (delayData[delayPos] + in) * delayLevel;
  147. if (++delayPos >= delayBuffer.getNumSamples())
  148. delayPos = 0;
  149. }
  150. }
  151. delayPosition = delayPos;
  152. }
  153. void JuceDemoPluginAudioProcessor::updateCurrentTimeInfoFromHost()
  154. {
  155. if (AudioPlayHead* ph = getPlayHead())
  156. {
  157. AudioPlayHead::CurrentPositionInfo newTime;
  158. if (ph->getCurrentPosition (newTime))
  159. {
  160. lastPosInfo = newTime; // Successfully got the current time from the host..
  161. return;
  162. }
  163. }
  164. // If the host fails to provide the current time, we'll just reset our copy to a default..
  165. lastPosInfo.resetToDefault();
  166. }
  167. //==============================================================================
  168. AudioProcessorEditor* JuceDemoPluginAudioProcessor::createEditor()
  169. {
  170. return new JuceDemoPluginAudioProcessorEditor (*this);
  171. }
  172. //==============================================================================
  173. void JuceDemoPluginAudioProcessor::getStateInformation (MemoryBlock& destData)
  174. {
  175. // You should use this method to store your parameters in the memory block.
  176. // Here's an example of how you can use XML to make it easy and more robust:
  177. // Create an outer XML element..
  178. XmlElement xml ("MYPLUGINSETTINGS");
  179. // add some attributes to it..
  180. xml.setAttribute ("uiWidth", lastUIWidth);
  181. xml.setAttribute ("uiHeight", lastUIHeight);
  182. // Store the values of all our parameters, using their param ID as the XML attribute
  183. for (auto* param : getParameters())
  184. if (auto* p = dynamic_cast<AudioProcessorParameterWithID*> (param))
  185. xml.setAttribute (p->paramID, p->getValue());
  186. // then use this helper function to stuff it into the binary blob and return it..
  187. copyXmlToBinary (xml, destData);
  188. }
  189. void JuceDemoPluginAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
  190. {
  191. // You should use this method to restore your parameters from this memory block,
  192. // whose contents will have been created by the getStateInformation() call.
  193. // This getXmlFromBinary() helper function retrieves our XML from the binary blob..
  194. ScopedPointer<XmlElement> xmlState (getXmlFromBinary (data, sizeInBytes));
  195. if (xmlState != nullptr)
  196. {
  197. // make sure that it's actually our type of XML object..
  198. if (xmlState->hasTagName ("MYPLUGINSETTINGS"))
  199. {
  200. // ok, now pull out our last window size..
  201. lastUIWidth = jmax (xmlState->getIntAttribute ("uiWidth", lastUIWidth), 400);
  202. lastUIHeight = jmax (xmlState->getIntAttribute ("uiHeight", lastUIHeight), 200);
  203. // Now reload our parameters..
  204. for (auto* param : getParameters())
  205. if (auto* p = dynamic_cast<AudioProcessorParameterWithID*> (param))
  206. p->setValue ((float) xmlState->getDoubleAttribute (p->paramID, p->getValue()));
  207. }
  208. }
  209. }
  210. void JuceDemoPluginAudioProcessor::updateTrackProperties (const TrackProperties& properties)
  211. {
  212. trackProperties = properties;
  213. if (auto* editor = dynamic_cast<JuceDemoPluginAudioProcessorEditor*> (getActiveEditor()))
  214. editor->updateTrackProperties ();
  215. }
  216. //==============================================================================
  217. // This creates new instances of the plugin..
  218. AudioProcessor* JUCE_CALLTYPE createPluginFilter()
  219. {
  220. return new JuceDemoPluginAudioProcessor();
  221. }