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.

288 lines
8.4KB

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