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.

405 lines
13KB

  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. const float defaultGain = 1.0f;
  107. const float defaultDelay = 0.5f;
  108. //==============================================================================
  109. JuceDemoPluginAudioProcessor::JuceDemoPluginAudioProcessor()
  110. : delayBuffer (2, 12000)
  111. {
  112. // Set up some default values..
  113. gain = defaultGain;
  114. delay = defaultDelay;
  115. lastUIWidth = 400;
  116. lastUIHeight = 200;
  117. lastPosInfo.resetToDefault();
  118. delayPosition = 0;
  119. // Initialise the synth...
  120. for (int i = 4; --i >= 0;)
  121. synth.addVoice (new SineWaveVoice()); // These voices will play our custom sine-wave sounds..
  122. synth.addSound (new SineWaveSound());
  123. }
  124. JuceDemoPluginAudioProcessor::~JuceDemoPluginAudioProcessor()
  125. {
  126. }
  127. //==============================================================================
  128. int JuceDemoPluginAudioProcessor::getNumParameters()
  129. {
  130. return totalNumParams;
  131. }
  132. float JuceDemoPluginAudioProcessor::getParameter (int index)
  133. {
  134. // This method will be called by the host, probably on the audio thread, so
  135. // it's absolutely time-critical. Don't use critical sections or anything
  136. // UI-related, or anything at all that may block in any way!
  137. switch (index)
  138. {
  139. case gainParam: return gain;
  140. case delayParam: return delay;
  141. default: return 0.0f;
  142. }
  143. }
  144. void JuceDemoPluginAudioProcessor::setParameter (int index, float newValue)
  145. {
  146. // This method will be called by the host, probably on the audio thread, so
  147. // it's absolutely time-critical. Don't use critical sections or anything
  148. // UI-related, or anything at all that may block in any way!
  149. switch (index)
  150. {
  151. case gainParam: gain = newValue; break;
  152. case delayParam: delay = newValue; break;
  153. default: break;
  154. }
  155. }
  156. float JuceDemoPluginAudioProcessor::getParameterDefaultValue (int index)
  157. {
  158. switch (index)
  159. {
  160. case gainParam: return defaultGain;
  161. case delayParam: return defaultDelay;
  162. default: break;
  163. }
  164. return 0.0f;
  165. }
  166. const String JuceDemoPluginAudioProcessor::getParameterName (int index)
  167. {
  168. switch (index)
  169. {
  170. case gainParam: return "gain";
  171. case delayParam: return "delay";
  172. default: break;
  173. }
  174. return String::empty;
  175. }
  176. const String JuceDemoPluginAudioProcessor::getParameterText (int index)
  177. {
  178. return String (getParameter (index), 2);
  179. }
  180. //==============================================================================
  181. void JuceDemoPluginAudioProcessor::prepareToPlay (double sampleRate, int /*samplesPerBlock*/)
  182. {
  183. // Use this method as the place to do any pre-playback
  184. // initialisation that you need..
  185. synth.setCurrentPlaybackSampleRate (sampleRate);
  186. keyboardState.reset();
  187. delayBuffer.clear();
  188. }
  189. void JuceDemoPluginAudioProcessor::releaseResources()
  190. {
  191. // When playback stops, you can use this as an opportunity to free up any
  192. // spare memory, etc.
  193. keyboardState.reset();
  194. }
  195. void JuceDemoPluginAudioProcessor::reset()
  196. {
  197. // Use this method as the place to clear any delay lines, buffers, etc, as it
  198. // means there's been a break in the audio's continuity.
  199. delayBuffer.clear();
  200. }
  201. void JuceDemoPluginAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
  202. {
  203. const int numSamples = buffer.getNumSamples();
  204. int channel, dp = 0;
  205. // Go through the incoming data, and apply our gain to it...
  206. for (channel = 0; channel < getNumInputChannels(); ++channel)
  207. buffer.applyGain (channel, 0, buffer.getNumSamples(), gain);
  208. // Now pass any incoming midi messages to our keyboard state object, and let it
  209. // add messages to the buffer if the user is clicking on the on-screen keys
  210. keyboardState.processNextMidiBuffer (midiMessages, 0, numSamples, true);
  211. // and now get the synth to process these midi events and generate its output.
  212. synth.renderNextBlock (buffer, midiMessages, 0, numSamples);
  213. // Apply our delay effect to the new output..
  214. for (channel = 0; channel < getNumInputChannels(); ++channel)
  215. {
  216. float* channelData = buffer.getSampleData (channel);
  217. float* delayData = delayBuffer.getSampleData (jmin (channel, delayBuffer.getNumChannels() - 1));
  218. dp = delayPosition;
  219. for (int i = 0; i < numSamples; ++i)
  220. {
  221. const float in = channelData[i];
  222. channelData[i] += delayData[dp];
  223. delayData[dp] = (delayData[dp] + in) * delay;
  224. if (++dp >= delayBuffer.getNumSamples())
  225. dp = 0;
  226. }
  227. }
  228. delayPosition = dp;
  229. // In case we have more outputs than inputs, we'll clear any output
  230. // channels that didn't contain input data, (because these aren't
  231. // guaranteed to be empty - they may contain garbage).
  232. for (int i = getNumInputChannels(); i < getNumOutputChannels(); ++i)
  233. buffer.clear (i, 0, buffer.getNumSamples());
  234. // ask the host for the current time so we can display it...
  235. AudioPlayHead::CurrentPositionInfo newTime;
  236. if (getPlayHead() != nullptr && getPlayHead()->getCurrentPosition (newTime))
  237. {
  238. // Successfully got the current time from the host..
  239. lastPosInfo = newTime;
  240. }
  241. else
  242. {
  243. // If the host fails to fill-in the current time, we'll just clear it to a default..
  244. lastPosInfo.resetToDefault();
  245. }
  246. }
  247. //==============================================================================
  248. AudioProcessorEditor* JuceDemoPluginAudioProcessor::createEditor()
  249. {
  250. return new JuceDemoPluginAudioProcessorEditor (this);
  251. }
  252. //==============================================================================
  253. void JuceDemoPluginAudioProcessor::getStateInformation (MemoryBlock& destData)
  254. {
  255. // You should use this method to store your parameters in the memory block.
  256. // Here's an example of how you can use XML to make it easy and more robust:
  257. // Create an outer XML element..
  258. XmlElement xml ("MYPLUGINSETTINGS");
  259. // add some attributes to it..
  260. xml.setAttribute ("uiWidth", lastUIWidth);
  261. xml.setAttribute ("uiHeight", lastUIHeight);
  262. xml.setAttribute ("gain", gain);
  263. xml.setAttribute ("delay", delay);
  264. // then use this helper function to stuff it into the binary blob and return it..
  265. copyXmlToBinary (xml, destData);
  266. }
  267. void JuceDemoPluginAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
  268. {
  269. // You should use this method to restore your parameters from this memory block,
  270. // whose contents will have been created by the getStateInformation() call.
  271. // This getXmlFromBinary() helper function retrieves our XML from the binary blob..
  272. ScopedPointer<XmlElement> xmlState (getXmlFromBinary (data, sizeInBytes));
  273. if (xmlState != nullptr)
  274. {
  275. // make sure that it's actually our type of XML object..
  276. if (xmlState->hasTagName ("MYPLUGINSETTINGS"))
  277. {
  278. // ok, now pull out our parameters..
  279. lastUIWidth = xmlState->getIntAttribute ("uiWidth", lastUIWidth);
  280. lastUIHeight = xmlState->getIntAttribute ("uiHeight", lastUIHeight);
  281. gain = (float) xmlState->getDoubleAttribute ("gain", gain);
  282. delay = (float) xmlState->getDoubleAttribute ("delay", delay);
  283. }
  284. }
  285. }
  286. const String JuceDemoPluginAudioProcessor::getInputChannelName (const int channelIndex) const
  287. {
  288. return String (channelIndex + 1);
  289. }
  290. const String JuceDemoPluginAudioProcessor::getOutputChannelName (const int channelIndex) const
  291. {
  292. return String (channelIndex + 1);
  293. }
  294. bool JuceDemoPluginAudioProcessor::isInputChannelStereoPair (int /*index*/) const
  295. {
  296. return true;
  297. }
  298. bool JuceDemoPluginAudioProcessor::isOutputChannelStereoPair (int /*index*/) const
  299. {
  300. return true;
  301. }
  302. bool JuceDemoPluginAudioProcessor::acceptsMidi() const
  303. {
  304. #if JucePlugin_WantsMidiInput
  305. return true;
  306. #else
  307. return false;
  308. #endif
  309. }
  310. bool JuceDemoPluginAudioProcessor::producesMidi() const
  311. {
  312. #if JucePlugin_ProducesMidiOutput
  313. return true;
  314. #else
  315. return false;
  316. #endif
  317. }
  318. bool JuceDemoPluginAudioProcessor::silenceInProducesSilenceOut() const
  319. {
  320. return false;
  321. }
  322. double JuceDemoPluginAudioProcessor::getTailLengthSeconds() const
  323. {
  324. return 0.0;
  325. }
  326. //==============================================================================
  327. // This creates new instances of the plugin..
  328. AudioProcessor* JUCE_CALLTYPE createPluginFilter()
  329. {
  330. return new JuceDemoPluginAudioProcessor();
  331. }