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.

807 lines
29KB

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