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.

284 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. const uint8_t* midiData;
  102. int numBytes;
  103. int sampleNumber;
  104. NativeMidiEvent tmpEvent;
  105. tmpEvent.port = 0;
  106. for (MidiBuffer::Iterator outBufferIterator(fMidiBuffer); outBufferIterator.getNextEvent(midiData, numBytes, sampleNumber);)
  107. {
  108. if (numBytes <= 0 || numBytes > 4)
  109. continue;
  110. tmpEvent.size = numBytes;
  111. tmpEvent.time = sampleNumber;
  112. std::memcpy(tmpEvent.data, midiData, sizeof(uint8_t)*tmpEvent.size);
  113. writeMidiEvent(&tmpEvent);
  114. }
  115. }
  116. // -------------------------------------------------------------------
  117. // Plugin UI calls
  118. void uiShow(const bool show) override
  119. {
  120. const MessageManagerLock mmLock;
  121. if (show)
  122. {
  123. if (fWindow == nullptr)
  124. {
  125. fWindow = new MainHostWindow(fFormatManager, fGraph, *fAppProperties);
  126. fWindow->setName(getUiName());
  127. #ifdef HAVE_X11
  128. ::Window thisWinId = (::Window)fWindow->getWindowHandle();
  129. ::Window hostWinId = (::Window)getUiParentId();
  130. if (display != nullptr && thisWinId != 0 && hostWinId != 0)
  131. XSetTransientForHint(display, thisWinId, hostWinId);
  132. #endif
  133. }
  134. {
  135. const ScopedLock csl(fMidiKeyMutex);
  136. fMidiKeyState = fWindow->getMidiState();
  137. }
  138. fWindow->toFront(true);
  139. }
  140. else if (fWindow != nullptr)
  141. {
  142. {
  143. const ScopedLock csl(fMidiKeyMutex);
  144. fMidiKeyState = nullptr;
  145. }
  146. fWindow->setVisible(false);
  147. fWindow = nullptr;
  148. }
  149. }
  150. void uiIdle() override
  151. {
  152. if (fWindow == nullptr)
  153. return;
  154. if (fWindow->wasClosedByUser())
  155. {
  156. uiShow(false);
  157. uiClosed();
  158. }
  159. }
  160. // -------------------------------------------------------------------
  161. // Plugin state calls
  162. char* getState() const override
  163. {
  164. ScopedPointer<XmlElement> xml(fGraph.createXml());
  165. MemoryOutputStream stream;
  166. xml->writeToStream(stream, String::empty);
  167. return strdup(stream.toUTF8().toRawUTF8());
  168. }
  169. void setState(const char* const data) override
  170. {
  171. CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
  172. String sdata(data);
  173. XmlDocument doc(sdata);
  174. ScopedPointer<XmlElement> xml(doc.getDocumentElement());
  175. if (xml != nullptr && xml->hasTagName("FILTERGRAPH"))
  176. fGraph.restoreFromXml(*xml);
  177. }
  178. // -------------------------------------------------------------------
  179. // Plugin dispatcher calls
  180. void uiNameChanged(const char* const uiName) override
  181. {
  182. CARLA_SAFE_ASSERT_RETURN(uiName != nullptr,);
  183. if (fWindow == nullptr)
  184. return;
  185. const MessageManagerLock mmLock;
  186. fWindow->setName(uiName);
  187. }
  188. private:
  189. AudioPluginFormatManager fFormatManager;
  190. FilterGraph fGraph;
  191. AudioSampleBuffer fAudioBuffer;
  192. MidiBuffer fMidiBuffer;
  193. ScopedPointer<ApplicationProperties> fAppProperties;
  194. ScopedPointer<MainHostWindow> fWindow;
  195. MidiKeyboardState* fMidiKeyState;
  196. CriticalSection fMidiKeyMutex;
  197. PluginClassEND(JucePatchbayPlugin)
  198. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(JucePatchbayPlugin)
  199. };
  200. // -----------------------------------------------------------------------
  201. static const NativePluginDescriptor jucepatchbayDesc = {
  202. /* category */ PLUGIN_CATEGORY_UTILITY,
  203. /* 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),
  204. /* supports */ static_cast<NativePluginSupports>(0x0),
  205. /* audioIns */ 2,
  206. /* audioOuts */ 2,
  207. /* midiIns */ 1,
  208. /* midiOuts */ 1,
  209. /* paramIns */ 0,
  210. /* paramOuts */ 0,
  211. /* name */ "Juce Patchbay",
  212. /* label */ "jucepatchbay",
  213. /* maker */ "falkTX, Raw Material Software Ltd.",
  214. /* copyright */ "GNU GPL v2+",
  215. PluginDescriptorFILL(JucePatchbayPlugin)
  216. };
  217. // -----------------------------------------------------------------------
  218. CARLA_EXPORT
  219. void carla_register_native_plugin_jucepatchbay()
  220. {
  221. carla_register_native_plugin(&jucepatchbayDesc);
  222. }
  223. // -----------------------------------------------------------------------