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.

285 lines
8.3KB

  1. /*
  2. * Carla Native Plugins
  3. * Copyright (C) 2012-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 "JuceInternalFilters.hpp"
  19. #include "juce_gui_extra.h"
  20. #ifdef HAVE_X11
  21. # include <X11/Xlib.h>
  22. # undef KeyPress
  23. #endif
  24. // -----------------------------------------------------------------------
  25. namespace juce {
  26. #include "jucepluginhost/juce_MidiKeyboardComponent.h"
  27. #include "jucepluginhost/juce_MidiKeyboardComponent.cpp"
  28. #include "jucepluginhost/FilterGraph.h"
  29. #include "jucepluginhost/GraphEditorPanel.h"
  30. #include "jucepluginhost/MainHostWindow.h"
  31. #include "jucepluginhost/FilterGraph.cpp"
  32. #include "jucepluginhost/GraphEditorPanel.cpp"
  33. #include "jucepluginhost/MainHostWindow.cpp"
  34. #ifdef HAVE_X11
  35. extern Display* display;
  36. #endif
  37. }
  38. using namespace juce;
  39. // -----------------------------------------------------------------------
  40. class JucePatchbayPlugin : public NativePluginClass
  41. {
  42. public:
  43. JucePatchbayPlugin(const NativeHostDescriptor* const host)
  44. : NativePluginClass(host),
  45. fFormatManager(),
  46. fGraph(fFormatManager),
  47. fMidiKeyState(nullptr)
  48. {
  49. PropertiesFile::Options options;
  50. options.applicationName = "Juce Audio Plugin Host";
  51. options.filenameSuffix = "settings";
  52. options.osxLibrarySubFolder = "Preferences";
  53. fAppProperties = new ApplicationProperties();
  54. fAppProperties->setStorageParameters(options);
  55. fFormatManager.addDefaultFormats();
  56. fFormatManager.addFormat(new InternalPluginFormat());
  57. fGraph.ready(fAppProperties);
  58. fGraph.getGraph().setPlayConfigDetails(2, 2, getSampleRate(), static_cast<int>(getBufferSize()));
  59. fMidiBuffer.ensureSize(512*2);
  60. fMidiBuffer.clear();
  61. }
  62. ~JucePatchbayPlugin() override
  63. {
  64. fGraph.clear();
  65. fAppProperties = nullptr;
  66. }
  67. protected:
  68. // -------------------------------------------------------------------
  69. // Plugin process calls
  70. void activate() override
  71. {
  72. fGraph.getGraph().prepareToPlay(getSampleRate(), static_cast<int>(getBufferSize()));
  73. fAudioBuffer.setSize(2, static_cast<int>(getBufferSize()));
  74. {
  75. const ScopedLock csl(fMidiKeyMutex);
  76. if (fMidiKeyState != nullptr)
  77. fMidiKeyState->reset();
  78. }
  79. }
  80. void deactivate() override
  81. {
  82. fGraph.getGraph().releaseResources();
  83. }
  84. void process(float** inBuffer, float** const outBuffer, const uint32_t frames, const NativeMidiEvent* const midiEvents, const uint32_t midiEventCount) override
  85. {
  86. fMidiBuffer.clear();
  87. for (uint32_t i=0; i < midiEventCount; ++i)
  88. {
  89. const NativeMidiEvent* const midiEvent(&midiEvents[i]);
  90. fMidiBuffer.addEvent(midiEvent->data, midiEvent->size, midiEvent->time);
  91. }
  92. {
  93. const ScopedLock csl(fMidiKeyMutex);
  94. if (fMidiKeyState != nullptr)
  95. fMidiKeyState->processNextMidiBuffer(fMidiBuffer, 0, static_cast<int>(frames), true);
  96. }
  97. FloatVectorOperations::copy(outBuffer[0], inBuffer[0], static_cast<int>(frames));
  98. FloatVectorOperations::copy(outBuffer[1], inBuffer[1], static_cast<int>(frames));
  99. AudioSampleBuffer audioBuf(outBuffer, 2, static_cast<int>(frames));
  100. fGraph.getGraph().processBlock(audioBuf, fMidiBuffer);
  101. MidiBuffer::Iterator outBufferIterator(fMidiBuffer);
  102. const uint8_t* midiData;
  103. int numBytes;
  104. int sampleNumber;
  105. NativeMidiEvent tmpEvent;
  106. tmpEvent.port = 0;
  107. for (; outBufferIterator.getNextEvent(midiData, numBytes, sampleNumber);)
  108. {
  109. if (numBytes <= 0 || numBytes > 4)
  110. continue;
  111. tmpEvent.size = numBytes;
  112. tmpEvent.time = sampleNumber;
  113. std::memcpy(tmpEvent.data, midiData, sizeof(uint8_t)*tmpEvent.size);
  114. writeMidiEvent(&tmpEvent);
  115. }
  116. }
  117. // -------------------------------------------------------------------
  118. // Plugin UI calls
  119. void uiShow(const bool show) override
  120. {
  121. const MessageManagerLock mmLock;
  122. if (show)
  123. {
  124. if (fWindow == nullptr)
  125. {
  126. fWindow = new MainHostWindow(fFormatManager, fGraph, *fAppProperties);
  127. fWindow->setName(getUiName());
  128. #ifdef HAVE_X11
  129. ::Window thisWinId = (::Window)fWindow->getWindowHandle();
  130. ::Window hostWinId = (::Window)getUiParentId();
  131. if (display != nullptr && thisWinId != 0 && hostWinId != 0)
  132. XSetTransientForHint(display, thisWinId, hostWinId);
  133. #endif
  134. }
  135. {
  136. const ScopedLock csl(fMidiKeyMutex);
  137. fMidiKeyState = fWindow->getMidiState();
  138. }
  139. fWindow->toFront(true);
  140. }
  141. else if (fWindow != nullptr)
  142. {
  143. {
  144. const ScopedLock csl(fMidiKeyMutex);
  145. fMidiKeyState = nullptr;
  146. }
  147. fWindow->setVisible(false);
  148. fWindow = nullptr;
  149. }
  150. }
  151. void uiIdle() override
  152. {
  153. if (fWindow == nullptr)
  154. return;
  155. if (fWindow->wasClosedByUser())
  156. {
  157. uiShow(false);
  158. uiClosed();
  159. }
  160. }
  161. // -------------------------------------------------------------------
  162. // Plugin state calls
  163. char* getState() const override
  164. {
  165. ScopedPointer<XmlElement> xml(fGraph.createXml());
  166. MemoryOutputStream stream;
  167. xml->writeToStream(stream, String::empty);
  168. return strdup(stream.toUTF8().toRawUTF8());
  169. }
  170. void setState(const char* const data) override
  171. {
  172. CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
  173. String sdata(data);
  174. XmlDocument doc(sdata);
  175. ScopedPointer<XmlElement> xml(doc.getDocumentElement());
  176. if (xml != nullptr && xml->hasTagName("FILTERGRAPH"))
  177. fGraph.restoreFromXml(*xml);
  178. }
  179. // -------------------------------------------------------------------
  180. // Plugin dispatcher calls
  181. void uiNameChanged(const char* const uiName) override
  182. {
  183. CARLA_SAFE_ASSERT_RETURN(uiName != nullptr,);
  184. if (fWindow == nullptr)
  185. return;
  186. const MessageManagerLock mmLock;
  187. fWindow->setName(uiName);
  188. }
  189. private:
  190. AudioPluginFormatManager fFormatManager;
  191. FilterGraph fGraph;
  192. AudioSampleBuffer fAudioBuffer;
  193. MidiBuffer fMidiBuffer;
  194. ScopedPointer<ApplicationProperties> fAppProperties;
  195. ScopedPointer<MainHostWindow> fWindow;
  196. MidiKeyboardState* fMidiKeyState;
  197. CriticalSection fMidiKeyMutex;
  198. PluginClassEND(JucePatchbayPlugin)
  199. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(JucePatchbayPlugin)
  200. };
  201. // -----------------------------------------------------------------------
  202. static const NativePluginDescriptor jucepatchbayDesc = {
  203. /* category */ PLUGIN_CATEGORY_UTILITY,
  204. /* hints */ static_cast<NativePluginHints>(PLUGIN_IS_SYNTH|PLUGIN_HAS_UI|PLUGIN_NEEDS_FIXED_BUFFERS|PLUGIN_NEEDS_UI_JUCE|PLUGIN_USES_STATE/*|PLUGIN_USES_TIME*/|PLUGIN_USES_PARENT_ID),
  205. /* supports */ static_cast<NativePluginSupports>(0x0),
  206. /* audioIns */ 2,
  207. /* audioOuts */ 2,
  208. /* midiIns */ 1,
  209. /* midiOuts */ 1,
  210. /* paramIns */ 0,
  211. /* paramOuts */ 0,
  212. /* name */ "Juce Patchbay",
  213. /* label */ "jucepatchbay",
  214. /* maker */ "falkTX, Raw Material Software Ltd.",
  215. /* copyright */ "GNU GPL v2+",
  216. PluginDescriptorFILL(JucePatchbayPlugin)
  217. };
  218. // -----------------------------------------------------------------------
  219. CARLA_EXPORT
  220. void carla_register_native_plugin_jucepatchbay()
  221. {
  222. carla_register_native_plugin(&jucepatchbayDesc);
  223. }
  224. // -----------------------------------------------------------------------