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.

762 lines
28KB

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # Carla plugin host (plugin UI)
  4. # Copyright (C) 2013-2014 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 (Custom Stuff)
  19. from carla_host import *
  20. from externalui import ExternalUI
  21. # ------------------------------------------------------------------------------------------------------------
  22. # Helper object
  23. class PluginStoreInfo(object):
  24. __slots__ = [
  25. 'pluginInfo',
  26. 'pluginRealName',
  27. 'audioCountInfo',
  28. 'midiCountInfo',
  29. 'parameterCount',
  30. 'parameterCountInfo',
  31. 'parameterInfoS',
  32. 'parameterDataS',
  33. 'parameterRangeS',
  34. 'parameterValueS',
  35. 'programCount',
  36. 'programCurrent',
  37. 'programNameS',
  38. 'midiProgramCount',
  39. 'midiProgramCurrent',
  40. 'midiProgramDataS',
  41. 'peaks'
  42. ]
  43. # ------------------------------------------------------------------------------------------------------------
  44. # Host Plugin object
  45. class PluginHost(object):
  46. def __init__(self, sampleRate):
  47. object.__init__(self)
  48. self.fSupportedFileExts = ""
  49. self.fBufferSize = 0
  50. self.fSampleRate = sampleRate
  51. self.fLastError = ""
  52. self.fIsRunning = True
  53. self.fPluginsInfo = []
  54. def _add(self, pluginId):
  55. if len(self.fPluginsInfo) != pluginId:
  56. return
  57. info = PluginStoreInfo()
  58. info.pluginInfo = PyCarlaPluginInfo
  59. info.pluginRealName = ""
  60. info.audioCountInfo = PyCarlaPortCountInfo
  61. info.midiCountInfo = PyCarlaPortCountInfo
  62. info.parameterCount = 0
  63. info.parameterCountInfo = PyCarlaPortCountInfo
  64. info.parameterInfoS = []
  65. info.parameterDataS = []
  66. info.parameterRangeS = []
  67. info.parameterValueS = []
  68. info.programCount = 0
  69. info.programCurrent = -1
  70. info.programNameS = []
  71. info.midiProgramCount = 0
  72. info.midiProgramCurrent = -1
  73. info.midiProgramDataS = []
  74. info.peaks = [0.0, 0.0, 0.0, 0.0]
  75. self.fPluginsInfo.append(info)
  76. def _set_pluginInfo(self, pluginId, info):
  77. self.fPluginsInfo[pluginId].pluginInfo = info
  78. def _set_pluginName(self, pluginId, name):
  79. self.fPluginsInfo[pluginId].pluginInfo['name'] = name
  80. def _set_pluginRealName(self, pluginId, realName):
  81. self.fPluginsInfo[pluginId].pluginRealName = realName
  82. def _set_audioCountInfo(self, pluginId, info):
  83. self.fPluginsInfo[pluginId].audioCountInfo = info
  84. def _set_midiCountInfo(self, pluginId, info):
  85. self.fPluginsInfo[pluginId].midiCountInfo = info
  86. def _set_parameterCountInfo(self, pluginId, count, info):
  87. self.fPluginsInfo[pluginId].parameterCount = count
  88. self.fPluginsInfo[pluginId].parameterCountInfo = info
  89. # clear
  90. self.fPluginsInfo[pluginId].parameterInfoS = []
  91. self.fPluginsInfo[pluginId].parameterDataS = []
  92. self.fPluginsInfo[pluginId].parameterRangeS = []
  93. self.fPluginsInfo[pluginId].parameterValueS = []
  94. # add placeholders
  95. for x in range(count):
  96. self.fPluginsInfo[pluginId].parameterInfoS.append(PyCarlaParameterInfo)
  97. self.fPluginsInfo[pluginId].parameterDataS.append(PyParameterData)
  98. self.fPluginsInfo[pluginId].parameterRangeS.append(PyParameterRanges)
  99. self.fPluginsInfo[pluginId].parameterValueS.append(0.0)
  100. def _set_programCount(self, pluginId, count):
  101. self.fPluginsInfo[pluginId].programCount = count
  102. # clear
  103. self.fPluginsInfo[pluginId].programNameS = []
  104. # add placeholders
  105. for x in range(count):
  106. self.fPluginsInfo[pluginId].programNameS.append("")
  107. def _set_midiProgramCount(self, pluginId, count):
  108. self.fPluginsInfo[pluginId].midiProgramCount = count
  109. # clear
  110. self.fPluginsInfo[pluginId].midiProgramDataS = []
  111. # add placeholders
  112. for x in range(count):
  113. self.fPluginsInfo[pluginId].midiProgramDataS.append(PyMidiProgramData)
  114. def _set_parameterInfoS(self, pluginId, paramIndex, info):
  115. if pluginId < len(self.fPluginsInfo) and paramIndex < self.fPluginsInfo[pluginId].parameterCount:
  116. self.fPluginsInfo[pluginId].parameterInfoS[paramIndex] = info
  117. def _set_parameterDataS(self, pluginId, paramIndex, data):
  118. if pluginId < len(self.fPluginsInfo) and paramIndex < self.fPluginsInfo[pluginId].parameterCount:
  119. self.fPluginsInfo[pluginId].parameterDataS[paramIndex] = data
  120. def _set_parameterRangeS(self, pluginId, paramIndex, ranges):
  121. if pluginId < len(self.fPluginsInfo) and paramIndex < self.fPluginsInfo[pluginId].parameterCount:
  122. self.fPluginsInfo[pluginId].parameterRangeS[paramIndex] = ranges
  123. def _set_parameterValueS(self, pluginId, paramIndex, value):
  124. if pluginId < len(self.fPluginsInfo) and paramIndex < self.fPluginsInfo[pluginId].parameterCount:
  125. self.fPluginsInfo[pluginId].parameterValueS[paramIndex] = value
  126. def _set_parameterDefault(self, pluginId, paramIndex, value):
  127. if pluginId < len(self.fPluginsInfo) and paramIndex < self.fPluginsInfo[pluginId].parameterCount:
  128. self.fPluginsInfo[pluginId].parameterRangeS[paramIndex]['def'] = value
  129. def _set_parameterMidiChannel(self, pluginId, paramIndex, channel):
  130. if pluginId < len(self.fPluginsInfo) and paramIndex < self.fPluginsInfo[pluginId].parameterCount:
  131. self.fPluginsInfo[pluginId].parameterDataS[paramIndex]['midiChannel'] = channel
  132. def _set_parameterMidiCC(self, pluginId, paramIndex, cc):
  133. if pluginId < len(self.fPluginsInfo) and paramIndex < self.fPluginsInfo[pluginId].parameterCount:
  134. self.fPluginsInfo[pluginId].parameterDataS[paramIndex]['midiCC'] = cc
  135. def _set_currentProgram(self, pluginId, pIndex):
  136. self.fPluginsInfo[pluginId].programCurrent = pIndex
  137. def _set_currentMidiProgram(self, pluginId, mpIndex):
  138. self.fPluginsInfo[pluginId].midiProgramCurrent = mpIndex
  139. def _set_programNameS(self, pluginId, pIndex, name):
  140. if pIndex < self.fPluginsInfo[pluginId].programCount:
  141. self.fPluginsInfo[pluginId].programNameS[pIndex] = name
  142. def _set_midiProgramDataS(self, pluginId, mpIndex, data):
  143. if mpIndex < self.fPluginsInfo[pluginId].midiProgramCount:
  144. self.fPluginsInfo[pluginId].midiProgramDataS[mpIndex] = data
  145. def _set_peaks(self, pluginId, in1, in2, out1, out2):
  146. self.fPluginsInfo[pluginId].peaks = [in1, in2, out1, out2]
  147. # -------------------------------------------------------------------
  148. def get_complete_license_text(self):
  149. return ""
  150. def get_supported_file_extensions(self):
  151. return self.fSupportedFileExts
  152. # -------------------------------------------------------------------
  153. def get_engine_driver_count(self):
  154. return 1
  155. def get_engine_driver_name(self, index):
  156. return "Plugin"
  157. def get_engine_driver_device_names(self, index):
  158. return []
  159. def get_engine_driver_device_info(self, index, name):
  160. return PyEngineDriverDeviceInfo
  161. # -------------------------------------------------------------------
  162. def get_internal_plugin_count(self):
  163. return 0
  164. def get_internal_plugin_info(self, index):
  165. return None
  166. # -------------------------------------------------------------------
  167. def engine_init(self, driverName, clientName):
  168. return True
  169. def engine_close(self):
  170. return True
  171. def engine_idle(self):
  172. if gCarla.gui.idleExternalUI():
  173. return
  174. self.fIsRunning = False
  175. gCarla.gui.d_uiQuit()
  176. def is_engine_running(self):
  177. return self.fIsRunning
  178. def set_engine_about_to_close(self):
  179. pass
  180. def set_engine_callback(self, func):
  181. pass
  182. def set_engine_option(self, option, value, valueStr):
  183. gCarla.gui.send(["set_engine_option", option, value, valueStr])
  184. def set_file_callback(self, func):
  185. pass
  186. # -------------------------------------------------------------------
  187. def set_file_callback(self, func):
  188. pass
  189. def load_file(self, filename):
  190. gCarla.gui.send(["load_file", filename])
  191. return True
  192. def load_project(self, filename):
  193. gCarla.gui.send(["load_project", filename])
  194. return True
  195. def save_project(self, filename):
  196. gCarla.gui.send(["save_project", filename])
  197. return True
  198. # -------------------------------------------------------------------
  199. def patchbay_connect(self, portIdA, portIdB):
  200. gCarla.gui.send(["patchbay_connect", portIdA, portIdB])
  201. return True
  202. def patchbay_disconnect(self, connectionId):
  203. gCarla.gui.send(["patchbay_disconnect", connectionId])
  204. return True
  205. def patchbay_refresh(self):
  206. gCarla.gui.send(["patchbay_refresh"])
  207. return True
  208. # -------------------------------------------------------------------
  209. def transport_play(self):
  210. gCarla.gui.send(["transport_play"])
  211. def transport_pause(self):
  212. gCarla.gui.send(["transport_pause"])
  213. def transport_relocate(self, frame):
  214. gCarla.gui.send(["transport_relocate"])
  215. def get_current_transport_frame(self):
  216. return 0
  217. def get_transport_info(self):
  218. return PyCarlaTransportInfo
  219. # -------------------------------------------------------------------
  220. def add_plugin(self, btype, ptype, filename, name, label, uniqueId, extraPtr):
  221. gCarla.gui.send(["add_plugin", btype, ptype, filename, name, label, uniqueId])
  222. return True
  223. def remove_plugin(self, pluginId):
  224. gCarla.gui.send(["remove_plugin", pluginId])
  225. return True
  226. def remove_all_plugins(self):
  227. gCarla.gui.send(["remove_all_plugins"])
  228. return True
  229. def rename_plugin(self, pluginId, newName):
  230. gCarla.gui.send(["rename_plugin", pluginId, newName])
  231. return newName
  232. def clone_plugin(self, pluginId):
  233. gCarla.gui.send(["clone_plugin", pluginId])
  234. return True
  235. def replace_plugin(self, pluginId):
  236. gCarla.gui.send(["replace_plugin", pluginId])
  237. return True
  238. def switch_plugins(self, pluginIdA, pluginIdB):
  239. gCarla.gui.send(["switch_plugins", pluginIdA, pluginIdB])
  240. return True
  241. # -------------------------------------------------------------------
  242. def load_plugin_state(self, pluginId, filename):
  243. gCarla.gui.send(["load_plugin_state", pluginId, filename])
  244. return True
  245. def save_plugin_state(self, pluginId, filename):
  246. gCarla.gui.send(["save_plugin_state", pluginId, filename])
  247. return True
  248. # -------------------------------------------------------------------
  249. def get_plugin_info(self, pluginId):
  250. return self.fPluginsInfo[pluginId].pluginInfo
  251. def get_audio_port_count_info(self, pluginId):
  252. return self.fPluginsInfo[pluginId].audioCountInfo
  253. def get_midi_port_count_info(self, pluginId):
  254. return self.fPluginsInfo[pluginId].midiCountInfo
  255. def get_parameter_count_info(self, pluginId):
  256. return self.fPluginsInfo[pluginId].parameterCountInfo
  257. def get_parameter_info(self, pluginId, parameterId):
  258. return self.fPluginsInfo[pluginId].parameterInfoS[parameterId]
  259. def get_parameter_scalepoint_info(self, pluginId, parameterId, scalePointId):
  260. return PyCarlaScalePointInfo
  261. # -------------------------------------------------------------------
  262. def get_parameter_data(self, pluginId, parameterId):
  263. return self.fPluginsInfo[pluginId].parameterDataS[parameterId]
  264. def get_parameter_ranges(self, pluginId, parameterId):
  265. return self.fPluginsInfo[pluginId].parameterRangeS[parameterId]
  266. def get_midi_program_data(self, pluginId, midiProgramId):
  267. return self.fPluginsInfo[pluginId].midiProgramDataS[midiProgramId]
  268. def get_custom_data(self, pluginId, customDataId):
  269. return PyCustomData
  270. def get_chunk_data(self, pluginId):
  271. return ""
  272. # -------------------------------------------------------------------
  273. def get_parameter_count(self, pluginId):
  274. return self.fPluginsInfo[pluginId].parameterCount
  275. def get_program_count(self, pluginId):
  276. return self.fPluginsInfo[pluginId].programCount
  277. def get_midi_program_count(self, pluginId):
  278. return self.fPluginsInfo[pluginId].midiProgramCount
  279. def get_custom_data_count(self, pluginId):
  280. return 0
  281. # -------------------------------------------------------------------
  282. def get_parameter_text(self, pluginId, parameterId, value):
  283. return ""
  284. def get_program_name(self, pluginId, programId):
  285. return self.fPluginsInfo[pluginId].programNameS[programId]
  286. def get_midi_program_name(self, pluginId, midiProgramId):
  287. return self.fPluginsInfo[pluginId].midiProgramDataS[midiProgramId]['label']
  288. def get_real_plugin_name(self, pluginId):
  289. return self.fPluginsInfo[pluginId].pluginRealName
  290. # -------------------------------------------------------------------
  291. def get_current_program_index(self, pluginId):
  292. return self.fPluginsInfo[pluginId].programCurrent
  293. def get_current_midi_program_index(self, pluginId):
  294. return self.fPluginsInfo[pluginId].midiProgramCurrent
  295. def get_default_parameter_value(self, pluginId, parameterId):
  296. return self.fPluginsInfo[pluginId].parameterRangeS[parameterId]['def']
  297. def get_current_parameter_value(self, pluginId, parameterId):
  298. return self.fPluginsInfo[pluginId].parameterValueS[parameterId]
  299. def get_input_peak_value(self, pluginId, isLeft):
  300. return self.fPluginsInfo[pluginId].peaks[0 if isLeft else 1]
  301. def get_output_peak_value(self, pluginId, isLeft):
  302. return self.fPluginsInfo[pluginId].peaks[2 if isLeft else 3]
  303. # -------------------------------------------------------------------
  304. def set_option(self, pluginId, option, yesNo):
  305. gCarla.gui.send(["set_option", pluginId, option, yesNo])
  306. def set_active(self, pluginId, onOff):
  307. gCarla.gui.send(["set_active", pluginId, onOff])
  308. def set_drywet(self, pluginId, value):
  309. gCarla.gui.send(["set_drywet", pluginId, value])
  310. def set_volume(self, pluginId, value):
  311. gCarla.gui.send(["set_volume", pluginId, value])
  312. def set_balance_left(self, pluginId, value):
  313. gCarla.gui.send(["set_balance_left", pluginId, value])
  314. def set_balance_right(self, pluginId, value):
  315. gCarla.gui.send(["set_balance_right", pluginId, value])
  316. def set_panning(self, pluginId, value):
  317. gCarla.gui.send(["set_panning", pluginId, value])
  318. def set_ctrl_channel(self, pluginId, channel):
  319. gCarla.gui.send(["set_ctrl_channel", pluginId, channel])
  320. # -------------------------------------------------------------------
  321. def set_parameter_value(self, pluginId, parameterId, value):
  322. gCarla.gui.send(["set_parameter_value", pluginId, parameterId, value])
  323. def set_parameter_midi_channel(self, pluginId, parameterId, channel):
  324. gCarla.gui.send(["set_parameter_midi_channel", pluginId, parameterId, channel])
  325. def set_parameter_midi_cc(self, pluginId, parameterId, cc):
  326. gCarla.gui.send(["set_parameter_midi_cc", pluginId, parameterId, cc])
  327. def set_program(self, pluginId, programId):
  328. gCarla.gui.send(["set_program", pluginId, programId])
  329. def set_midi_program(self, pluginId, midiProgramId):
  330. gCarla.gui.send(["set_midi_program", pluginId, midiProgramId])
  331. def set_custom_data(self, pluginId, type_, key, value):
  332. gCarla.gui.send(["set_custom_data", pluginId, type_, key, value])
  333. def set_chunk_data(self, pluginId, chunkData):
  334. gCarla.gui.send(["set_chunk_data", pluginId, chunkData])
  335. # -------------------------------------------------------------------
  336. def prepare_for_save(self, pluginId):
  337. gCarla.gui.send(["prepare_for_save", pluginId])
  338. def send_midi_note(self, pluginId, channel, note, velocity):
  339. gCarla.gui.send(["send_midi_note", pluginId, channel, note, velocity])
  340. def show_custom_ui(self, pluginId, yesNo):
  341. gCarla.gui.send(["show_custom_ui", pluginId, yesNo])
  342. # -------------------------------------------------------------------
  343. def get_buffer_size(self):
  344. return self.fBufferSize
  345. def get_sample_rate(self):
  346. return self.fSampleRate
  347. def get_last_error(self):
  348. return self.fLastError
  349. def get_host_osc_url_tcp(self):
  350. return ""
  351. def get_host_osc_url_udp(self):
  352. return ""
  353. # ------------------------------------------------------------------------------------------------------------
  354. # Main Window
  355. class CarlaMiniW(HostWindow, ExternalUI):
  356. def __init__(self):
  357. HostWindow.__init__(self, None)
  358. ExternalUI.__init__(self)
  359. if False:
  360. from carla_patchbay import CarlaPatchbayW
  361. self.fContainer = CarlaPatchbayW(self)
  362. else:
  363. from carla_rack import CarlaRackW
  364. self.fContainer = CarlaRackW(self)
  365. self.setupContainer(False)
  366. self.setWindowTitle(self.fUiName)
  367. self.showUiIfTesting()
  368. # -------------------------------------------------------------------
  369. # ExternalUI Callbacks
  370. def d_uiShow(self):
  371. self.show()
  372. def d_uiHide(self):
  373. self.hide()
  374. def d_uiQuit(self):
  375. self.close()
  376. app.quit()
  377. def d_uiTitleChanged(self, uiTitle):
  378. self.setWindowTitle(uiTitle)
  379. # -------------------------------------------------------------------
  380. # Qt events
  381. def closeEvent(self, event):
  382. self.closeExternalUI()
  383. HostWindow.closeEvent(self, event)
  384. # -------------------------------------------------------------------
  385. # Custom idler
  386. def idleExternalUI(self):
  387. while True:
  388. if self.fPipeRecv is None:
  389. return True
  390. try:
  391. msg = self.fPipeRecv.readline().strip()
  392. except IOError:
  393. return False
  394. if not msg:
  395. return True
  396. elif msg.startswith("PEAKS_"):
  397. pluginId = int(msg.replace("PEAKS_", ""))
  398. in1, in2, out1, out2 = [float(i) for i in self.fPipeRecv.readline().strip().split(":")]
  399. gCarla.host._set_peaks(pluginId, in1, in2, out1, out2)
  400. elif msg.startswith("PARAMVAL_"):
  401. pluginId, paramId = [int(i) for i in msg.replace("PARAMVAL_", "").split(":")]
  402. paramValue = float(self.fPipeRecv.readline().strip())
  403. gCarla.host._set_parameterValueS(pluginId, paramId, paramValue)
  404. elif msg.startswith("ENGINE_CALLBACK_"):
  405. action = int(msg.replace("ENGINE_CALLBACK_", ""))
  406. pluginId = int(self.fPipeRecv.readline().strip())
  407. value1 = int(self.fPipeRecv.readline().strip())
  408. value2 = int(self.fPipeRecv.readline().strip())
  409. value3 = float(self.fPipeRecv.readline().strip())
  410. valueStr = self.fPipeRecv.readline().strip().replace("\r", "\n")
  411. if action == ENGINE_CALLBACK_PLUGIN_RENAMED:
  412. gCarla.host._set_pluginName(pluginId, valueStr)
  413. elif action == ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED:
  414. gCarla.host._set_parameterValueS(pluginId, value1, value3)
  415. elif action == ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED:
  416. gCarla.host._set_parameterDefault(pluginId, value1, value3)
  417. elif action == ENGINE_CALLBACK_PARAMETER_MIDI_CC_CHANGED:
  418. gCarla.host._set_parameterMidiCC(pluginId, value1, value2)
  419. elif action == ENGINE_CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED:
  420. gCarla.host._set_parameterMidiChannel(pluginId, value1, value2)
  421. elif action == ENGINE_CALLBACK_PROGRAM_CHANGED:
  422. gCarla.host._set_currentProgram(pluginId, value1)
  423. elif action == ENGINE_CALLBACK_MIDI_PROGRAM_CHANGED:
  424. gCarla.host._set_currentMidiProgram(pluginId, value1)
  425. engineCallback(None, action, pluginId, value1, value2, value3, valueStr)
  426. elif msg.startswith("PLUGIN_INFO_"):
  427. pluginId = int(msg.replace("PLUGIN_INFO_", ""))
  428. gCarla.host._add(pluginId)
  429. type_, category, hints, uniqueId, optsAvail, optsEnabled = [int(i) for i in self.fPipeRecv.readline().strip().split(":")]
  430. filename = self.fPipeRecv.readline().strip().replace("\r", "\n")
  431. name = self.fPipeRecv.readline().strip().replace("\r", "\n")
  432. iconName = self.fPipeRecv.readline().strip().replace("\r", "\n")
  433. realName = self.fPipeRecv.readline().strip().replace("\r", "\n")
  434. label = self.fPipeRecv.readline().strip().replace("\r", "\n")
  435. maker = self.fPipeRecv.readline().strip().replace("\r", "\n")
  436. copyright = self.fPipeRecv.readline().strip().replace("\r", "\n")
  437. pinfo = {
  438. 'type': type_,
  439. 'category': category,
  440. 'hints': hints,
  441. 'optionsAvailable': optsAvail,
  442. 'optionsEnabled': optsEnabled,
  443. 'filename': filename,
  444. 'name': name,
  445. 'label': label,
  446. 'maker': maker,
  447. 'copyright': copyright,
  448. 'iconName': iconName,
  449. 'patchbayClientId': 0,
  450. 'uniqueId': uniqueId
  451. }
  452. gCarla.host._set_pluginInfo(pluginId, pinfo)
  453. gCarla.host._set_pluginRealName(pluginId, realName)
  454. elif msg.startswith("AUDIO_COUNT_"):
  455. pluginId, ins, outs = [int(i) for i in msg.replace("AUDIO_COUNT_", "").split(":")]
  456. gCarla.host._set_audioCountInfo(pluginId, {'ins': ins, 'outs': outs})
  457. elif msg.startswith("MIDI_COUNT_"):
  458. pluginId, ins, outs = [int(i) for i in msg.replace("MIDI_COUNT_", "").split(":")]
  459. gCarla.host._set_midiCountInfo(pluginId, {'ins': ins, 'outs': outs})
  460. elif msg.startswith("PARAMETER_COUNT_"):
  461. pluginId, ins, outs, count = [int(i) for i in msg.replace("PARAMETER_COUNT_", "").split(":")]
  462. gCarla.host._set_parameterCountInfo(pluginId, count, {'ins': ins, 'outs': outs})
  463. elif msg.startswith("PARAMETER_DATA_"):
  464. pluginId, paramId = [int(i) for i in msg.replace("PARAMETER_DATA_", "").split(":")]
  465. paramType, paramHints, midiChannel, midiCC = [int(i) for i in self.fPipeRecv.readline().strip().split(":")]
  466. paramName = self.fPipeRecv.readline().strip().replace("\r", "\n")
  467. paramUnit = self.fPipeRecv.readline().strip().replace("\r", "\n")
  468. paramInfo = {
  469. 'name': paramName,
  470. 'symbol': "",
  471. 'unit': paramUnit,
  472. 'scalePointCount': 0,
  473. }
  474. gCarla.host._set_parameterInfoS(pluginId, paramId, paramInfo)
  475. paramData = {
  476. 'type': paramType,
  477. 'hints': paramHints,
  478. 'index': paramId,
  479. 'rindex': -1,
  480. 'midiCC': midiCC,
  481. 'midiChannel': midiChannel
  482. }
  483. gCarla.host._set_parameterDataS(pluginId, paramId, paramData)
  484. elif msg.startswith("PARAMETER_RANGES_"):
  485. pluginId, paramId = [int(i) for i in msg.replace("PARAMETER_RANGES_", "").split(":")]
  486. def_, min_, max_, step, stepSmall, stepLarge = [float(i) for i in self.fPipeRecv.readline().strip().split(":")]
  487. paramRanges = {
  488. 'def': def_,
  489. 'min': min_,
  490. 'max': max_,
  491. 'step': step,
  492. 'stepSmall': stepSmall,
  493. 'stepLarge': stepLarge
  494. }
  495. gCarla.host._set_parameterRangeS(pluginId, paramId, paramRanges)
  496. elif msg.startswith("PROGRAM_COUNT_"):
  497. pluginId, count, current = [int(i) for i in msg.replace("PROGRAM_COUNT_", "").split(":")]
  498. gCarla.host._set_programCount(pluginId, count)
  499. gCarla.host._set_currentProgram(pluginId, current)
  500. elif msg.startswith("PROGRAM_NAME_"):
  501. pluginId, progId = [int(i) for i in msg.replace("PROGRAM_NAME_", "").split(":")]
  502. progName = self.fPipeRecv.readline().strip().replace("\r", "\n")
  503. gCarla.host._set_programNameS(pluginId, progId, progName)
  504. elif msg.startswith("MIDI_PROGRAM_COUNT_"):
  505. pluginId, count, current = [int(i) for i in msg.replace("MIDI_PROGRAM_COUNT_", "").split(":")]
  506. gCarla.host._set_midiProgramCount(pluginId, count)
  507. gCarla.host._set_currentMidiProgram(pluginId, current)
  508. elif msg.startswith("MIDI_PROGRAM_DATA_"):
  509. pluginId, midiProgId = [int(i) for i in msg.replace("MIDI_PROGRAM_DATA_", "").split(":")]
  510. bank, program = [int(i) for i in self.fPipeRecv.readline().strip().split(":")]
  511. name = self.fPipeRecv.readline().strip().replace("\r", "\n")
  512. gCarla.host._set_midiProgramDataS(pluginId, midiProgId, {'bank': bank, 'program': program, 'name': name})
  513. elif msg == "error":
  514. error = self.fPipeRecv.readline().strip().replace("\r", "\n")
  515. engineCallback(None, ENGINE_CALLBACK_ERROR, 0, 0, 0, 0.0, error)
  516. elif msg == "show":
  517. self.d_uiShow()
  518. elif msg == "hide":
  519. self.d_uiHide()
  520. elif msg == "quit":
  521. self.fQuitReceived = True
  522. self.d_uiQuit()
  523. elif msg == "uiTitle":
  524. uiTitle = self.fPipeRecv.readline().strip().replace("\r", "\n")
  525. self.d_uiTitleChanged(uiTitle)
  526. else:
  527. print("unknown message: \"" + msg + "\"")
  528. return True
  529. # ------------------------------------------------------------------------------------------------------------
  530. # Main
  531. if __name__ == '__main__':
  532. # -------------------------------------------------------------
  533. # App initialization
  534. app = CarlaApplication("Carla2-Plugin")
  535. # -------------------------------------------------------------
  536. # Set-up custom signal handling
  537. setUpSignals()
  538. # -------------------------------------------------------------
  539. # Init plugin host data
  540. gCarla.isControl = False
  541. gCarla.isLocal = True
  542. gCarla.isPlugin = True
  543. # -------------------------------------------------------------
  544. # Create GUI first
  545. gCarla.gui = CarlaMiniW()
  546. # -------------------------------------------------------------
  547. # Init plugin host now
  548. gCarla.host = PluginHost(gCarla.gui.d_getSampleRate())
  549. initHost("Carla-Plugin")
  550. # set our gui as parent for all plugins UIs
  551. gCarla.host.set_engine_option(ENGINE_OPTION_FRONTEND_WIN_ID, 0, str(gCarla.gui.winId()))
  552. # simulate an engire started callback
  553. engineCallback(None, ENGINE_CALLBACK_ENGINE_STARTED, 0, ENGINE_PROCESS_MODE_CONTINUOUS_RACK, ENGINE_TRANSPORT_MODE_PLUGIN, 0.0, "Plugin")
  554. # -------------------------------------------------------------
  555. # App-Loop
  556. ret = app.exec_()
  557. # disable parenting
  558. gCarla.host.set_engine_option(ENGINE_OPTION_FRONTEND_WIN_ID, 0, "0")
  559. sys.exit(ret)