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.

219 lines
5.8KB

  1. // SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #ifndef CARLA_NATIVE_EXTERNAL_UI_HPP_INCLUDED
  4. #define CARLA_NATIVE_EXTERNAL_UI_HPP_INCLUDED
  5. #include "CarlaNative.hpp"
  6. #include "CarlaExternalUI.hpp"
  7. #include "CarlaMIDI.h"
  8. /*!
  9. * @defgroup CarlaNativeAPI Carla Native API
  10. * @{
  11. */
  12. // -----------------------------------------------------------------------
  13. // Native Plugin and External UI class
  14. class NativePluginAndUiClass : public NativePluginClass
  15. #ifndef CARLA_OS_WASM
  16. , public CarlaExternalUI
  17. #endif
  18. {
  19. public:
  20. NativePluginAndUiClass(const NativeHostDescriptor* const host, const char* const pathToExternalUI)
  21. : NativePluginClass(host),
  22. #ifndef CARLA_OS_WASM
  23. CarlaExternalUI(),
  24. #endif
  25. fExtUiPath(getResourceDir())
  26. {
  27. fExtUiPath += CARLA_OS_SEP_STR;
  28. fExtUiPath += pathToExternalUI;
  29. #ifdef CARLA_OS_WIN
  30. fExtUiPath += ".exe";
  31. #endif
  32. }
  33. const char* getExtUiPath() const noexcept
  34. {
  35. return fExtUiPath;
  36. }
  37. #ifndef CARLA_OS_WASM
  38. protected:
  39. // -------------------------------------------------------------------
  40. // Plugin UI calls
  41. void uiShow(const bool show) override
  42. {
  43. if (show)
  44. {
  45. if (isPipeRunning())
  46. {
  47. writeFocusMessage();
  48. return;
  49. }
  50. carla_stdout("Trying to start UI using \"%s\"", fExtUiPath.buffer());
  51. CarlaExternalUI::setData(fExtUiPath, getSampleRate(), getUiName());
  52. if (! CarlaExternalUI::startPipeServer(true))
  53. {
  54. uiClosed();
  55. hostUiUnavailable();
  56. }
  57. }
  58. else
  59. {
  60. CarlaExternalUI::stopPipeServer(2000);
  61. }
  62. }
  63. void uiIdle() override
  64. {
  65. CarlaExternalUI::idlePipe();
  66. switch (CarlaExternalUI::getAndResetUiState())
  67. {
  68. case CarlaExternalUI::UiNone:
  69. case CarlaExternalUI::UiShow:
  70. break;
  71. case CarlaExternalUI::UiCrashed:
  72. uiClosed();
  73. hostUiUnavailable();
  74. break;
  75. case CarlaExternalUI::UiHide:
  76. uiClosed();
  77. CarlaExternalUI::stopPipeServer(1000);
  78. break;
  79. }
  80. }
  81. void uiSetParameterValue(const uint32_t index, const float value) noexcept override
  82. {
  83. CARLA_SAFE_ASSERT_RETURN(index < getParameterCount(),);
  84. writeControlMessage(index, value);
  85. }
  86. void uiSetMidiProgram(const uint8_t channel, const uint32_t bank, const uint32_t program) noexcept override
  87. {
  88. CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
  89. writeProgramMessage(channel, bank, program);
  90. }
  91. void uiSetCustomData(const char* const key, const char* const value) noexcept override
  92. {
  93. CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
  94. CARLA_SAFE_ASSERT_RETURN(value != nullptr,);
  95. writeConfigureMessage(key, value);
  96. }
  97. void uiNameChanged(const char* const uiName) override
  98. {
  99. CARLA_SAFE_ASSERT_RETURN(uiName != nullptr && uiName[0] != '\0',);
  100. const CarlaMutexLocker cml(getPipeLock());
  101. if (! writeMessage("uiTitle\n", 8))
  102. return;
  103. if (! writeAndFixMessage(uiName))
  104. return;
  105. syncMessages();
  106. }
  107. bool uiMIDIEvent(const uint8_t size, const uint8_t data[]) override
  108. {
  109. if (size != 3)
  110. return false;
  111. const uint8_t status = MIDI_GET_STATUS_FROM_DATA(data);
  112. if (! (MIDI_IS_STATUS_NOTE_ON(status) || MIDI_IS_STATUS_NOTE_OFF(status)))
  113. return false;
  114. writeMidiNoteMessage(MIDI_IS_STATUS_NOTE_ON(status),
  115. MIDI_GET_CHANNEL_FROM_DATA(data),
  116. data[1], data[2]);
  117. return true;
  118. }
  119. // -------------------------------------------------------------------
  120. // Pipe Server calls
  121. bool msgReceived(const char* const msg) noexcept override
  122. {
  123. if (CarlaExternalUI::msgReceived(msg))
  124. return true;
  125. if (std::strcmp(msg, "control") == 0)
  126. {
  127. uint32_t param;
  128. float value;
  129. CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(param), true);
  130. CARLA_SAFE_ASSERT_RETURN(readNextLineAsFloat(value), true);
  131. try {
  132. uiParameterChanged(param, value);
  133. } CARLA_SAFE_EXCEPTION("uiParameterChanged");
  134. return true;
  135. }
  136. if (std::strcmp(msg, "program") == 0)
  137. {
  138. uint8_t channel;
  139. uint32_t bank, program;
  140. CARLA_SAFE_ASSERT_RETURN(readNextLineAsByte(channel), true);
  141. CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(bank), true);
  142. CARLA_SAFE_ASSERT_RETURN(readNextLineAsUInt(program), true);
  143. CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS, true);
  144. try {
  145. uiMidiProgramChanged(static_cast<uint8_t>(channel), bank, program);
  146. } CARLA_SAFE_EXCEPTION("uiMidiProgramChanged");
  147. return true;
  148. }
  149. if (std::strcmp(msg, "configure") == 0)
  150. {
  151. const char* key;
  152. const char* value;
  153. CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(key, true), true);
  154. CARLA_SAFE_ASSERT_RETURN(readNextLineAsString(value, false), true);
  155. try {
  156. uiCustomDataChanged(key, value);
  157. } CARLA_SAFE_EXCEPTION("uiCustomDataChanged");
  158. delete[] key;
  159. return true;
  160. }
  161. return false;
  162. }
  163. #endif
  164. private:
  165. String fExtUiPath;
  166. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(NativePluginAndUiClass)
  167. };
  168. /**@}*/
  169. // -----------------------------------------------------------------------
  170. #endif // CARLA_NATIVE_EXTERNAL_UI_HPP_INCLUDED