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.

carla-plugin 23KB

7 years ago
10 years ago
9 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # Carla plugin host (plugin UI)
  4. # Copyright (C) 2013-2016 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 (Config)
  19. from carla_config import *
  20. # ------------------------------------------------------------------------------------------------------------
  21. # Imports (Global)
  22. if config_UseQt5:
  23. from PyQt5.QtGui import QKeySequence
  24. from PyQt5.QtWidgets import QHBoxLayout
  25. else:
  26. from PyQt4.QtGui import QHBoxLayout, QKeySequence
  27. # ------------------------------------------------------------------------------------------------------------
  28. # Imports (Custom Stuff)
  29. from carla_host import *
  30. from externalui import ExternalUI
  31. # ------------------------------------------------------------------------------------------------------------
  32. # Host Plugin object
  33. class PluginHost(CarlaHostQtPlugin):
  34. def __init__(self):
  35. CarlaHostQtPlugin.__init__(self)
  36. if False:
  37. # kdevelop likes this :)
  38. self.fExternalUI = ExternalUI()
  39. # ---------------------------------------------------------------
  40. self.fExternalUI = None
  41. # -------------------------------------------------------------------
  42. def setExternalUI(self, extUI):
  43. self.fExternalUI = extUI
  44. def sendMsg(self, lines):
  45. if self.fExternalUI is None:
  46. return False
  47. return self.fExternalUI.send(lines)
  48. # -------------------------------------------------------------------
  49. def engine_init(self, driverName, clientName):
  50. return True
  51. def engine_close(self):
  52. return True
  53. def engine_idle(self):
  54. self.fExternalUI.idleExternalUI()
  55. def is_engine_running(self):
  56. return self.fExternalUI.isRunning()
  57. def set_engine_about_to_close(self):
  58. return True
  59. # ------------------------------------------------------------------------------------------------------------
  60. # Main Window
  61. class CarlaMiniW(ExternalUI, HostWindow):
  62. def __init__(self, host, parent=None):
  63. ExternalUI.__init__(self)
  64. HostWindow.__init__(self, host, sys.argv[0].lower().endswith("/carla-plugin-patchbay"), parent)
  65. self.host = host
  66. if False:
  67. # kdevelop likes this :)
  68. host = PluginHost()
  69. self.host = host
  70. host.setExternalUI(self)
  71. self.fFirstInit = True
  72. self.setWindowTitle(self.fUiName)
  73. self.ready()
  74. # Override this as it can be called from several places.
  75. # We really need to close all UIs as events are driven by host idle which is only available when UI is visible
  76. def closeExternalUI(self):
  77. for i in reversed(range(self.fPluginCount)):
  78. self.host.show_custom_ui(i, False)
  79. ExternalUI.closeExternalUI(self)
  80. # -------------------------------------------------------------------
  81. # ExternalUI Callbacks
  82. def uiShow(self):
  83. if self.parent() is not None:
  84. return
  85. self.show()
  86. def uiFocus(self):
  87. if self.parent() is not None:
  88. return
  89. self.setWindowState((self.windowState() & ~Qt.WindowMinimized) | Qt.WindowActive)
  90. self.show()
  91. self.raise_()
  92. self.activateWindow()
  93. def uiHide(self):
  94. if self.parent() is not None:
  95. return
  96. self.hide()
  97. def uiQuit(self):
  98. self.closeExternalUI()
  99. self.close()
  100. if self != gui:
  101. gui.close()
  102. # there might be other qt windows open which will block carla-plugin from quitting
  103. app.quit()
  104. def uiTitleChanged(self, uiTitle):
  105. self.setWindowTitle(uiTitle)
  106. # -------------------------------------------------------------------
  107. # Qt events
  108. def closeEvent(self, event):
  109. self.closeExternalUI()
  110. HostWindow.closeEvent(self, event)
  111. # there might be other qt windows open which will block carla-plugin from quitting
  112. app.quit()
  113. # -------------------------------------------------------------------
  114. # Custom callback
  115. def msgCallback(self, msg):
  116. try:
  117. self.msgCallback2(msg)
  118. except:
  119. print("msgCallback error, skipped for", msg)
  120. def msgCallback2(self, msg):
  121. msg = charPtrToString(msg)
  122. #if not msg:
  123. #return
  124. if msg.startswith("PEAKS_"):
  125. pluginId = int(msg.replace("PEAKS_", ""))
  126. in1, in2, out1, out2 = [float(i) for i in self.readlineblock().split(":")]
  127. self.host._set_peaks(pluginId, in1, in2, out1, out2)
  128. elif msg.startswith("PARAMVAL_"):
  129. pluginId, paramId = [int(i) for i in msg.replace("PARAMVAL_", "").split(":")]
  130. paramValue = float(self.readlineblock())
  131. if paramId < 0:
  132. self.host._set_internalValue(pluginId, paramId, paramValue)
  133. else:
  134. self.host._set_parameterValue(pluginId, paramId, paramValue)
  135. elif msg.startswith("ENGINE_CALLBACK_"):
  136. action = int(msg.replace("ENGINE_CALLBACK_", ""))
  137. pluginId = int(self.readlineblock())
  138. value1 = int(self.readlineblock())
  139. value2 = int(self.readlineblock())
  140. value3 = float(self.readlineblock())
  141. valueStr = self.readlineblock().replace("\r", "\n")
  142. if action == ENGINE_CALLBACK_PLUGIN_RENAMED:
  143. self.host._set_pluginName(pluginId, valueStr)
  144. elif action == ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED:
  145. if value1 < 0:
  146. self.host._set_internalValue(pluginId, value1, value3)
  147. else:
  148. self.host._set_parameterValue(pluginId, value1, value3)
  149. elif action == ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED:
  150. self.host._set_parameterDefault(pluginId, value1, value3)
  151. elif action == ENGINE_CALLBACK_PARAMETER_MIDI_CC_CHANGED:
  152. self.host._set_parameterMidiCC(pluginId, value1, value2)
  153. elif action == ENGINE_CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED:
  154. self.host._set_parameterMidiChannel(pluginId, value1, value2)
  155. elif action == ENGINE_CALLBACK_PROGRAM_CHANGED:
  156. self.host._set_currentProgram(pluginId, value1)
  157. elif action == ENGINE_CALLBACK_MIDI_PROGRAM_CHANGED:
  158. self.host._set_currentMidiProgram(pluginId, value1)
  159. engineCallback(self.host, action, pluginId, value1, value2, value3, valueStr)
  160. elif msg.startswith("ENGINE_OPTION_"):
  161. option = int(msg.replace("ENGINE_OPTION_", ""))
  162. forced = bool(self.readlineblock() == "true")
  163. value = self.readlineblock()
  164. if self.fFirstInit and not forced:
  165. return
  166. if option == ENGINE_OPTION_PROCESS_MODE:
  167. self.host.processMode = int(value)
  168. elif option == ENGINE_OPTION_TRANSPORT_MODE:
  169. self.host.transportMode = int(value)
  170. elif option == ENGINE_OPTION_FORCE_STEREO:
  171. self.host.forceStereo = bool(value == "true")
  172. elif option == ENGINE_OPTION_PREFER_PLUGIN_BRIDGES:
  173. self.host.preferPluginBridges = bool(value == "true")
  174. elif option == ENGINE_OPTION_PREFER_UI_BRIDGES:
  175. self.host.preferUIBridges = bool(value == "true")
  176. elif option == ENGINE_OPTION_UIS_ALWAYS_ON_TOP:
  177. self.host.uisAlwaysOnTop = bool(value == "true")
  178. elif option == ENGINE_OPTION_MAX_PARAMETERS:
  179. self.host.maxParameters = int(value)
  180. elif option == ENGINE_OPTION_UI_BRIDGES_TIMEOUT:
  181. self.host.uiBridgesTimeout = int(value)
  182. elif option == ENGINE_OPTION_PATH_BINARIES:
  183. self.host.pathBinaries = value
  184. elif option == ENGINE_OPTION_PATH_RESOURCES:
  185. self.host.pathResources = value
  186. elif msg.startswith("PLUGIN_INFO_"):
  187. pluginId = int(msg.replace("PLUGIN_INFO_", ""))
  188. self.host._add(pluginId)
  189. type_, category, hints, uniqueId, optsAvail, optsEnabled = [int(i) for i in self.readlineblock().split(":")]
  190. filename = self.readlineblock().replace("\r", "\n")
  191. name = self.readlineblock().replace("\r", "\n")
  192. iconName = self.readlineblock().replace("\r", "\n")
  193. realName = self.readlineblock().replace("\r", "\n")
  194. label = self.readlineblock().replace("\r", "\n")
  195. maker = self.readlineblock().replace("\r", "\n")
  196. copyright = self.readlineblock().replace("\r", "\n")
  197. pinfo = {
  198. 'type': type_,
  199. 'category': category,
  200. 'hints': hints,
  201. 'optionsAvailable': optsAvail,
  202. 'optionsEnabled': optsEnabled,
  203. 'filename': filename,
  204. 'name': name,
  205. 'label': label,
  206. 'maker': maker,
  207. 'copyright': copyright,
  208. 'iconName': iconName,
  209. 'patchbayClientId': 0,
  210. 'uniqueId': uniqueId
  211. }
  212. self.host._set_pluginInfo(pluginId, pinfo)
  213. self.host._set_pluginRealName(pluginId, realName)
  214. elif msg.startswith("AUDIO_COUNT_"):
  215. pluginId, ins, outs = [int(i) for i in msg.replace("AUDIO_COUNT_", "").split(":")]
  216. self.host._set_audioCountInfo(pluginId, {'ins': ins, 'outs': outs})
  217. elif msg.startswith("MIDI_COUNT_"):
  218. pluginId, ins, outs = [int(i) for i in msg.replace("MIDI_COUNT_", "").split(":")]
  219. self.host._set_midiCountInfo(pluginId, {'ins': ins, 'outs': outs})
  220. elif msg.startswith("PARAMETER_COUNT_"):
  221. pluginId, ins, outs, count = [int(i) for i in msg.replace("PARAMETER_COUNT_", "").split(":")]
  222. self.host._set_parameterCountInfo(pluginId, count, {'ins': ins, 'outs': outs})
  223. elif msg.startswith("PARAMETER_DATA_"):
  224. pluginId, paramId = [int(i) for i in msg.replace("PARAMETER_DATA_", "").split(":")]
  225. paramType, paramHints, midiChannel, midiCC = [int(i) for i in self.readlineblock().split(":")]
  226. paramName = self.readlineblock().replace("\r", "\n")
  227. paramUnit = self.readlineblock().replace("\r", "\n")
  228. paramInfo = {
  229. 'name': paramName,
  230. 'symbol': "",
  231. 'unit': paramUnit,
  232. 'scalePointCount': 0,
  233. }
  234. self.host._set_parameterInfo(pluginId, paramId, paramInfo)
  235. paramData = {
  236. 'type': paramType,
  237. 'hints': paramHints,
  238. 'index': paramId,
  239. 'rindex': -1,
  240. 'midiCC': midiCC,
  241. 'midiChannel': midiChannel
  242. }
  243. self.host._set_parameterData(pluginId, paramId, paramData)
  244. elif msg.startswith("PARAMETER_RANGES_"):
  245. pluginId, paramId = [int(i) for i in msg.replace("PARAMETER_RANGES_", "").split(":")]
  246. def_, min_, max_, step, stepSmall, stepLarge = [float(i) for i in self.readlineblock().split(":")]
  247. paramRanges = {
  248. 'def': def_,
  249. 'min': min_,
  250. 'max': max_,
  251. 'step': step,
  252. 'stepSmall': stepSmall,
  253. 'stepLarge': stepLarge
  254. }
  255. self.host._set_parameterRanges(pluginId, paramId, paramRanges)
  256. elif msg.startswith("PROGRAM_COUNT_"):
  257. pluginId, count, current = [int(i) for i in msg.replace("PROGRAM_COUNT_", "").split(":")]
  258. self.host._set_programCount(pluginId, count)
  259. self.host._set_currentProgram(pluginId, current)
  260. elif msg.startswith("PROGRAM_NAME_"):
  261. pluginId, progId = [int(i) for i in msg.replace("PROGRAM_NAME_", "").split(":")]
  262. progName = self.readlineblock().replace("\r", "\n")
  263. self.host._set_programName(pluginId, progId, progName)
  264. elif msg.startswith("MIDI_PROGRAM_COUNT_"):
  265. pluginId, count, current = [int(i) for i in msg.replace("MIDI_PROGRAM_COUNT_", "").split(":")]
  266. self.host._set_midiProgramCount(pluginId, count)
  267. self.host._set_currentMidiProgram(pluginId, current)
  268. elif msg.startswith("MIDI_PROGRAM_DATA_"):
  269. pluginId, midiProgId = [int(i) for i in msg.replace("MIDI_PROGRAM_DATA_", "").split(":")]
  270. bank, program = [int(i) for i in self.readlineblock().split(":")]
  271. name = self.readlineblock().replace("\r", "\n")
  272. self.host._set_midiProgramData(pluginId, midiProgId, {'bank': bank, 'program': program, 'name': name})
  273. elif msg.startswith("CUSTOM_DATA_COUNT_"):
  274. pluginId, count = [int(i) for i in msg.replace("CUSTOM_DATA_COUNT_", "").split(":")]
  275. self.host._set_customDataCount(pluginId, count)
  276. elif msg.startswith("CUSTOM_DATA_"):
  277. pluginId, customDataId = [int(i) for i in msg.replace("CUSTOM_DATA_", "").split(":")]
  278. type_ = self.readlineblock().replace("\r", "\n")
  279. key = self.readlineblock().replace("\r", "\n")
  280. value = self.readlineblock().replace("\r", "\n")
  281. self.host._set_customData(pluginId, customDataId, {'type': type_, 'key': key, 'value': value})
  282. elif msg == "osc-urls":
  283. tcp = self.readlineblock().replace("\r", "\n")
  284. udp = self.readlineblock().replace("\r", "\n")
  285. self.host.fOscTCP = tcp
  286. self.host.fOscUDP = udp
  287. elif msg == "max-plugin-number":
  288. maxnum = int(self.readlineblock())
  289. self.host.fMaxPluginNumber = maxnum
  290. elif msg == "buffer-size":
  291. bufsize = int(self.readlineblock())
  292. self.host.fBufferSize = bufsize
  293. elif msg == "sample-rate":
  294. srate = float(self.readlineblock())
  295. self.host.fSampleRate = srate
  296. elif msg == "transport":
  297. playing = bool(self.readlineblock() == "true")
  298. frame, bar, beat, tick = [int(i) for i in self.readlineblock().split(":")]
  299. bpm = float(self.readlineblock())
  300. self.host._set_transport(playing, frame, bar, beat, tick, bpm)
  301. elif msg == "error":
  302. error = self.readlineblock().replace("\r", "\n")
  303. engineCallback(self.host, ENGINE_CALLBACK_ERROR, 0, 0, 0, 0.0, error)
  304. elif msg == "show":
  305. self.fFirstInit = False
  306. self.uiShow()
  307. elif msg == "focus":
  308. self.uiFocus()
  309. elif msg == "hide":
  310. self.uiHide()
  311. elif msg == "quit":
  312. self.fQuitReceived = True
  313. self.uiQuit()
  314. elif msg == "uiTitle":
  315. uiTitle = self.readlineblock().replace("\r", "\n")
  316. self.uiTitleChanged(uiTitle)
  317. else:
  318. print("unknown message: \"" + msg + "\"")
  319. # ------------------------------------------------------------------------------------------------------------
  320. # Embed Widget
  321. if config_UseQt5 and LINUX:
  322. from PyQt5.QtGui import QMouseEvent
  323. class QEmbedWidget(QWidget):
  324. def __init__(self, winId):
  325. QWidget.__init__(self)
  326. self.setAttribute(Qt.WA_LayoutUsesWidgetRect)
  327. self.move(0, 0)
  328. self.fPos = (0, 0)
  329. self.fWinId = 0
  330. def getWidget(self):
  331. return self
  332. def finalSetup(self, gui, winId):
  333. self.fWinId = int(self.winId())
  334. gui.ui.centralwidget.installEventFilter(self)
  335. gui.ui.menubar.installEventFilter(self)
  336. gCarla.utils.x11_reparent_window(self.fWinId, winId)
  337. self.show()
  338. def fixPosition(self):
  339. pos = gCarla.utils.x11_get_window_pos(self.fWinId)
  340. if self.fPos == pos:
  341. return
  342. self.fPos = pos
  343. self.move(pos[0], pos[1])
  344. gCarla.utils.x11_move_window(self.fWinId, 0, 0)
  345. def eventFilter(self, obj, ev):
  346. if isinstance(ev, QMouseEvent):
  347. self.fixPosition()
  348. return False
  349. def enterEvent(self, ev):
  350. self.fixPosition()
  351. QWidget.enterEvent(self, ev)
  352. elif config_UseQt5 and not LINUX:
  353. from PyQt5.QtGui import QWindow
  354. class QEmbedWidget(object):
  355. def __init__(self, winId):
  356. self.fWindow = QWindow.fromWinId(winId)
  357. self.fWidget = QWidget.createWindowContainer(self.fWindow)
  358. self.fWidget.setAttribute(Qt.WA_LayoutUsesWidgetRect)
  359. # TODO: show/hide/close events
  360. def getWidget(self):
  361. return self.fWidget
  362. def finalSetup(self, gui, winId):
  363. self.fWidget.show()
  364. elif not config_UseQt5 and LINUX:
  365. from PyQt4.QtGui import QX11EmbedWidget
  366. class QEmbedWidget(QX11EmbedWidget):
  367. def __init__(self, winId):
  368. QX11EmbedWidget.__init__(self)
  369. def getWidget(self):
  370. return self
  371. def finalSetup(self, gui, winId):
  372. self.embedInto(winId)
  373. self.show()
  374. else:
  375. class QEmbedWidget(object):
  376. def __init__(self, winId):
  377. print("Cannot use embed UI with this configuration")
  378. raise Exception
  379. # ------------------------------------------------------------------------------------------------------------
  380. # Embed plugin UI
  381. class CarlaEmbedW(QEmbedWidget):
  382. def __init__(self, host, winId):
  383. QEmbedWidget.__init__(self, winId)
  384. self.host = host
  385. self.fWinId = winId
  386. self.fWidget = self.getWidget()
  387. self.fWidget.setFixedSize(740, 512)
  388. self.fLayout = QVBoxLayout(self.fWidget)
  389. self.fLayout.setContentsMargins(0, 0, 0, 0)
  390. self.fLayout.setSpacing(0)
  391. self.fWidget.setLayout(self.fLayout)
  392. self.gui = CarlaMiniW(host, self.fWidget)
  393. self.gui.hide()
  394. self.gui.ui.act_file_quit.setEnabled(False)
  395. self.gui.ui.act_file_quit.setVisible(False)
  396. self.fShortcutActions = []
  397. self.addShortcutActions(self.gui.ui.menu_File.actions())
  398. self.addShortcutActions(self.gui.ui.menu_Plugin.actions())
  399. self.addShortcutActions(self.gui.ui.menu_PluginMacros.actions())
  400. self.addShortcutActions(self.gui.ui.menu_Settings.actions())
  401. self.addShortcutActions(self.gui.ui.menu_Help.actions())
  402. if self.host.processMode == ENGINE_PROCESS_MODE_PATCHBAY:
  403. self.addShortcutActions(self.gui.ui.menu_Canvas.actions())
  404. self.addShortcutActions(self.gui.ui.menu_Canvas_Zoom.actions())
  405. self.addWidget(self.gui.ui.menubar)
  406. self.addLine()
  407. self.addWidget(self.gui.ui.toolBar)
  408. if self.host.processMode == ENGINE_PROCESS_MODE_PATCHBAY:
  409. self.addLine()
  410. self.addWidget(self.gui.centralWidget())
  411. self.finalSetup(self.gui, winId)
  412. self.gui.send(["ready", int(self.fWidget.winId())])
  413. def addShortcutActions(self, actions):
  414. for action in actions:
  415. if not action.shortcut().isEmpty():
  416. self.fShortcutActions.append(action)
  417. def addWidget(self, widget):
  418. widget.setParent(self.fWidget)
  419. self.fLayout.addWidget(widget)
  420. def addLine(self):
  421. line = QFrame(self.fWidget)
  422. line.setFrameShadow(QFrame.Sunken)
  423. line.setFrameShape(QFrame.HLine)
  424. line.setLineWidth(0)
  425. line.setMidLineWidth(1)
  426. self.fLayout.addWidget(line)
  427. def keyPressEvent(self, event):
  428. modifiers = event.modifiers()
  429. modifiersStr = ""
  430. if modifiers & Qt.ShiftModifier:
  431. modifiersStr += "Shift+"
  432. if modifiers & Qt.ControlModifier:
  433. modifiersStr += "Ctrl+"
  434. if modifiers & Qt.AltModifier:
  435. modifiersStr += "Alt+"
  436. if modifiers & Qt.MetaModifier:
  437. modifiersStr += "Meta+"
  438. keyStr = QKeySequence(event.key()).toString()
  439. keySeq = QKeySequence(modifiersStr + keyStr)
  440. for action in self.fShortcutActions:
  441. if not action.isEnabled():
  442. continue
  443. if keySeq.matches(action.shortcut()) != QKeySequence.ExactMatch:
  444. continue
  445. event.accept()
  446. action.trigger()
  447. return
  448. QEmbedWidget.keyPressEvent(self, event)
  449. def showEvent(self, event):
  450. QEmbedWidget.showEvent(self, event)
  451. # set our gui as parent for all plugins UIs
  452. if self.host.manageUIs:
  453. winIdStr = "%x" % self.fWinId
  454. self.host.set_engine_option(ENGINE_OPTION_FRONTEND_WIN_ID, 0, winIdStr)
  455. def hideEvent(self, event):
  456. # disable parent
  457. self.host.set_engine_option(ENGINE_OPTION_FRONTEND_WIN_ID, 0, "0")
  458. QEmbedWidget.hideEvent(self, event)
  459. def closeEvent(self, event):
  460. self.gui.close()
  461. self.gui.closeExternalUI()
  462. QEmbedWidget.closeEvent(self, event)
  463. # there might be other qt windows open which will block carla-plugin from quitting
  464. app.quit()
  465. # ------------------------------------------------------------------------------------------------------------
  466. # Main
  467. if __name__ == '__main__':
  468. # -------------------------------------------------------------
  469. # App initialization
  470. app = CarlaApplication("Carla2-Plugin")
  471. # -------------------------------------------------------------
  472. # Set-up custom signal handling
  473. setUpSignals()
  474. # -------------------------------------------------------------
  475. # Init host backend
  476. host = initHost("Carla-Plugin", None, False, True, True, PluginHost)
  477. host.processMode = ENGINE_PROCESS_MODE_PATCHBAY if sys.argv[0].lower().endswith("/carla-plugin-patchbay") else ENGINE_PROCESS_MODE_CONTINUOUS_RACK
  478. host.processModeForced = True
  479. host.nextProcessMode = host.processMode
  480. loadHostSettings(host)
  481. # -------------------------------------------------------------
  482. # Create GUI
  483. try:
  484. winId = int(os.getenv("CARLA_PLUGIN_EMBED_WINID"))
  485. except:
  486. winId = 0
  487. gCarla.utils.setenv("CARLA_PLUGIN_EMBED_WINID", "0")
  488. if LINUX and winId != 0:
  489. gui = CarlaEmbedW(host, winId)
  490. else:
  491. gui = CarlaMiniW(host)
  492. # -------------------------------------------------------------
  493. # App-Loop
  494. app.exit_exec()