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.

391 lines
12KB

  1. /*
  2. ==============================================================================
  3. This file was auto-generated by the Jucer!
  4. It contains the basic startup code for a Juce application.
  5. ==============================================================================
  6. */
  7. #include "PluginProcessor.h"
  8. #include "PluginEditor.h"
  9. AudioProcessor* JUCE_CALLTYPE createPluginFilter();
  10. //==============================================================================
  11. /** A demo synth sound that's just a basic sine wave.. */
  12. class SineWaveSound : public SynthesiserSound
  13. {
  14. public:
  15. SineWaveSound() {}
  16. bool appliesToNote (const int /*midiNoteNumber*/) { return true; }
  17. bool appliesToChannel (const int /*midiChannel*/) { return true; }
  18. };
  19. //==============================================================================
  20. /** A simple demo synth voice that just plays a sine wave.. */
  21. class SineWaveVoice : public SynthesiserVoice
  22. {
  23. public:
  24. SineWaveVoice()
  25. : angleDelta (0.0),
  26. tailOff (0.0)
  27. {
  28. }
  29. bool canPlaySound (SynthesiserSound* sound)
  30. {
  31. return dynamic_cast <SineWaveSound*> (sound) != 0;
  32. }
  33. void startNote (int midiNoteNumber, float velocity,
  34. SynthesiserSound* /*sound*/, int /*currentPitchWheelPosition*/)
  35. {
  36. currentAngle = 0.0;
  37. level = velocity * 0.15;
  38. tailOff = 0.0;
  39. double cyclesPerSecond = MidiMessage::getMidiNoteInHertz (midiNoteNumber);
  40. double cyclesPerSample = cyclesPerSecond / getSampleRate();
  41. angleDelta = cyclesPerSample * 2.0 * double_Pi;
  42. }
  43. void stopNote (bool allowTailOff)
  44. {
  45. if (allowTailOff)
  46. {
  47. // start a tail-off by setting this flag. The render callback will pick up on
  48. // this and do a fade out, calling clearCurrentNote() when it's finished.
  49. if (tailOff == 0.0) // we only need to begin a tail-off if it's not already doing so - the
  50. // stopNote method could be called more than once.
  51. tailOff = 1.0;
  52. }
  53. else
  54. {
  55. // we're being told to stop playing immediately, so reset everything..
  56. clearCurrentNote();
  57. angleDelta = 0.0;
  58. }
  59. }
  60. void pitchWheelMoved (int /*newValue*/)
  61. {
  62. // can't be bothered implementing this for the demo!
  63. }
  64. void controllerMoved (int /*controllerNumber*/, int /*newValue*/)
  65. {
  66. // not interested in controllers in this case.
  67. }
  68. void renderNextBlock (AudioSampleBuffer& outputBuffer, int startSample, int numSamples)
  69. {
  70. if (angleDelta != 0.0)
  71. {
  72. if (tailOff > 0)
  73. {
  74. while (--numSamples >= 0)
  75. {
  76. const float currentSample = (float) (sin (currentAngle) * level * tailOff);
  77. for (int i = outputBuffer.getNumChannels(); --i >= 0;)
  78. *outputBuffer.getSampleData (i, startSample) += currentSample;
  79. currentAngle += angleDelta;
  80. ++startSample;
  81. tailOff *= 0.99;
  82. if (tailOff <= 0.005)
  83. {
  84. clearCurrentNote();
  85. angleDelta = 0.0;
  86. break;
  87. }
  88. }
  89. }
  90. else
  91. {
  92. while (--numSamples >= 0)
  93. {
  94. const float currentSample = (float) (sin (currentAngle) * level);
  95. for (int i = outputBuffer.getNumChannels(); --i >= 0;)
  96. *outputBuffer.getSampleData (i, startSample) += currentSample;
  97. currentAngle += angleDelta;
  98. ++startSample;
  99. }
  100. }
  101. }
  102. }
  103. private:
  104. double currentAngle, angleDelta, level, tailOff;
  105. };
  106. //==============================================================================
  107. JuceDemoPluginAudioProcessor::JuceDemoPluginAudioProcessor()
  108. : delayBuffer (2, 12000)
  109. {
  110. // Set up some default values..
  111. gain = 1.0f;
  112. delay = 0.5f;
  113. lastUIWidth = 400;
  114. lastUIHeight = 200;
  115. lastPosInfo.resetToDefault();
  116. delayPosition = 0;
  117. // Initialise the synth...
  118. for (int i = 4; --i >= 0;)
  119. synth.addVoice (new SineWaveVoice()); // These voices will play our custom sine-wave sounds..
  120. synth.addSound (new SineWaveSound());
  121. }
  122. JuceDemoPluginAudioProcessor::~JuceDemoPluginAudioProcessor()
  123. {
  124. }
  125. //==============================================================================
  126. int JuceDemoPluginAudioProcessor::getNumParameters()
  127. {
  128. return totalNumParams;
  129. }
  130. float JuceDemoPluginAudioProcessor::getParameter (int index)
  131. {
  132. // This method will be called by the host, probably on the audio thread, so
  133. // it's absolutely time-critical. Don't use critical sections or anything
  134. // UI-related, or anything at all that may block in any way!
  135. switch (index)
  136. {
  137. case gainParam: return gain;
  138. case delayParam: return delay;
  139. default: return 0.0f;
  140. }
  141. }
  142. void JuceDemoPluginAudioProcessor::setParameter (int index, float newValue)
  143. {
  144. // This method will be called by the host, probably on the audio thread, so
  145. // it's absolutely time-critical. Don't use critical sections or anything
  146. // UI-related, or anything at all that may block in any way!
  147. switch (index)
  148. {
  149. case gainParam: gain = newValue; break;
  150. case delayParam: delay = newValue; break;
  151. default: break;
  152. }
  153. }
  154. const String JuceDemoPluginAudioProcessor::getParameterName (int index)
  155. {
  156. switch (index)
  157. {
  158. case gainParam: return "gain";
  159. case delayParam: return "delay";
  160. default: break;
  161. }
  162. return String::empty;
  163. }
  164. const String JuceDemoPluginAudioProcessor::getParameterText (int index)
  165. {
  166. return String (getParameter (index), 2);
  167. }
  168. //==============================================================================
  169. void JuceDemoPluginAudioProcessor::prepareToPlay (double sampleRate, int /*samplesPerBlock*/)
  170. {
  171. // Use this method as the place to do any pre-playback
  172. // initialisation that you need..
  173. synth.setCurrentPlaybackSampleRate (sampleRate);
  174. keyboardState.reset();
  175. delayBuffer.clear();
  176. }
  177. void JuceDemoPluginAudioProcessor::releaseResources()
  178. {
  179. // When playback stops, you can use this as an opportunity to free up any
  180. // spare memory, etc.
  181. keyboardState.reset();
  182. }
  183. void JuceDemoPluginAudioProcessor::reset()
  184. {
  185. // Use this method as the place to clear any delay lines, buffers, etc, as it
  186. // means there's been a break in the audio's continuity.
  187. delayBuffer.clear();
  188. }
  189. void JuceDemoPluginAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
  190. {
  191. const int numSamples = buffer.getNumSamples();
  192. int channel, dp = 0;
  193. // Go through the incoming data, and apply our gain to it...
  194. for (channel = 0; channel < getNumInputChannels(); ++channel)
  195. buffer.applyGain (channel, 0, buffer.getNumSamples(), gain);
  196. // Now pass any incoming midi messages to our keyboard state object, and let it
  197. // add messages to the buffer if the user is clicking on the on-screen keys
  198. keyboardState.processNextMidiBuffer (midiMessages, 0, numSamples, true);
  199. // and now get the synth to process these midi events and generate its output.
  200. synth.renderNextBlock (buffer, midiMessages, 0, numSamples);
  201. // Apply our delay effect to the new output..
  202. for (channel = 0; channel < getNumInputChannels(); ++channel)
  203. {
  204. float* channelData = buffer.getSampleData (channel);
  205. float* delayData = delayBuffer.getSampleData (jmin (channel, delayBuffer.getNumChannels() - 1));
  206. dp = delayPosition;
  207. for (int i = 0; i < numSamples; ++i)
  208. {
  209. const float in = channelData[i];
  210. channelData[i] += delayData[dp];
  211. delayData[dp] = (delayData[dp] + in) * delay;
  212. if (++dp >= delayBuffer.getNumSamples())
  213. dp = 0;
  214. }
  215. }
  216. delayPosition = dp;
  217. // In case we have more outputs than inputs, we'll clear any output
  218. // channels that didn't contain input data, (because these aren't
  219. // guaranteed to be empty - they may contain garbage).
  220. for (int i = getNumInputChannels(); i < getNumOutputChannels(); ++i)
  221. buffer.clear (i, 0, buffer.getNumSamples());
  222. // ask the host for the current time so we can display it...
  223. AudioPlayHead::CurrentPositionInfo newTime;
  224. if (getPlayHead() != nullptr && getPlayHead()->getCurrentPosition (newTime))
  225. {
  226. // Successfully got the current time from the host..
  227. lastPosInfo = newTime;
  228. }
  229. else
  230. {
  231. // If the host fails to fill-in the current time, we'll just clear it to a default..
  232. lastPosInfo.resetToDefault();
  233. }
  234. }
  235. //==============================================================================
  236. AudioProcessorEditor* JuceDemoPluginAudioProcessor::createEditor()
  237. {
  238. return new JuceDemoPluginAudioProcessorEditor (this);
  239. }
  240. //==============================================================================
  241. void JuceDemoPluginAudioProcessor::getStateInformation (MemoryBlock& destData)
  242. {
  243. // You should use this method to store your parameters in the memory block.
  244. // Here's an example of how you can use XML to make it easy and more robust:
  245. // Create an outer XML element..
  246. XmlElement xml ("MYPLUGINSETTINGS");
  247. // add some attributes to it..
  248. xml.setAttribute ("uiWidth", lastUIWidth);
  249. xml.setAttribute ("uiHeight", lastUIHeight);
  250. xml.setAttribute ("gain", gain);
  251. xml.setAttribute ("delay", delay);
  252. // then use this helper function to stuff it into the binary blob and return it..
  253. copyXmlToBinary (xml, destData);
  254. }
  255. void JuceDemoPluginAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
  256. {
  257. // You should use this method to restore your parameters from this memory block,
  258. // whose contents will have been created by the getStateInformation() call.
  259. // This getXmlFromBinary() helper function retrieves our XML from the binary blob..
  260. ScopedPointer<XmlElement> xmlState (getXmlFromBinary (data, sizeInBytes));
  261. if (xmlState != nullptr)
  262. {
  263. // make sure that it's actually our type of XML object..
  264. if (xmlState->hasTagName ("MYPLUGINSETTINGS"))
  265. {
  266. // ok, now pull out our parameters..
  267. lastUIWidth = xmlState->getIntAttribute ("uiWidth", lastUIWidth);
  268. lastUIHeight = xmlState->getIntAttribute ("uiHeight", lastUIHeight);
  269. gain = (float) xmlState->getDoubleAttribute ("gain", gain);
  270. delay = (float) xmlState->getDoubleAttribute ("delay", delay);
  271. }
  272. }
  273. }
  274. const String JuceDemoPluginAudioProcessor::getInputChannelName (const int channelIndex) const
  275. {
  276. return String (channelIndex + 1);
  277. }
  278. const String JuceDemoPluginAudioProcessor::getOutputChannelName (const int channelIndex) const
  279. {
  280. return String (channelIndex + 1);
  281. }
  282. bool JuceDemoPluginAudioProcessor::isInputChannelStereoPair (int /*index*/) const
  283. {
  284. return true;
  285. }
  286. bool JuceDemoPluginAudioProcessor::isOutputChannelStereoPair (int /*index*/) const
  287. {
  288. return true;
  289. }
  290. bool JuceDemoPluginAudioProcessor::acceptsMidi() const
  291. {
  292. #if JucePlugin_WantsMidiInput
  293. return true;
  294. #else
  295. return false;
  296. #endif
  297. }
  298. bool JuceDemoPluginAudioProcessor::producesMidi() const
  299. {
  300. #if JucePlugin_ProducesMidiOutput
  301. return true;
  302. #else
  303. return false;
  304. #endif
  305. }
  306. bool JuceDemoPluginAudioProcessor::silenceInProducesSilenceOut() const
  307. {
  308. return false;
  309. }
  310. double JuceDemoPluginAudioProcessor::getTailLengthSeconds() const
  311. {
  312. return 0.0;
  313. }
  314. //==============================================================================
  315. // This creates new instances of the plugin..
  316. AudioProcessor* JUCE_CALLTYPE createPluginFilter()
  317. {
  318. return new JuceDemoPluginAudioProcessor();
  319. }