Extra "ports" of juce-based plugins using the distrho build system
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.

376 lines
12KB

  1. /*
  2. ==============================================================================
  3. This file was auto-generated by the Introjucer!
  4. It contains the basic framework code for a JUCE plugin processor.
  5. ==============================================================================
  6. */
  7. #include "PluginProcessor.h"
  8. #include "MainComponent.h"
  9. bool PureDataAudioProcessor::otherInstanceAlreadyRunning;
  10. //==============================================================================
  11. PureDataAudioProcessor::PureDataAudioProcessor()
  12. {
  13. for (int i=0; i<10; i++) {
  14. FloatParameter* p = new FloatParameter (0.5, ("Param" + (String) (i+1)).toStdString());
  15. parameterList.add(p);
  16. addParameter(p);
  17. }
  18. if(PureDataAudioProcessor::otherInstanceAlreadyRunning) {
  19. isInstanceLocked = true;
  20. }
  21. PureDataAudioProcessor::otherInstanceAlreadyRunning = true;
  22. }
  23. PureDataAudioProcessor::~PureDataAudioProcessor()
  24. {
  25. pd = nullptr;
  26. if (!isInstanceLocked) {
  27. PureDataAudioProcessor::otherInstanceAlreadyRunning = false;
  28. }
  29. }
  30. //==============================================================================
  31. void PureDataAudioProcessor::setParameterName(int index, String name)
  32. {
  33. FloatParameter* p = parameterList.getUnchecked(index);
  34. p->setName(name);
  35. }
  36. const String PureDataAudioProcessor::getName() const
  37. {
  38. return JucePlugin_Name;
  39. }
  40. const String PureDataAudioProcessor::getInputChannelName (int channelIndex) const
  41. {
  42. return String (channelIndex + 1);
  43. }
  44. const String PureDataAudioProcessor::getOutputChannelName (int channelIndex) const
  45. {
  46. return String (channelIndex + 1);
  47. }
  48. bool PureDataAudioProcessor::isInputChannelStereoPair (int index) const
  49. {
  50. return true;
  51. }
  52. bool PureDataAudioProcessor::isOutputChannelStereoPair (int index) const
  53. {
  54. return true;
  55. }
  56. bool PureDataAudioProcessor::acceptsMidi() const
  57. {
  58. #if JucePlugin_WantsMidiInput
  59. return true;
  60. #else
  61. return false;
  62. #endif
  63. }
  64. bool PureDataAudioProcessor::producesMidi() const
  65. {
  66. #if JucePlugin_ProducesMidiOutput
  67. return true;
  68. #else
  69. return false;
  70. #endif
  71. }
  72. bool PureDataAudioProcessor::silenceInProducesSilenceOut() const
  73. {
  74. return false;
  75. }
  76. double PureDataAudioProcessor::getTailLengthSeconds() const
  77. {
  78. return 0.0;
  79. }
  80. int PureDataAudioProcessor::getNumPrograms()
  81. {
  82. return 1; // NB: some hosts don't cope very well if you tell them there are 0 programs,
  83. // so this should be at least 1, even if you're not really implementing programs.
  84. }
  85. int PureDataAudioProcessor::getCurrentProgram()
  86. {
  87. return 0;
  88. }
  89. void PureDataAudioProcessor::setCurrentProgram (int index)
  90. {
  91. }
  92. const String PureDataAudioProcessor::getProgramName (int index)
  93. {
  94. return String();
  95. }
  96. void PureDataAudioProcessor::changeProgramName (int index, const String& newName)
  97. {
  98. }
  99. //==============================================================================
  100. void PureDataAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
  101. {
  102. // Use this method as the place to do any pre-playback
  103. // initialisation that you need..
  104. reloadPatch(sampleRate);
  105. pos = 0;
  106. }
  107. void PureDataAudioProcessor::releaseResources()
  108. {
  109. // When playback stops, you can use this as an opportunity to free up any
  110. // spare memory, etc.
  111. if (pd != nullptr)
  112. {
  113. pd->computeAudio (false);
  114. pd->closePatch (patch);
  115. }
  116. pd = nullptr;
  117. pdInBuffer.free();
  118. pdOutBuffer.free();
  119. }
  120. void PureDataAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
  121. {
  122. if (isInstanceLocked) {
  123. return;
  124. }
  125. // In case we have more outputs than inputs, this code clears any output channels that didn't contain input data, (because these aren't guaranteed to be empty - they may contain garbage).
  126. // I've added this to avoid people getting screaming feedback when they first compile the plugin, but obviously you don't need to this code if your algorithm already fills all the output channels.
  127. for (int i = getTotalNumInputChannels(); i < getTotalNumOutputChannels(); ++i)
  128. buffer.clear (i, 0, buffer.getNumSamples());
  129. int numChannels = jmin (getTotalNumInputChannels(), getTotalNumOutputChannels());
  130. int len = buffer.getNumSamples();
  131. int idx = 0;
  132. for (int i=0; i<parameterList.size(); i++) {
  133. FloatParameter* parameter = parameterList[i];
  134. pd->sendFloat(parameter->getName(300).toStdString(), parameter->getValue());
  135. }
  136. MidiMessage message;
  137. MidiBuffer::Iterator it (midiMessages);
  138. int samplePosition = buffer.getNumSamples();
  139. while (it.getNextEvent (message, samplePosition))
  140. {
  141. if (message.isNoteOn (true)) {
  142. pd->sendNoteOn (message.getChannel(), message.getNoteNumber(), message.getVelocity());
  143. }
  144. if (message.isNoteOff (true)) {
  145. pd->sendNoteOn (message.getChannel(), message.getNoteNumber(), 0);
  146. }
  147. }
  148. while (len > 0)
  149. {
  150. int max = jmin (len, pd->blockSize());
  151. /* interleave audio */
  152. {
  153. float* dstBuffer = pdInBuffer.getData();
  154. for (int i = 0; i < max; ++i)
  155. {
  156. for (int channelIndex = 0; channelIndex < numChannels; ++channelIndex)
  157. *dstBuffer++ = buffer.getReadPointer(channelIndex) [idx + i];
  158. }
  159. }
  160. pd->processFloat (1, pdInBuffer.getData(), pdOutBuffer.getData());
  161. /* write-back */
  162. {
  163. const float* srcBuffer = pdOutBuffer.getData();
  164. for (int i = 0; i < max; ++i)
  165. {
  166. for (int channelIndex = 0; channelIndex < numChannels; ++channelIndex)
  167. buffer.getWritePointer (channelIndex) [idx + i] = *srcBuffer++;
  168. }
  169. }
  170. idx += max;
  171. len -= max;
  172. }
  173. }
  174. //==============================================================================
  175. bool PureDataAudioProcessor::hasEditor() const
  176. {
  177. return true; // (change this to false if you choose to not supply an editor)
  178. }
  179. AudioProcessorEditor* PureDataAudioProcessor::createEditor()
  180. {
  181. return new MainComponent(*this);
  182. }
  183. //==============================================================================
  184. void PureDataAudioProcessor::getStateInformation (MemoryBlock& destData)
  185. {
  186. // You should use this method to store your parameters in the memory block.
  187. // You could do that either as raw data, or use the XML or ValueTree classes
  188. // as intermediaries to make it easy to save and load complex data.
  189. // STORE / SAVE
  190. XmlElement xml(getName());
  191. // patchfile
  192. XmlElement* patchfileElement = new XmlElement("patchfile");
  193. patchfileElement->setAttribute("path", patchfile.getParentDirectory().getFullPathName());
  194. patchfileElement->setAttribute("fullpath", patchfile.getFullPathName());
  195. patchfileElement->setAttribute("filename", patchfile.getFileName());
  196. xml.addChildElement(patchfileElement);
  197. // parameters
  198. XmlElement* parameterListElement = new XmlElement("parameterList");
  199. for(size_t i = 0; i < parameterList.size(); ++i) {
  200. XmlElement* parameterElement = new XmlElement("parameter");
  201. FloatParameter* parameter = parameterList[i];
  202. parameterElement->setAttribute("index", (int) parameter->getParameterIndex());
  203. parameterElement->setAttribute("name", parameter->getName(256));
  204. parameterElement->setAttribute("value", (double) parameter->getValue());
  205. parameterListElement->addChildElement(parameterElement);
  206. }
  207. xml.addChildElement(parameterListElement);
  208. MemoryOutputStream stream;
  209. xml.writeToStream(stream, "");
  210. //std::cout << "save [" << stream.toString() << "] " << std::endl;
  211. copyXmlToBinary(xml, destData);
  212. }
  213. void PureDataAudioProcessor::setStateInformation (const void* data, int sizeInBytes)
  214. {
  215. // You should use this method to restore your parameters from this memory block,
  216. // whose contents will have been created by the getStateInformation() call.
  217. // RESTORE / LOAD
  218. ScopedPointer<XmlElement> xml(getXmlFromBinary(data, sizeInBytes));
  219. if(xml != 0 && xml->hasTagName(getName())) {
  220. MemoryOutputStream stream;
  221. xml->writeToStream(stream, "<?xml version=\"1.0\"?>");
  222. //std::cout << "load [" << stream.toString() << "] " << std::endl;
  223. forEachXmlChildElement (*xml, child)
  224. {
  225. std::cout << " - load : " << child->getTagName() << std::endl;
  226. if(child->hasTagName("patchfile")) {
  227. File path(child->getStringAttribute ("fullpath"));
  228. if (path.exists()) {
  229. patchfile = path; // creates a copy
  230. reloadPatch(NULL);
  231. } else {
  232. // Todo add exclamation mark or something
  233. std::cout << "cant find " << child->getStringAttribute("fullpath") << std::endl;
  234. }
  235. }
  236. if(child->hasTagName("parameterList")) {
  237. forEachXmlChildElement (*child, parameterElement) {
  238. //std::cout << "loading param " << parameterElement->getStringAttribute("name");
  239. //std::cout << "[" << parameterElement->getIntAttribute("index") << "]: ";
  240. //std::cout << parameterElement->getDoubleAttribute("value") << std::endl;
  241. setParameter(parameterElement->getIntAttribute("index"), (float) parameterElement->getDoubleAttribute("value"));
  242. setParameterName(parameterElement->getIntAttribute("index"), parameterElement->getStringAttribute("name"));
  243. }
  244. }
  245. }
  246. }
  247. }
  248. void PureDataAudioProcessor::reloadPatch (double sampleRate)
  249. {
  250. if (isInstanceLocked) {
  251. status = "Currently only one simultaneous instance of this plugin is allowed";
  252. return;
  253. }
  254. if (sampleRate) {
  255. cachedSampleRate = sampleRate;
  256. } else {
  257. sampleRate = cachedSampleRate;
  258. }
  259. if (pd) {
  260. pd->computeAudio(false);
  261. pd->closePatch(patch);
  262. }
  263. pd = new pd::PdBase;
  264. pd->init (getTotalNumInputChannels(), getTotalNumOutputChannels(), sampleRate);
  265. int numChannels = jmin (getTotalNumInputChannels(), getTotalNumOutputChannels());
  266. pdInBuffer.calloc (pd->blockSize() * numChannels);
  267. pdOutBuffer.calloc (pd->blockSize() * numChannels);
  268. if (!patchfile.exists()) {
  269. if (patchfile.getFullPathName().toStdString() != "") {
  270. status = "File does not exist";
  271. }
  272. return;
  273. }
  274. if (patchfile.isDirectory()) {
  275. status = "You selected a directory";
  276. return;
  277. }
  278. patch = pd->openPatch (patchfile.getFileName().toStdString(), patchfile.getParentDirectory().getFullPathName().toStdString());
  279. if (patch.isValid()) {
  280. pd->computeAudio (true);
  281. status = "Patch loaded successfully";
  282. } else {
  283. status = "Selected patch is not valid, sorry";
  284. }
  285. }
  286. void PureDataAudioProcessor::setPatchFile(File file)
  287. {
  288. patchfile = file;
  289. }
  290. File PureDataAudioProcessor::getPatchFile()
  291. {
  292. return patchfile;
  293. }
  294. //==============================================================================
  295. // This creates new instances of the plugin..
  296. AudioProcessor* JUCE_CALLTYPE createPluginFilter()
  297. {
  298. return new PureDataAudioProcessor();
  299. }