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.

276 lines
8.1KB

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