Audio plugin host https://kx.studio/carla
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.

247 lines
7.3KB

  1. /*
  2. * Carla Native Plugins
  3. * Copyright (C) 2013-2014 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  16. */
  17. #include "CarlaNative.hpp"
  18. #include "juce_audio_processors.h"
  19. #include "juce_gui_extra.h"
  20. using namespace juce;
  21. // -----------------------------------------------------------------------
  22. #include "juce-host/FilterGraph.h"
  23. #include "juce-host/InternalFilters.h"
  24. #include "juce-host/GraphEditorPanel.h"
  25. #include "juce-host/MainHostWindow.h"
  26. // -----------------------------------------------------------------------
  27. class JucePatchbayPlugin : public NativePluginClass
  28. {
  29. public:
  30. JucePatchbayPlugin(const NativeHostDescriptor* const host)
  31. : NativePluginClass(host),
  32. graph(formatManager),
  33. fAudioBuffer(1, 0)
  34. {
  35. PropertiesFile::Options options;
  36. options.applicationName = "Juce Audio Plugin Host";
  37. options.filenameSuffix = "settings";
  38. options.osxLibrarySubFolder = "Preferences";
  39. fAppProperties = new ApplicationProperties();
  40. fAppProperties->setStorageParameters(options);
  41. formatManager.addDefaultFormats();
  42. formatManager.addFormat(new InternalPluginFormat());
  43. graph.ready(fAppProperties);
  44. graph.getGraph().setPlayConfigDetails(2, 2, getSampleRate(), static_cast<int>(getBufferSize()));
  45. fMidiBuffer.ensureSize(512*2);
  46. fMidiBuffer.clear();
  47. }
  48. ~JucePatchbayPlugin() override
  49. {
  50. graph.clear();
  51. fAppProperties = nullptr;
  52. }
  53. protected:
  54. // -------------------------------------------------------------------
  55. // Plugin process calls
  56. void activate() override
  57. {
  58. graph.getGraph().prepareToPlay(getSampleRate(), static_cast<int>(getBufferSize()));
  59. fAudioBuffer.setSize(2, static_cast<int>(getBufferSize()));
  60. }
  61. void deactivate() override
  62. {
  63. graph.getGraph().releaseResources();
  64. }
  65. void process(float** inBuffer, float** const outBuffer, const uint32_t frames, const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount) override
  66. {
  67. fAudioBuffer.copyFrom(0, 0, inBuffer[0], static_cast<int>(frames));
  68. fAudioBuffer.copyFrom(1, 0, inBuffer[1], static_cast<int>(frames));
  69. fMidiBuffer.clear();
  70. for (uint32_t i=0; i < midiEventCount; ++i)
  71. {
  72. const NativeMidiEvent* const midiEvent(&midiEvents[i]);
  73. fMidiBuffer.addEvent(midiEvent->data, midiEvent->size, midiEvent->time);
  74. }
  75. graph.getGraph().processBlock(fAudioBuffer, fMidiBuffer);
  76. MidiBuffer::Iterator outBufferIterator(fMidiBuffer);
  77. const uint8_t* midiData;
  78. int numBytes;
  79. int sampleNumber;
  80. NativeMidiEvent tmpEvent;
  81. tmpEvent.port = 0;
  82. for (; outBufferIterator.getNextEvent(midiData, numBytes, sampleNumber);)
  83. {
  84. if (numBytes <= 0 || numBytes > 4)
  85. continue;
  86. tmpEvent.size = numBytes;
  87. tmpEvent.time = sampleNumber;
  88. std::memcpy(tmpEvent.data, midiData, sizeof(uint8_t)*tmpEvent.size);
  89. writeMidiEvent(&tmpEvent);
  90. }
  91. FloatVectorOperations::copy(outBuffer[0], fAudioBuffer.getSampleData(0), static_cast<int>(frames));
  92. FloatVectorOperations::copy(outBuffer[1], fAudioBuffer.getSampleData(1), static_cast<int>(frames));
  93. }
  94. // -------------------------------------------------------------------
  95. // Plugin UI calls
  96. void uiShow(const bool show) override
  97. {
  98. const MessageManagerLock mmLock;
  99. if (show)
  100. {
  101. if (fWindow == nullptr)
  102. {
  103. fWindow = new MainHostWindow(formatManager, graph, *fAppProperties);
  104. fWindow->setName(getUiName());
  105. }
  106. fWindow->toFront(true);
  107. }
  108. else if (fWindow != nullptr)
  109. {
  110. fWindow->setVisible(false);
  111. fWindow = nullptr;
  112. }
  113. }
  114. void uiIdle() override
  115. {
  116. if (fWindow == nullptr)
  117. return;
  118. if (fWindow->wasClosedByUser())
  119. {
  120. uiShow(false);
  121. uiClosed();
  122. }
  123. }
  124. // -------------------------------------------------------------------
  125. // Plugin state calls
  126. char* getState() const override
  127. {
  128. ScopedPointer<XmlElement> xml(graph.createXml());
  129. MemoryOutputStream stream;
  130. xml->writeToStream(stream, String::empty);
  131. return strdup(stream.toUTF8().toRawUTF8());
  132. }
  133. void setState(const char* const data) override
  134. {
  135. CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
  136. String sdata(data);
  137. XmlDocument doc(sdata);
  138. ScopedPointer<XmlElement> xml(doc.getDocumentElement());
  139. if (xml != nullptr && xml->hasTagName("FILTERGRAPH"))
  140. graph.restoreFromXml(*xml);
  141. }
  142. // -------------------------------------------------------------------
  143. // Plugin dispatcher calls
  144. void uiNameChanged(const char* const uiName) override
  145. {
  146. CARLA_SAFE_ASSERT_RETURN(uiName != nullptr,);
  147. if (fWindow == nullptr)
  148. return;
  149. const MessageManagerLock mmLock;
  150. fWindow->setName(uiName);
  151. }
  152. private:
  153. AudioPluginFormatManager formatManager;
  154. FilterGraph graph;
  155. AudioSampleBuffer fAudioBuffer;
  156. MidiBuffer fMidiBuffer;
  157. ScopedPointer<ApplicationProperties> fAppProperties;
  158. ScopedPointer<MainHostWindow> fWindow;
  159. PluginClassEND(JucePatchbayPlugin)
  160. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(JucePatchbayPlugin)
  161. };
  162. // -----------------------------------------------------------------------
  163. static const NativePluginDescriptor jucePatchbayDesc = {
  164. /* category */ PLUGIN_CATEGORY_UTILITY,
  165. /* hints */ static_cast<NativePluginHints>(PLUGIN_IS_SYNTH|PLUGIN_HAS_UI|PLUGIN_NEEDS_FIXED_BUFFERS|/*PLUGIN_NEEDS_SINGLE_THREAD|*/PLUGIN_NEEDS_UI_JUCE|PLUGIN_USES_STATE|PLUGIN_USES_TIME),
  166. /* supports */ static_cast<NativePluginSupports>(0x0),
  167. /* audioIns */ 2,
  168. /* audioOuts */ 2,
  169. /* midiIns */ 1,
  170. /* midiOuts */ 1,
  171. /* paramIns */ 0,
  172. /* paramOuts */ 0,
  173. /* name */ "Juce Patchbay",
  174. /* label */ "jucePatchbay",
  175. /* maker */ "falkTX",
  176. /* copyright */ "GNU GPL v2+",
  177. PluginDescriptorFILL(JucePatchbayPlugin)
  178. };
  179. // -----------------------------------------------------------------------
  180. CARLA_EXPORT
  181. void carla_register_native_plugin_jucePatchbay()
  182. {
  183. carla_register_native_plugin(&jucePatchbayDesc);
  184. }
  185. // -----------------------------------------------------------------------
  186. #include "juce-host/juce_MidiKeyboardComponent.h"
  187. #include "juce-host/juce_MidiKeyboardComponent.cpp"
  188. #include "juce-host/FilterGraph.cpp"
  189. #include "juce-host/InternalFilters.cpp"
  190. #include "juce-host/GraphEditorPanel.cpp"
  191. #include "juce-host/MainHostWindow.cpp"
  192. // -----------------------------------------------------------------------