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_control.py 39KB

11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # Carla OSC controller
  4. # Copyright (C) 2011-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 PyQt4.QtCore import QLibrary
  20. from PyQt4.QtGui import QApplication, QInputDialog, QMainWindow
  21. from liblo import make_method, Address, ServerError, ServerThread
  22. from liblo import send as lo_send
  23. from liblo import TCP as LO_TCP
  24. from liblo import UDP as LO_UDP
  25. # ------------------------------------------------------------------------------------------------------------
  26. # Imports (Custom)
  27. import ui_carla_control
  28. from carla_shared import *
  29. global lo_target, lo_targetName
  30. lo_target = None
  31. lo_targetName = ""
  32. Carla.isControl = True
  33. Carla.isLocal = False
  34. # ------------------------------------------------------------------------------------------------------------
  35. # Python Object dicts compatible to carla-backend struct ctypes
  36. ParameterData = {
  37. 'type': PARAMETER_NULL,
  38. 'index': 0,
  39. 'rindex': -1,
  40. 'hints': 0x0,
  41. 'midiChannel': 0,
  42. 'midiCC': -1
  43. }
  44. ParameterRanges = {
  45. 'def': 0.0,
  46. 'min': 0.0,
  47. 'max': 1.0,
  48. 'step': 0.0,
  49. 'stepSmall': 0.0,
  50. 'stepLarge': 0.0
  51. }
  52. MidiProgramData = {
  53. 'bank': 0,
  54. 'program': 0,
  55. 'name': None
  56. }
  57. CustomData = {
  58. 'type': CUSTOM_DATA_INVALID,
  59. 'key': None,
  60. 'value': None
  61. }
  62. # ------------------------------------------------------------------------------------------------------------
  63. CarlaPluginInfo = {
  64. 'type': PLUGIN_NONE,
  65. 'category': PLUGIN_CATEGORY_NONE,
  66. 'hints': 0x0,
  67. 'optionsAvailable': 0x0,
  68. 'optionsEnabled': 0x0,
  69. 'binary': None,
  70. 'name': None,
  71. 'label': None,
  72. 'maker': None,
  73. 'copyright': None,
  74. 'iconName': None,
  75. 'uniqueId': 0,
  76. 'latency': 0
  77. }
  78. CarlaNativePluginInfo = {
  79. 'category': PLUGIN_CATEGORY_NONE,
  80. 'hints': 0x0,
  81. 'audioIns': 0,
  82. 'audioOuts': 0,
  83. 'midiIns': 0,
  84. 'midiOuts': 0,
  85. 'parameterIns': 0,
  86. 'parameterOuts': 0,
  87. 'name': None,
  88. 'label': None,
  89. 'maker': None,
  90. 'copyright': None
  91. }
  92. CarlaPortCountInfo = {
  93. 'ins': 0,
  94. 'outs': 0,
  95. 'total': 0
  96. }
  97. CarlaParameterInfo = {
  98. 'name': None,
  99. 'symbol': None,
  100. 'unit': None,
  101. 'scalePointCount': 0,
  102. }
  103. CarlaScalePointInfo = {
  104. 'value': 0.0,
  105. 'label': None
  106. }
  107. CarlaTransportInfo = {
  108. 'playing': False,
  109. 'frame': 0,
  110. 'bar': 0,
  111. 'beat': 0,
  112. 'tick': 0,
  113. 'bpm': 0.0
  114. }
  115. # ------------------------------------------------------------------------------------------------------------
  116. # Helper class
  117. class ControlPluginInfo(object):
  118. __slots__ = [
  119. 'pluginInfo',
  120. 'pluginRealName',
  121. 'audioCountInfo',
  122. 'midiCountInfo',
  123. 'parameterCountInfo',
  124. 'parameterInfoS',
  125. 'parameterDataS',
  126. 'parameterRangeS',
  127. 'parameterValueS',
  128. 'programCount',
  129. 'programCurrent',
  130. 'programNameS',
  131. 'midiProgramCount',
  132. 'midiProgramCurrent',
  133. 'midiProgramDataS',
  134. 'peaks'
  135. ]
  136. # ------------------------------------------------------------------------------------------------------------
  137. # Python Object class compatible to 'Host' on the Carla Backend code
  138. class Host(object):
  139. def __init__(self):
  140. object.__init__(self)
  141. self.fPluginsInfo = []
  142. def _add(self, pluginId):
  143. if len(self.fPluginsInfo) != pluginId:
  144. return
  145. info = ControlPluginInfo()
  146. info.pluginInfo = CarlaPluginInfo
  147. info.pluginRealName = None
  148. info.audioCountInfo = CarlaPortCountInfo
  149. info.midiCountInfo = CarlaPortCountInfo
  150. info.parameterCountInfo = CarlaPortCountInfo
  151. info.parameterInfoS = []
  152. info.parameterDataS = []
  153. info.parameterRangeS = []
  154. info.parameterValueS = []
  155. info.programCount = 0
  156. info.programCurrent = -1
  157. info.programNameS = []
  158. info.midiProgramCount = 0
  159. info.midiProgramCurrent = -1
  160. info.midiProgramDataS = []
  161. info.peaks = [0.0, 0.0, 0.0, 0.0]
  162. self.fPluginsInfo.append(info)
  163. def _set_pluginInfo(self, index, info):
  164. self.fPluginsInfo[index].pluginInfo = info
  165. def _set_pluginRealName(self, index, realName):
  166. self.fPluginsInfo[index].pluginRealName = realName
  167. def _set_audioCountInfo(self, index, info):
  168. self.fPluginsInfo[index].audioCountInfo = info
  169. def _set_midiCountInfo(self, index, info):
  170. self.fPluginsInfo[index].midiCountInfo = info
  171. def _set_parameterCountInfo(self, index, info):
  172. self.fPluginsInfo[index].parameterCountInfo = info
  173. # clear
  174. self.fPluginsInfo[index].parameterInfoS = []
  175. self.fPluginsInfo[index].parameterDataS = []
  176. self.fPluginsInfo[index].parameterRangeS = []
  177. self.fPluginsInfo[index].parameterValueS = []
  178. # add placeholders
  179. for x in range(info['total']):
  180. self.fPluginsInfo[index].parameterInfoS.append(CarlaParameterInfo)
  181. self.fPluginsInfo[index].parameterDataS.append(ParameterData)
  182. self.fPluginsInfo[index].parameterRangeS.append(ParameterRanges)
  183. self.fPluginsInfo[index].parameterValueS.append(0.0)
  184. def _set_programCount(self, index, count):
  185. self.fPluginsInfo[index].programCount = count
  186. # clear
  187. self.fPluginsInfo[index].programNameS = []
  188. # add placeholders
  189. for x in range(count):
  190. self.fPluginsInfo[index].programNameS.append(None)
  191. def _set_midiProgramCount(self, index, count):
  192. self.fPluginsInfo[index].midiProgramCount = count
  193. # clear
  194. self.fPluginsInfo[index].midiProgramDataS = []
  195. # add placeholders
  196. for x in range(count):
  197. self.fPluginsInfo[index].midiProgramDataS.append(MidiProgramData)
  198. def _set_parameterInfoS(self, index, paramIndex, data):
  199. if paramIndex < self.fPluginsInfo[index].parameterCountInfo['total']:
  200. self.fPluginsInfo[index].parameterInfoS[paramIndex] = data
  201. def _set_parameterDataS(self, index, paramIndex, data):
  202. if paramIndex < self.fPluginsInfo[index].parameterCountInfo['total']:
  203. self.fPluginsInfo[index].parameterDataS[paramIndex] = data
  204. def _set_parameterRangeS(self, index, paramIndex, data):
  205. if paramIndex < self.fPluginsInfo[index].parameterCountInfo['total']:
  206. self.fPluginsInfo[index].parameterRangeS[paramIndex] = data
  207. def _set_parameterValueS(self, index, paramIndex, value):
  208. if paramIndex < self.fPluginsInfo[index].parameterCountInfo['total']:
  209. self.fPluginsInfo[index].parameterValueS[paramIndex] = value
  210. def _set_parameterDefaultValue(self, index, paramIndex, value):
  211. if paramIndex < self.fPluginsInfo[index].parameterCountInfo['total']:
  212. self.fPluginsInfo[index].parameterRangeS[paramIndex]['def'] = value
  213. def _set_parameterMidiCC(self, index, paramIndex, cc):
  214. if paramIndex < self.fPluginsInfo[index].parameterCountInfo['total']:
  215. self.fPluginsInfo[index].parameterDataS[paramIndex]['midiCC'] = cc
  216. def _set_parameterMidiChannel(self, index, paramIndex, channel):
  217. if paramIndex < self.fPluginsInfo[index].parameterCountInfo['total']:
  218. self.fPluginsInfo[index].parameterDataS[paramIndex]['midiChannel'] = channel
  219. def _set_currentProgram(self, index, pIndex):
  220. self.fPluginsInfo[index].programCurrent = pIndex
  221. def _set_currentMidiProgram(self, index, mpIndex):
  222. self.fPluginsInfo[index].midiProgramCurrent = mpIndex
  223. def _set_programNameS(self, index, pIndex, data):
  224. if pIndex < self.fPluginsInfo[index].programCount:
  225. self.fPluginsInfo[index].programNameS[pIndex] = data
  226. def _set_midiProgramDataS(self, index, mpIndex, data):
  227. if mpIndex < self.fPluginsInfo[index].midiProgramCount:
  228. self.fPluginsInfo[index].midiProgramDataS[mpIndex] = data
  229. def _set_peaks(self, index, in1, in2, out1, out2):
  230. self.fPluginsInfo[index].peaks = [in1, in2, out1, out2]
  231. # get_extended_license_text
  232. # get_supported_file_types
  233. # get_engine_driver_count
  234. # get_engine_driver_name
  235. # get_engine_driver_device_names
  236. # get_internal_plugin_count
  237. # get_internal_plugin_info
  238. # engine_init
  239. # engine_close
  240. # engine_idle
  241. # is_engine_running
  242. # set_engine_about_to_close
  243. # set_engine_callback
  244. # set_engine_option
  245. # load_filename
  246. # load_project
  247. # save_project
  248. # patchbay_connect
  249. # patchbay_disconnect
  250. # patchbay_refresh
  251. # transport_play
  252. # transport_pause
  253. # transport_relocate
  254. # get_current_transport_frame
  255. # get_transport_info
  256. # add_plugin
  257. # remove_plugin
  258. # remove_all_plugins
  259. # rename_plugin
  260. # clone_plugin
  261. # replace_plugin
  262. # switch_plugins
  263. # load_plugin_state
  264. # save_plugin_state
  265. def get_plugin_info(self, pluginId):
  266. return self.fPluginsInfo[pluginId].pluginInfo
  267. def get_audio_port_count_info(self, pluginId):
  268. return self.fPluginsInfo[pluginId].audioCountInfo
  269. def get_midi_port_count_info(self, pluginId):
  270. return self.fPluginsInfo[pluginId].midiCountInfo
  271. def get_parameter_count_info(self, pluginId):
  272. return self.fPluginsInfo[pluginId].parameterCountInfo
  273. def get_parameter_info(self, pluginId, parameterId):
  274. return self.fPluginsInfo[pluginId].parameterInfoS[parameterId]
  275. def get_parameter_scalepoint_info(self, pluginId, parameterId, scalepoint_id):
  276. return CarlaScalePointInfo
  277. def get_parameter_data(self, pluginId, parameterId):
  278. return self.fPluginsInfo[pluginId].parameterDataS[parameterId]
  279. def get_parameter_ranges(self, pluginId, parameterId):
  280. return self.fPluginsInfo[pluginId].parameterRangeS[parameterId]
  281. def get_midi_program_data(self, pluginId, midiProgramId):
  282. return self.fPluginsInfo[pluginId].midiProgramDataS[midiProgramId]
  283. def get_custom_data(self, pluginId, custom_data_id):
  284. return CustomData
  285. def get_chunk_data(self, pluginId):
  286. return None
  287. def get_parameter_count(self, pluginId):
  288. return self.fPluginsInfo[pluginId].parameterCountInfo['total']
  289. def get_program_count(self, pluginId):
  290. return self.fPluginsInfo[pluginId].programCount
  291. def get_midi_program_count(self, pluginId):
  292. return self.fPluginsInfo[pluginId].midiProgramCount
  293. def get_custom_data_count(self, pluginId):
  294. return 0
  295. def get_parameter_text(self, pluginId, parameterId):
  296. return None
  297. def get_program_name(self, pluginId, programId):
  298. return self.fPluginsInfo[pluginId].programNameS[programId]
  299. def get_midi_program_name(self, pluginId, midiProgramId):
  300. return self.fPluginsInfo[pluginId].midiProgramDataS[midiProgramId]['label']
  301. def get_real_plugin_name(self, pluginId):
  302. return self.fPluginsInfo[pluginId].pluginRealName
  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_input_peak_value(self, pluginId, portId):
  312. return self.fPluginsInfo[pluginId].peaks[portId-1]
  313. def get_output_peak_value(self, pluginId, portId):
  314. return self.fPluginsInfo[pluginId].peaks[portId+1]
  315. def set_option(self, pluginId, option, yesNo):
  316. global to_target, lo_targetName
  317. lo_path = "/%s/%i/set_option" % (lo_targetName, pluginId)
  318. lo_send(lo_target, lo_path, option, yesNo)
  319. def set_active(self, pluginId, onoff):
  320. global to_target, lo_targetName
  321. lo_path = "/%s/%i/set_active" % (lo_targetName, pluginId)
  322. lo_send(lo_target, lo_path, 1 if onoff else 0)
  323. def set_drywet(self, pluginId, value):
  324. global to_target, lo_targetName
  325. lo_path = "/%s/%i/set_drywet" % (lo_targetName, pluginId)
  326. lo_send(lo_target, lo_path, value)
  327. def set_volume(self, pluginId, value):
  328. global to_target, lo_targetName
  329. lo_path = "/%s/%i/set_volume" % (lo_targetName, pluginId)
  330. lo_send(lo_target, lo_path, value)
  331. def set_balance_left(self, pluginId, value):
  332. global to_target, lo_targetName
  333. lo_path = "/%s/%i/set_balance_left" % (lo_targetName, pluginId)
  334. lo_send(lo_target, lo_path, value)
  335. def set_balance_right(self, pluginId, value):
  336. global to_target, lo_targetName
  337. lo_path = "/%s/%i/set_balance_right" % (lo_targetName, pluginId)
  338. lo_send(lo_target, lo_path, value)
  339. def set_panning(self, pluginId, value):
  340. global to_target, lo_targetName
  341. lo_path = "/%s/%i/set_panning" % (lo_targetName, pluginId)
  342. lo_send(lo_target, lo_path, value)
  343. def set_ctrl_channel(self, pluginId, channel):
  344. global to_target, lo_targetName
  345. lo_path = "/%s/%i/set_ctrl_channel" % (lo_targetName, pluginId)
  346. lo_send(lo_target, lo_path, channel)
  347. def set_parameter_value(self, pluginId, parameterId, value):
  348. global to_target, lo_targetName
  349. lo_path = "/%s/%i/set_parameter_value" % (lo_targetName, pluginId)
  350. lo_send(lo_target, lo_path, parameterId, value)
  351. def set_parameter_midi_cc(self, pluginId, parameterId, midi_cc):
  352. global to_target, lo_targetName
  353. lo_path = "/%s/%i/set_parameter_midi_cc" % (lo_targetName, pluginId)
  354. lo_send(lo_target, lo_path, parameterId, midi_cc)
  355. def set_parameter_midi_channel(self, pluginId, parameterId, channel):
  356. global to_target, lo_targetName
  357. lo_path = "/%s/%i/set_parameter_midi_channel" % (lo_targetName, pluginId)
  358. lo_send(lo_target, lo_path, parameterId, channel)
  359. def set_program(self, pluginId, programId):
  360. global to_target, lo_targetName
  361. lo_path = "/%s/%i/set_program" % (lo_targetName, pluginId)
  362. lo_send(lo_target, lo_path, programId)
  363. def set_midi_program(self, pluginId, midiProgramId):
  364. global to_target, lo_targetName
  365. lo_path = "/%s/%i/set_midi_program" % (lo_targetName, pluginId)
  366. lo_send(lo_target, lo_path, midiProgramId)
  367. # set_custom_data
  368. # set_chunk_data
  369. # prepare_for_save
  370. def send_midi_note(self, pluginId, channel, note, velocity):
  371. global to_target, lo_targetName
  372. if velocity:
  373. lo_path = "/%s/%i/note_on" % (lo_targetName, pluginId)
  374. lo_send(lo_target, lo_path, channel, note, velocity)
  375. else:
  376. lo_path = "/%s/%i/note_off" % (lo_targetName, pluginId)
  377. lo_send(lo_target, lo_path, channel, note)
  378. # show_gui
  379. # get_buffer_size
  380. # get_sample_rate
  381. # get_last_error
  382. # get_host_osc_url
  383. # nsm_announce
  384. # nsm_reply_open
  385. # nsm_reply_save
  386. # ------------------------------------------------------------------------------------------------------------
  387. # OSC Control server
  388. class ControlServer(ServerThread):
  389. def __init__(self, parent, mode):
  390. ServerThread.__init__(self, 8087, mode)
  391. self.fParent = parent
  392. def getFullURL(self):
  393. return "%scarla-control" % self.get_url()
  394. @make_method('/carla-control/add_plugin_start', 'is')
  395. def add_plugin_start_callback(self, path, args):
  396. pluginId, pluginName = args
  397. self.fParent.emit(SIGNAL("AddPluginStart(int, QString)"), pluginId, pluginName)
  398. @make_method('/carla-control/add_plugin_end', 'i')
  399. def add_plugin_end_callback(self, path, args):
  400. pluginId, = args
  401. self.fParent.emit(SIGNAL("AddPluginEnd(int)"), pluginId)
  402. @make_method('/carla-control/remove_plugin', 'i')
  403. def remove_plugin_callback(self, path, args):
  404. pluginId, = args
  405. self.fParent.emit(SIGNAL("RemovePlugin(int)"), pluginId)
  406. @make_method('/carla-control/set_plugin_data', 'iiiissssh')
  407. def set_plugin_data_callback(self, path, args):
  408. pluginId, ptype, category, hints, realName, label, maker, copyright_, uniqueId = args
  409. self.fParent.emit(SIGNAL("SetPluginData(int, int, int, int, QString, QString, QString, QString, int)"), pluginId, ptype, category, hints, realName, label, maker, copyright_, uniqueId)
  410. @make_method('/carla-control/set_plugin_ports', 'iiiiiiii')
  411. def set_plugin_ports_callback(self, path, args):
  412. pluginId, audioIns, audioOuts, midiIns, midiOuts, cIns, cOuts, cTotals = args
  413. self.fParent.emit(SIGNAL("SetPluginPorts(int, int, int, int, int, int, int, int)"), pluginId, audioIns, audioOuts, midiIns, midiOuts, cIns, cOuts, cTotals)
  414. @make_method('/carla-control/set_parameter_data', 'iiiissf')
  415. def set_parameter_data_callback(self, path, args):
  416. pluginId, index, type_, hints, name, label, current = args
  417. self.fParent.emit(SIGNAL("SetParameterData(int, int, int, int, QString, QString, double)"), pluginId, index, type_, hints, name, label, current)
  418. @make_method('/carla-control/set_parameter_ranges', 'iiffffff')
  419. def set_parameter_ranges_callback(self, path, args):
  420. pluginId, index, min_, max_, def_, step, stepSmall, stepLarge = args
  421. self.fParent.emit(SIGNAL("SetParameterRanges(int, int, double, double, double, double, double, double)"), pluginId, index, min_, max_, def_, step, stepSmall, stepLarge)
  422. @make_method('/carla-control/set_parameter_midi_cc', 'iii')
  423. def set_parameter_midi_cc_callback(self, path, args):
  424. pluginId, index, cc = args
  425. self.fParent.emit(SIGNAL("SetParameterMidiCC(int, int, int)"), pluginId, index, cc)
  426. @make_method('/carla-control/set_parameter_midi_channel', 'iii')
  427. def set_parameter_midi_channel_callback(self, path, args):
  428. pluginId, index, channel = args
  429. self.fParent.emit(SIGNAL("SetParameterMidiChannel(int, int, int)"), pluginId, index, channel)
  430. @make_method('/carla-control/set_parameter_value', 'iif')
  431. def set_parameter_value_callback(self, path, args):
  432. pluginId, index, value = args
  433. self.fParent.emit(SIGNAL("SetParameterValue(int, int, double)"), pluginId, index, value)
  434. @make_method('/carla-control/set_default_value', 'iif')
  435. def set_default_value_callback(self, path, args):
  436. pluginId, index, value = args
  437. self.fParent.emit(SIGNAL("SetDefaultValue(int, int, double)"), pluginId, index, value)
  438. @make_method('/carla-control/set_program', 'ii')
  439. def set_program_callback(self, path, args):
  440. pluginId, index = args
  441. self.fParent.emit(SIGNAL("SetProgram(int, int)"), pluginId, index)
  442. @make_method('/carla-control/set_program_count', 'ii')
  443. def set_program_count_callback(self, path, args):
  444. pluginId, count = args
  445. self.fParent.emit(SIGNAL("SetProgramCount(int, int)"), pluginId, count)
  446. @make_method('/carla-control/set_program_name', 'iis')
  447. def set_program_name_callback(self, path, args):
  448. pluginId, index, name = args
  449. self.fParent.emit(SIGNAL("SetProgramName(int, int, QString)"), pluginId, index, name)
  450. @make_method('/carla-control/set_midi_program', 'ii')
  451. def set_midi_program_callback(self, path, args):
  452. pluginId, index = args
  453. self.fParent.emit(SIGNAL("SetMidiProgram(int, int)"), pluginId, index)
  454. @make_method('/carla-control/set_midi_program_count', 'ii')
  455. def set_midi_program_count_callback(self, path, args):
  456. pluginId, count = args
  457. self.fParent.emit(SIGNAL("SetMidiProgramCount(int, int)"), pluginId, count)
  458. @make_method('/carla-control/set_midi_program_data', 'iiiis')
  459. def set_midi_program_data_callback(self, path, args):
  460. pluginId, index, bank, program, name = args
  461. self.fParent.emit(SIGNAL("SetMidiProgramData(int, int, int, int, QString)"), pluginId, index, bank, program, name)
  462. @make_method('/carla-control/note_on', 'iiii')
  463. def note_on_callback(self, path, args):
  464. pluginId, channel, note, velo = args
  465. self.fParent.emit(SIGNAL("NoteOn(int, int, int, int)"), pluginId, channel, note, velo)
  466. @make_method('/carla-control/note_off', 'iii')
  467. def note_off_callback(self, path, args):
  468. pluginId, channel, note = args
  469. self.fParent.emit(SIGNAL("NoteOff(int, int, int)"), pluginId, channel, note)
  470. @make_method('/carla-control/set_peaks', 'iffff')
  471. def set_output_peak_value_callback(self, path, args):
  472. pluginId, in1, in2, out1, out2 = args
  473. self.fParent.emit(SIGNAL("SetPeaks(int, double, double, double, double)"), pluginId, in1, in2, out1, out2)
  474. @make_method('/carla-control/exit', '')
  475. def exit_callback(self, path, args):
  476. self.fParent.emit(SIGNAL("Exit()"))
  477. @make_method(None, None)
  478. def fallback(self, path, args):
  479. print("ControlServer::fallback(\"%s\") - unknown message, args =" % path, args)
  480. # ------------------------------------------------------------------------------------------------------------
  481. # Main Window
  482. class CarlaControlW(QMainWindow):
  483. def __init__(self, oscAddr=None):
  484. QMainWindow.__init__(self, None)
  485. self.ui = ui_carla_control.Ui_CarlaControlW()
  486. self.ui.setupUi(self)
  487. if MACOS:
  488. self.setUnifiedTitleAndToolBarOnMac(True)
  489. # -------------------------------------------------------------
  490. # Internal stuff
  491. self.fProjectFilename = None
  492. self.fProjectLoading = False
  493. self.fPluginCount = 0
  494. self.fPluginList = []
  495. self.fIdleTimerFast = 0
  496. self.fIdleTimerSlow = 0
  497. self.fLastPluginName = ""
  498. self.lo_address = ""
  499. self.lo_server = None
  500. # -------------------------------------------------------------
  501. # Load Settings
  502. self.loadSettings()
  503. # -------------------------------------------------------------
  504. # Set-up GUI stuff
  505. self.ui.act_file_refresh.setEnabled(False)
  506. #self.ui.act_plugin_remove_all.setEnabled(False)
  507. self.resize(self.width(), 0)
  508. # -------------------------------------------------------------
  509. # Connect actions to functions
  510. self.connect(self.ui.act_file_connect, SIGNAL("triggered()"), SLOT("slot_fileConnect()"))
  511. self.connect(self.ui.act_file_refresh, SIGNAL("triggered()"), SLOT("slot_fileRefresh()"))
  512. #self.connect(self.ui.act_plugin_add, SIGNAL("triggered()"), SLOT("slot_pluginAdd()"))
  513. #self.connect(self.ui.act_plugin_add2, SIGNAL("triggered()"), SLOT("slot_pluginAdd()"))
  514. #self.connect(self.ui.act_plugin_refresh, SIGNAL("triggered()"), SLOT("slot_pluginRefresh()"))
  515. #self.connect(self.ui.act_plugin_remove_all, SIGNAL("triggered()"), SLOT("slot_pluginRemoveAll()"))
  516. #self.connect(self.ui.act_settings_show_toolbar, SIGNAL("triggered(bool)"), SLOT("slot_toolbarShown()"))
  517. #self.connect(self.ui.act_settings_configure, SIGNAL("triggered()"), SLOT("slot_configureCarla()"))
  518. self.connect(self.ui.act_help_about, SIGNAL("triggered()"), SLOT("slot_aboutCarlaControl()"))
  519. self.connect(self.ui.act_help_about_qt, SIGNAL("triggered()"), app, SLOT("aboutQt()"))
  520. self.connect(self, SIGNAL("SIGTERM()"), SLOT("slot_handleSIGTERM()"))
  521. self.connect(self, SIGNAL("AddPluginStart(int, QString)"), SLOT("slot_handleAddPluginStart(int, QString)"))
  522. self.connect(self, SIGNAL("AddPluginEnd(int)"), SLOT("slot_handleAddPluginEnd(int)"))
  523. self.connect(self, SIGNAL("RemovePlugin(int)"), SLOT("slot_handleRemovePlugin(int)"))
  524. self.connect(self, SIGNAL("SetPluginData(int, int, int, int, QString, QString, QString, QString, int)"), SLOT("slot_handleSetPluginData(int, int, int, int, QString, QString, QString, QString, int)"))
  525. self.connect(self, SIGNAL("SetPluginPorts(int, int, int, int, int, int, int, int)"), SLOT("slot_handleSetPluginPorts(int, int, int, int, int, int, int, int)"))
  526. self.connect(self, SIGNAL("SetParameterData(int, int, int, int, QString, QString, double)"), SLOT("slot_handleSetParameterData(int, int, int, int, QString, QString, double)"))
  527. self.connect(self, SIGNAL("SetParameterRanges(int, int, double, double, double, double, double, double)"), SLOT("slot_handleSetParameterRanges(int, int, double, double, double, double, double, double)"))
  528. self.connect(self, SIGNAL("SetParameterMidiCC(int, int, int)"), SLOT("slot_handleSetParameterMidiCC(int, int, int)"))
  529. self.connect(self, SIGNAL("SetParameterMidiChannel(int, int, int)"), SLOT("slot_handleSetParameterMidiChannel(int, int, int)"))
  530. self.connect(self, SIGNAL("SetParameterValue(int, int, double)"), SLOT("slot_handleSetParameterValue(int, int, double)"))
  531. self.connect(self, SIGNAL("SetDefaultValue(int, int, double)"), SLOT("slot_handleSetDefaultValue(int, int, double)"))
  532. self.connect(self, SIGNAL("SetProgram(int, int)"), SLOT("slot_handleSetProgram(int, int)"))
  533. self.connect(self, SIGNAL("SetProgramCount(int, int)"), SLOT("slot_handleSetProgramCount(int, int)"))
  534. self.connect(self, SIGNAL("SetProgramName(int, int, QString)"), SLOT("slot_handleSetProgramName(int, int, QString)"))
  535. self.connect(self, SIGNAL("SetMidiProgram(int, int)"), SLOT("slot_handleSetMidiProgram(int, int)"))
  536. self.connect(self, SIGNAL("SetMidiProgramCount(int, int)"), SLOT("slot_handleSetMidiProgramCount(int, int)"))
  537. self.connect(self, SIGNAL("SetMidiProgramData(int, int, int, int, QString)"), SLOT("slot_handleSetMidiProgramData(int, int, int, int, QString)"))
  538. self.connect(self, SIGNAL("NoteOn(int, int, int, int)"), SLOT("slot_handleNoteOn(int, int, int, int)"))
  539. self.connect(self, SIGNAL("NoteOff(int, int, int)"), SLOT("slot_handleNoteOff(int, int, int)"))
  540. self.connect(self, SIGNAL("SetPeaks(int, double, double, double, double)"), SLOT("slot_handleSetPeaks(int, double, double, double, double)"))
  541. self.connect(self, SIGNAL("Exit()"), SLOT("slot_handleExit()"))
  542. if oscAddr:
  543. self.connectToAddr(oscAddr)
  544. def connectToAddr(self, addr):
  545. global lo_target, lo_targetName
  546. self.lo_address = addr
  547. lo_target = Address(self.lo_address)
  548. lo_targetName = self.lo_address.rsplit("/", 1)[-1]
  549. print("Connecting to \"%s\" as '%s'..." % (self.lo_address, lo_targetName))
  550. try:
  551. self.lo_server = ControlServer(self, LO_UDP if self.lo_address.startswith("osc.udp") else LO_TCP)
  552. except: # ServerError, err:
  553. print("Connecting error!")
  554. #print str(err)
  555. QMessageBox.critical(self, self.tr("Error"), self.tr("Failed to connect, operation failed."))
  556. return
  557. if self.lo_server:
  558. self.lo_server.start()
  559. self.ui.act_file_refresh.setEnabled(True)
  560. lo_send(lo_target, "/register", self.lo_server.getFullURL())
  561. self.fIdleTimerFast = self.startTimer(60)
  562. self.fIdleTimerSlow = self.startTimer(60*2)
  563. def removeAll(self):
  564. self.killTimer(self.fIdleTimerFast)
  565. self.killTimer(self.fIdleTimerSlow)
  566. self.fIdleTimerFast = 0
  567. self.fIdleTimerSlow = 0
  568. for i in range(self.fPluginCount):
  569. pwidget = self.fPluginList[i]
  570. if pwidget is None:
  571. break
  572. pwidget.ui.edit_dialog.close()
  573. pwidget.close()
  574. pwidget.deleteLater()
  575. del pwidget
  576. self.fPluginCount = 0
  577. self.fPluginList = []
  578. Carla.host.fPluginsInfo = []
  579. self.fIdleTimerFast = self.startTimer(60)
  580. self.fIdleTimerSlow = self.startTimer(60*2)
  581. @pyqtSlot()
  582. def slot_handleSIGTERM(self):
  583. print("Got SIGTERM -> Closing now")
  584. self.close()
  585. @pyqtSlot()
  586. def slot_fileConnect(self):
  587. global lo_target, lo_targetName
  588. if lo_target and self.lo_server:
  589. urlText = self.lo_address
  590. else:
  591. urlText = "osc.tcp://127.0.0.1:19000/Carla"
  592. askValue = QInputDialog.getText(self, self.tr("Carla Control - Connect"), self.tr("Address"), text=urlText)
  593. if not askValue[1]:
  594. return
  595. self.slot_handleExit()
  596. self.connectToAddr(askValue[0])
  597. @pyqtSlot()
  598. def slot_fileRefresh(self):
  599. global lo_target
  600. if lo_target and self.lo_server:
  601. self.removeAll()
  602. lo_send(lo_target, "/unregister")
  603. lo_send(lo_target, "/register", self.lo_server.getFullURL())
  604. @pyqtSlot()
  605. def slot_aboutCarlaControl(self):
  606. CarlaAboutW(self).exec_()
  607. @pyqtSlot(int, str)
  608. def slot_handleAddPluginStart(self, pluginId, pluginName):
  609. self.fLastPluginName = pluginName
  610. Carla.host._add(pluginId)
  611. @pyqtSlot(int)
  612. def slot_handleAddPluginEnd(self, pluginId):
  613. pwidget = PluginWidget(self, pluginId)
  614. self.ui.w_plugins.layout().addWidget(pwidget)
  615. self.fPluginCount += 1
  616. self.fPluginList.append(pwidget)
  617. @pyqtSlot(int)
  618. def slot_handleRemovePlugin(self, pluginId):
  619. if pluginId >= self.fPluginCount:
  620. print("handleRemovePlugin(%i) - invalid plugin id" % pluginId)
  621. return
  622. pwidget = self.fPluginList[pluginId]
  623. if pwidget is None:
  624. print("handleRemovePlugin(%i) - invalid plugin" % pluginId)
  625. return
  626. self.fPluginList.pop(pluginId)
  627. self.fPluginCount -= 1
  628. self.ui.w_plugins.layout().removeWidget(pwidget)
  629. pwidget.ui.edit_dialog.close()
  630. pwidget.close()
  631. pwidget.deleteLater()
  632. del pwidget
  633. # push all plugins 1 slot back
  634. for i in range(pluginId, self.fPluginCount):
  635. self.fPluginList[i].setId(i)
  636. Carla.host.fPluginsInfo.pop(pluginId)
  637. @pyqtSlot(int, int, int, int, str, str, str, str, int)
  638. def slot_handleSetPluginData(self, pluginId, type_, category, hints, realName, label, maker, copyright, uniqueId):
  639. info = deepcopy(CarlaPluginInfo)
  640. info['type'] = type_
  641. info['category'] = category
  642. info['hints'] = hints
  643. info['name'] = self.fLastPluginName
  644. info['label'] = label
  645. info['maker'] = maker
  646. info['copyright'] = copyright
  647. info['uniqueId'] = uniqueId
  648. Carla.host._set_pluginInfo(pluginId, info)
  649. Carla.host._set_pluginRealName(pluginId, realName)
  650. @pyqtSlot(int, int, int, int, int, int, int, int)
  651. def slot_handleSetPluginPorts(self, pluginId, audioIns, audioOuts, midiIns, midiOuts, cIns, cOuts, cTotals):
  652. audioInfo = deepcopy(CarlaPortCountInfo)
  653. midiInfo = deepcopy(CarlaPortCountInfo)
  654. paramInfo = deepcopy(CarlaPortCountInfo)
  655. audioInfo['ins'] = audioIns
  656. audioInfo['outs'] = audioOuts
  657. audioInfo['total'] = audioIns + audioOuts
  658. midiInfo['ins'] = midiIns
  659. midiInfo['outs'] = midiOuts
  660. midiInfo['total'] = midiIns + midiOuts
  661. paramInfo['ins'] = cIns
  662. paramInfo['outs'] = cOuts
  663. paramInfo['total'] = cTotals
  664. Carla.host._set_audioCountInfo(pluginId, audioInfo)
  665. Carla.host._set_midiCountInfo(pluginId, midiInfo)
  666. Carla.host._set_parameterCountInfo(pluginId, paramInfo)
  667. @pyqtSlot(int, int, int, int, str, str, float)
  668. def slot_handleSetParameterData(self, pluginId, index, type_, hints, name, label, current):
  669. # remove hints not possible in bridge mode
  670. hints &= ~(PARAMETER_USES_SCALEPOINTS | PARAMETER_USES_CUSTOM_TEXT)
  671. data = deepcopy(ParameterData)
  672. data['type'] = type_
  673. data['index'] = index
  674. data['rindex'] = index
  675. data['hints'] = hints
  676. info = deepcopy(CarlaParameterInfo)
  677. info['name'] = name
  678. info['label'] = label
  679. Carla.host._set_parameterDataS(pluginId, index, data)
  680. Carla.host._set_parameterInfoS(pluginId, index, info)
  681. Carla.host._set_parameterValueS(pluginId, index, current)
  682. @pyqtSlot(int, int, float, float, float, float, float, float)
  683. def slot_handleSetParameterRanges(self, pluginId, index, min_, max_, def_, step, stepSmall, stepLarge):
  684. ranges = deepcopy(ParameterRanges)
  685. ranges['min'] = min_
  686. ranges['max'] = max_
  687. ranges['def'] = def_
  688. ranges['step'] = step
  689. ranges['stepSmall'] = stepSmall
  690. ranges['stepLarge'] = stepLarge
  691. Carla.host._set_parameterRangeS(pluginId, index, ranges)
  692. @pyqtSlot(int, int, float)
  693. def slot_handleSetParameterValue(self, pluginId, parameterId, value):
  694. if parameterId >= 0:
  695. Carla.host._set_parameterValueS(pluginId, parameterId, value)
  696. if pluginId >= self.fPluginCount:
  697. return
  698. pwidget = self.fPluginList[pluginId]
  699. if pwidget is None:
  700. return
  701. pwidget.setParameterValue(parameterId, value)
  702. @pyqtSlot(int, int, float)
  703. def slot_handleSetDefaultValue(self, pluginId, parameterId, value):
  704. Carla.host._set_parameterDefaultValue(pluginId, parameterId, value)
  705. if pluginId >= self.fPluginCount:
  706. return
  707. pwidget = self.fPluginList[pluginId]
  708. if pwidget is None:
  709. return
  710. pwidget.setParameterDefault(parameterId, value)
  711. @pyqtSlot(int, int, int)
  712. def slot_handleSetParameterMidiCC(self, pluginId, index, cc):
  713. Carla.host._set_parameterMidiCC(pluginId, index, cc)
  714. if pluginId >= self.fPluginCount:
  715. return
  716. pwidget = self.fPluginList[pluginId]
  717. if pwidget is None:
  718. return
  719. pwidget.setParameterMidiControl(index, cc)
  720. @pyqtSlot(int, int, int)
  721. def slot_handleSetParameterMidiChannel(self, pluginId, index, channel):
  722. Carla.host._set_parameterMidiChannel(pluginId, index, channel)
  723. if pluginId >= self.fPluginCount:
  724. return
  725. pwidget = self.fPluginList[pluginId]
  726. if pwidget is None:
  727. return
  728. pwidget.setParameterMidiChannel(index, channel)
  729. @pyqtSlot(int, int)
  730. def slot_handleSetProgram(self, pluginId, index):
  731. Carla.host._set_currentProgram(pluginId, index)
  732. if pluginId >= self.fPluginCount:
  733. return
  734. pwidget = self.fPluginList[pluginId]
  735. if pwidget is None:
  736. return
  737. pwidget.setProgram(index)
  738. @pyqtSlot(int, int)
  739. def slot_handleSetProgramCount(self, pluginId, count):
  740. Carla.host._set_programCount(pluginId, count)
  741. @pyqtSlot(int, int, str)
  742. def slot_handleSetProgramName(self, pluginId, index, name):
  743. Carla.host._set_programNameS(pluginId, index, name)
  744. @pyqtSlot(int, int)
  745. def slot_handleSetMidiProgram(self, pluginId, index):
  746. Carla.host._set_currentMidiProgram(pluginId, index)
  747. if pluginId >= self.fPluginCount:
  748. return
  749. pwidget = self.fPluginList[pluginId]
  750. if pwidget is None:
  751. return
  752. pwidget.setMidiProgram(index)
  753. @pyqtSlot(int, int)
  754. def slot_handleSetMidiProgramCount(self, pluginId, count):
  755. Carla.host._set_midiProgramCount(pluginId, count)
  756. @pyqtSlot(int, int, int, int, str)
  757. def slot_handleSetMidiProgramData(self, pluginId, index, bank, program, name):
  758. data = deepcopy(MidiProgramData)
  759. data['bank'] = bank
  760. data['program'] = program
  761. data['label'] = name
  762. Carla.host._set_midiProgramDataS(pluginId, index, data)
  763. @pyqtSlot(int, int, float)
  764. def slot_handleSetInputPeakValue(self, pluginId, portId, value):
  765. Carla.host._set_inPeak(pluginId, portId-1, value)
  766. @pyqtSlot(int, int, float)
  767. def slot_handleSetOutputPeakValue(self, pluginId, portId, value):
  768. Carla.host._set_outPeak(pluginId, portId-1, value)
  769. @pyqtSlot(int, int, int, int)
  770. def slot_handleNoteOn(self, pluginId, channel, note, velo):
  771. if pluginId >= self.fPluginCount:
  772. return
  773. pwidget = self.fPluginList[pluginId]
  774. if pwidget is None:
  775. return
  776. pwidget.sendNoteOn(channel, note)
  777. @pyqtSlot(int, int, int)
  778. def slot_handleNoteOff(self, pluginId, channel, note):
  779. if pluginId >= self.fPluginCount:
  780. return
  781. pwidget = self.fPluginList[pluginId]
  782. if pwidget is None:
  783. return
  784. pwidget.sendNoteOff(channel, note)
  785. @pyqtSlot(int, float, float, float, float)
  786. def slot_handleSetPeaks(self, pluginId, in1, in2, out1, out2):
  787. Carla.host._set_peaks(pluginId, in1, in2, out1, out2)
  788. @pyqtSlot()
  789. def slot_handleExit(self):
  790. self.removeAll()
  791. if self.lo_server:
  792. self.lo_server.stop()
  793. self.lo_server = None
  794. self.ui.act_file_refresh.setEnabled(False)
  795. global lo_target, lo_targetName
  796. lo_target = None
  797. lo_targetName = ""
  798. self.lo_address = ""
  799. def saveSettings(self):
  800. settings = QSettings()
  801. settings.setValue("Geometry", self.saveGeometry())
  802. #settings.setValue("ShowToolbar", self.ui.toolBar.isVisible())
  803. def loadSettings(self):
  804. settings = QSettings()
  805. self.restoreGeometry(settings.value("Geometry", ""))
  806. #showToolbar = settings.value("ShowToolbar", True, type=bool)
  807. #self.ui.act_settings_show_toolbar.setChecked(showToolbar)
  808. #self.ui.toolBar.setVisible(showToolbar)
  809. def timerEvent(self, event):
  810. if event.timerId() == self.fIdleTimerFast:
  811. for pwidget in self.fPluginList:
  812. if pwidget is None:
  813. break
  814. pwidget.idleFast()
  815. elif event.timerId() == self.fIdleTimerSlow:
  816. for pwidget in self.fPluginList:
  817. if pwidget is None:
  818. break
  819. pwidget.idleSlow()
  820. QMainWindow.timerEvent(self, event)
  821. def closeEvent(self, event):
  822. self.saveSettings()
  823. global lo_target
  824. if lo_target and self.lo_server:
  825. lo_send(lo_target, "/unregister")
  826. QMainWindow.closeEvent(self, event)
  827. #--------------- main ------------------
  828. if __name__ == '__main__':
  829. # App initialization
  830. app = QApplication(sys.argv)
  831. app.setApplicationName("Carla-Control")
  832. app.setApplicationVersion(VERSION)
  833. app.setOrganizationName("Cadence")
  834. app.setWindowIcon(QIcon(":/scalable/carla-control.svg"))
  835. libPrefix = None
  836. oscAddr = None
  837. argv = app.arguments()
  838. argc = len(argv)
  839. for i in range(argc):
  840. if i == 0: continue
  841. argument = argv[i]
  842. if argument.startswith("--with-libprefix="):
  843. libPrefix = argument.replace("--with-libprefix=", "")
  844. elif argument.startswith("osc."):
  845. oscAddr = argument
  846. if libPrefix is not None:
  847. libName = os.path.join(libPrefix, "lib", "carla", carla_libname)
  848. else:
  849. libName = carla_library_path
  850. # Load backend DLL, so it registers the theme
  851. libDLL = QLibrary()
  852. libDLL.setFileName(libName)
  853. try:
  854. libDLL.load()
  855. except:
  856. pass
  857. # Init backend (OSC bridge version)
  858. Carla.host = Host()
  859. # Create GUI
  860. Carla.gui = CarlaControlW(oscAddr)
  861. # Set-up custom signal handling
  862. setUpSignals()
  863. # Show GUI
  864. Carla.gui.show()
  865. # App-Loop
  866. ret = app.exec_()
  867. # Close backend DLL
  868. if libDLL.isLoaded():
  869. # Need to destroy app before theme
  870. del app
  871. libDLL.unload()
  872. sys.exit(ret)