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.

476 lines
14KB

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # Carla plugin host (plugin UI)
  4. # Copyright (C) 2013 Filipe Coelho <falktx@falktx.com>
  5. #
  6. # This program is free software; you can redistribute it and/or
  7. # modify it under the terms of the GNU General Public License as
  8. # published by the Free Software Foundation; either version 2 of
  9. # the License, or any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # For a full copy of the GNU General Public License see the GPL.txt file
  17. # ------------------------------------------------------------------------------------------------------------
  18. # Imports (Global)
  19. from time import sleep
  20. # ------------------------------------------------------------------------------------------------------------
  21. # Imports (Custom Stuff)
  22. from carla_host import *
  23. from externalui import ExternalUI
  24. # ------------------------------------------------------------------------------------------------------------
  25. # Host Plugin object
  26. class PluginHost(object):
  27. def __init__(self, sampleRate):
  28. object.__init__(self)
  29. self.fSupportedFileExts = ""
  30. self.fBufferSize = 0
  31. self.fSampleRate = sampleRate
  32. self.fLastError = ""
  33. self.fIsRunning = True
  34. # -------------------------------------------------------------------
  35. def get_complete_license_text(self):
  36. return ""
  37. def get_supported_file_extensions(self):
  38. return self.fSupportedFileExts
  39. # -------------------------------------------------------------------
  40. def get_engine_driver_count(self):
  41. return 1
  42. def get_engine_driver_name(self, index):
  43. return "Plugin"
  44. def get_engine_driver_device_names(self, index):
  45. return []
  46. def get_engine_driver_device_info(self, index, name):
  47. return PyEngineDriverDeviceInfo
  48. # -------------------------------------------------------------------
  49. def get_internal_plugin_count(self):
  50. return int(self.lib.carla_get_internal_plugin_count())
  51. def get_internal_plugin_info(self, index):
  52. return None
  53. # -------------------------------------------------------------------
  54. def engine_init(self, driverName, clientName):
  55. return True
  56. def engine_close(self):
  57. return True
  58. def engine_idle(self):
  59. if Carla.gui.idleExternalUI():
  60. return
  61. self.fIsRunning = False
  62. Carla.gui.d_uiQuit()
  63. def is_engine_running(self):
  64. return self.fIsRunning
  65. def set_engine_about_to_close(self):
  66. pass
  67. def set_engine_callback(self, func):
  68. pass
  69. def set_engine_option(self, option, value, valueStr):
  70. Carla.gui.send(["set_engine_option", option, value, valueStr])
  71. # -------------------------------------------------------------------
  72. def set_file_callback(self, func):
  73. pass
  74. def load_file(self, filename):
  75. Carla.gui.send(["load_file", filename])
  76. return True
  77. def load_project(self, filename):
  78. Carla.gui.send(["load_project", filename])
  79. return True
  80. def save_project(self, filename):
  81. Carla.gui.send(["save_project", filename])
  82. return True
  83. # -------------------------------------------------------------------
  84. def patchbay_connect(self, portIdA, portIdB):
  85. Carla.gui.send(["patchbay_connect", portIdA, portIdB])
  86. return True
  87. def patchbay_disconnect(self, connectionId):
  88. Carla.gui.send(["patchbay_disconnect", connectionId])
  89. return True
  90. def patchbay_refresh(self):
  91. Carla.gui.send(["patchbay_refresh"])
  92. return True
  93. # -------------------------------------------------------------------
  94. def transport_play(self):
  95. Carla.gui.send(["transport_play"])
  96. def transport_pause(self):
  97. Carla.gui.send(["transport_pause"])
  98. def transport_relocate(self, frame):
  99. Carla.gui.send(["transport_relocate"])
  100. def get_current_transport_frame(self):
  101. return 0
  102. def get_transport_info(self):
  103. return PyCarlaTransportInfo
  104. # -------------------------------------------------------------------
  105. def add_plugin(self, btype, ptype, filename, name, label, extraPtr):
  106. Carla.gui.send(["add_plugin", btype, ptype, filename, name, label])
  107. return True
  108. def remove_plugin(self, pluginId):
  109. Carla.gui.send(["remove_plugin", pluginId])
  110. return True
  111. def remove_all_plugins(self):
  112. Carla.gui.send(["remove_all_plugins"])
  113. return True
  114. def rename_plugin(self, pluginId, newName):
  115. Carla.gui.send(["rename_plugin", pluginId, newName])
  116. return newName
  117. def clone_plugin(self, pluginId):
  118. Carla.gui.send(["clone_plugin", pluginId])
  119. return True
  120. def replace_plugin(self, pluginId):
  121. Carla.gui.send(["replace_plugin", pluginId])
  122. return True
  123. def switch_plugins(self, pluginIdA, pluginIdB):
  124. Carla.gui.send(["switch_plugins", pluginIdA, pluginIdB])
  125. return True
  126. # -------------------------------------------------------------------
  127. def load_plugin_state(self, pluginId, filename):
  128. Carla.gui.send(["load_plugin_state", pluginId, filename])
  129. return True
  130. def save_plugin_state(self, pluginId, filename):
  131. Carla.gui.send(["save_plugin_state", pluginId, filename])
  132. return True
  133. # -------------------------------------------------------------------
  134. def get_plugin_info(self, pluginId):
  135. return PyCarlaPluginInfo
  136. def get_audio_port_count_info(self, pluginId):
  137. return PyCarlaPortCountInfo
  138. def get_midi_port_count_info(self, pluginId):
  139. return PyCarlaPortCountInfo
  140. def get_parameter_count_info(self, pluginId):
  141. return PyCarlaPortCountInfo
  142. def get_parameter_info(self, pluginId, parameterId):
  143. return PyCarlaParameterInfo
  144. def get_parameter_scalepoint_info(self, pluginId, parameterId, scalePointId):
  145. return PyCarlaScalePointInfo
  146. # -------------------------------------------------------------------
  147. def get_parameter_data(self, pluginId, parameterId):
  148. return PyParameterData
  149. def get_parameter_ranges(self, pluginId, parameterId):
  150. return PyParameterRanges
  151. def get_midi_program_data(self, pluginId, midiProgramId):
  152. return PyMidiProgramData
  153. def get_custom_data(self, pluginId, customDataId):
  154. return PyCustomData
  155. def get_chunk_data(self, pluginId):
  156. return ""
  157. # -------------------------------------------------------------------
  158. def get_parameter_count(self, pluginId):
  159. return 0
  160. def get_program_count(self, pluginId):
  161. return 0
  162. def get_midi_program_count(self, pluginId):
  163. return 0
  164. def get_custom_data_count(self, pluginId):
  165. return 0
  166. # -------------------------------------------------------------------
  167. def get_parameter_text(self, pluginId, parameterId, value):
  168. return ""
  169. def get_program_name(self, pluginId, programId):
  170. return ""
  171. def get_midi_program_name(self, pluginId, midiProgramId):
  172. return ""
  173. def get_real_plugin_name(self, pluginId):
  174. return ""
  175. # -------------------------------------------------------------------
  176. def get_current_program_index(self, pluginId):
  177. return 0
  178. def get_current_midi_program_index(self, pluginId):
  179. return 0
  180. def get_default_parameter_value(self, pluginId, parameterId):
  181. return 0.0
  182. def get_current_parameter_value(self, pluginId, parameterId):
  183. return 0.0
  184. def get_input_peak_value(self, pluginId, isLeft):
  185. return 0.0
  186. def get_output_peak_value(self, pluginId, isLeft):
  187. return 0.0
  188. # -------------------------------------------------------------------
  189. def set_option(self, pluginId, option, yesNo):
  190. Carla.gui.send(["set_option", pluginId, option, yesNo])
  191. def set_active(self, pluginId, onOff):
  192. Carla.gui.send(["set_active", pluginId, onOff])
  193. def set_drywet(self, pluginId, value):
  194. Carla.gui.send(["set_drywet", pluginId, value])
  195. def set_volume(self, pluginId, value):
  196. Carla.gui.send(["set_volume", pluginId, value])
  197. def set_balance_left(self, pluginId, value):
  198. Carla.gui.send(["set_balance_left", pluginId, value])
  199. def set_balance_right(self, pluginId, value):
  200. Carla.gui.send(["set_balance_right", pluginId, value])
  201. def set_panning(self, pluginId, value):
  202. Carla.gui.send(["set_panning", pluginId, value])
  203. def set_ctrl_channel(self, pluginId, channel):
  204. Carla.gui.send(["set_ctrl_channel", pluginId, channel])
  205. # -------------------------------------------------------------------
  206. def set_parameter_value(self, pluginId, parameterId, value):
  207. Carla.gui.send(["set_parameter_value", pluginId, parameterId, value])
  208. def set_parameter_midi_channel(self, pluginId, parameterId, channel):
  209. Carla.gui.send(["set_parameter_midi_channel", pluginId, parameterId, channel])
  210. def set_parameter_midi_cc(self, pluginId, parameterId, cc):
  211. Carla.gui.send(["set_parameter_midi_cc", pluginId, parameterId, cc])
  212. def set_program(self, pluginId, programId):
  213. Carla.gui.send(["set_program", pluginId, programId])
  214. def set_midi_program(self, pluginId, midiProgramId):
  215. Carla.gui.send(["set_midi_program", pluginId, midiProgramId])
  216. def set_custom_data(self, pluginId, type_, key, value):
  217. Carla.gui.send(["set_custom_data", pluginId, type_, key, value])
  218. def set_chunk_data(self, pluginId, chunkData):
  219. Carla.gui.send(["set_chunk_data", pluginId, chunkData])
  220. # -------------------------------------------------------------------
  221. def prepare_for_save(self, pluginId):
  222. Carla.gui.send(["prepare_for_save", pluginId])
  223. def send_midi_note(self, pluginId, channel, note, velocity):
  224. Carla.gui.send(["send_midi_note", pluginId, channel, note, velocity])
  225. def show_custom_ui(self, pluginId, yesNo):
  226. Carla.gui.send(["show_custom_ui", pluginId, yesNo])
  227. # -------------------------------------------------------------------
  228. def get_buffer_size(self):
  229. return self.fBufferSize
  230. def get_sample_rate(self):
  231. return self.fSampleRate
  232. def get_last_error(self):
  233. return self.fLastError
  234. def get_host_osc_url_tcp(self):
  235. return ""
  236. def get_host_osc_url_udp(self):
  237. return ""
  238. # ------------------------------------------------------------------------------------------------------------
  239. # Main Window
  240. class CarlaMiniW(HostWindow, ExternalUI):
  241. def __init__(self):
  242. HostWindow.__init__(self, None)
  243. ExternalUI.__init__(self)
  244. if False:
  245. from carla_patchbay import CarlaPatchbayW
  246. self.fContainer = CarlaPatchbayW(self)
  247. else:
  248. from carla_rack import CarlaRackW
  249. self.fContainer = CarlaRackW(self)
  250. self.setupContainer(False)
  251. self.setWindowTitle(self.fUiName)
  252. self.showUiIfTesting()
  253. # -------------------------------------------------------------------
  254. # ExternalUI Callbacks
  255. def d_uiShow(self):
  256. self.show()
  257. def d_uiHide(self):
  258. self.hide()
  259. def d_uiQuit(self):
  260. self.close()
  261. app.quit()
  262. def d_uiTitleChanged(self, uiTitle):
  263. self.setWindowTitle(uiTitle)
  264. # -------------------------------------------------------------------
  265. # Qt events
  266. def closeEvent(self, event):
  267. self.closeExternalUI()
  268. HostWindow.closeEvent(self, event)
  269. # -------------------------------------------------------------------
  270. # Custom idler
  271. def idleExternalUI(self):
  272. while True:
  273. if self.fPipeRecv is None:
  274. return True
  275. try:
  276. msg = self.fPipeRecv.readline().strip()
  277. except IOError:
  278. return False
  279. if not msg:
  280. return True
  281. elif msg == "show":
  282. self.d_uiShow()
  283. elif msg == "hide":
  284. self.d_uiHide()
  285. elif msg == "quit":
  286. self.fQuitReceived = True
  287. self.d_uiQuit()
  288. elif msg == "uiTitle":
  289. uiTitle = self.fPipeRecv.readline().strip().replace("\r", "\n")
  290. self.d_uiTitleChanged(uiTitle)
  291. elif msg.startswith("ENGINE_CALLBACK_"):
  292. action = int(msg.replace("ENGINE_CALLBACK_", ""))
  293. pluginId = int(self.fPipeRecv.readline())
  294. value1 = int(self.fPipeRecv.readline())
  295. value2 = int(self.fPipeRecv.readline())
  296. value3 = float(self.fPipeRecv.readline())
  297. valueStr = self.fPipeRecv.readline().strip().replace("\r", "\n")
  298. engineCallback(None, action, pluginId, value1, value2, value3, valueStr)
  299. else:
  300. print("unknown message: \"" + msg + "\"")
  301. return True
  302. # ------------------------------------------------------------------------------------------------------------
  303. # Main
  304. if __name__ == '__main__':
  305. # -------------------------------------------------------------
  306. # App initialization
  307. app = CarlaApplication()
  308. # -------------------------------------------------------------
  309. # Set-up custom signal handling
  310. setUpSignals()
  311. # -------------------------------------------------------------
  312. # Init plugin host data
  313. Carla.isControl = False
  314. Carla.isLocal = True
  315. Carla.isPlugin = True
  316. # -------------------------------------------------------------
  317. # Create GUI first
  318. Carla.gui = CarlaMiniW()
  319. # -------------------------------------------------------------
  320. # Init plugin host now
  321. Carla.host = PluginHost(Carla.gui.d_getSampleRate())
  322. initHost("Carla-Plugin")
  323. engineCallback(None, ENGINE_CALLBACK_ENGINE_STARTED, 0, ENGINE_PROCESS_MODE_CONTINUOUS_RACK, ENGINE_TRANSPORT_MODE_PLUGIN, 0.0, "Plugin")
  324. # -------------------------------------------------------------
  325. # App-Loop
  326. sys.exit(app.exec_())