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.

274 lines
8.1KB

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