Collection of tools useful for audio production
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.

491 lines
21KB

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # Carla Backend code
  4. # Copyright (C) 2011-2012 Filipe Coelho <falktx@gmail.com>
  5. #
  6. # This program is free software; you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation; either version 2 of the License, or
  9. # 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 COPYING file
  17. # Imports (Global)
  18. from PyQt4.QtGui import QApplication, QMainWindow
  19. from liblo import make_method, Address, ServerError, ServerThread
  20. from liblo import send as lo_send
  21. # Imports (Custom)
  22. import ui_carla_about, ui_carla_control, ui_carla_edit, ui_carla_parameter, ui_carla_plugin
  23. from shared_carla import *
  24. global carla_name, lo_target
  25. carla_name = ""
  26. lo_target = None
  27. Carla.isControl = True
  28. # OSC Control server
  29. class ControlServer(ServerThread):
  30. def __init__(self, parent):
  31. ServerThread.__init__(self, 8087)
  32. self.parent = parent
  33. def get_full_url(self):
  34. return "%scarla-control" % self.get_url()
  35. @make_method('/carla-control/add_plugin', 'is')
  36. def add_plugin_callback(self, path, args):
  37. pluginId, pluginName = args
  38. self.parent.emit(SIGNAL("AddPlugin(int, QString)"), pluginId, pluginName)
  39. @make_method('/carla-control/remove_plugin', 'i')
  40. def remove_plugin_callback(self, path, args):
  41. pluginId, = args
  42. self.parent.emit(SIGNAL("RemovePlugin(int)"), pluginId)
  43. @make_method('/carla-control/set_plugin_data', 'iiiissssh')
  44. def set_plugin_data_callback(self, path, args):
  45. pluginId, ptype, category, hints, realName, label, maker, copyright_, uniqueId = args
  46. self.parent.emit(SIGNAL("SetPluginData(int, int, int, int, QString, QString, QString, QString, long)"), pluginId, ptype, category, hints, realName, label, maker, copyright_, uniqueId)
  47. @make_method('/carla-control/set_plugin_ports', 'iiiiiiii')
  48. def set_plugin_ports_callback(self, path, args):
  49. pluginId, audioIns, audioOuts, midiIns, midiOuts, cIns, cOuts, cTotals = args
  50. self.parent.emit(SIGNAL("SetPluginPorts(int, int, int, int, int, int, int, int)"), pluginId, audioIns, audioOuts, midiIns, midiOuts, cIns, cOuts, cTotals)
  51. @make_method('/carla-control/set_parameter_data', 'iiiissd')
  52. def set_parameter_data_callback(self, path, args):
  53. pluginId, index, type_, hints, name, label, current = args
  54. self.parent.emit(SIGNAL("SetParameterData(int, int, int, int, QString, QString, double)"), pluginId, index, type_, hints, name, label, current)
  55. @make_method('/carla-control/set_parameter_ranges', 'iidddddd')
  56. def set_parameter_ranges_callback(self, path, args):
  57. pluginId, index, min_, max_, def_, step, stepSmall, stepLarge = args
  58. self.parent.emit(SIGNAL("SetParameterRanges(int, int, double, double, double, double, double, double, double)"), pluginId, index, min_, max_, def_, step, stepSmall, stepLarge)
  59. @make_method('/carla-control/set_parameter_midi_cc', 'iii')
  60. def set_parameter_midi_cc_callback(self, path, args):
  61. pluginId, index, cc = args
  62. self.parent.emit(SIGNAL("SetParameterMidiCC(int, int, int)"), pluginId, index, cc)
  63. @make_method('/carla-control/set_parameter_midi_channel', 'iii')
  64. def set_parameter_midi_channel_callback(self, path, args):
  65. pluginId, index, channel = args
  66. self.parent.emit(SIGNAL("SetParameterMidiChannel(int, int, int)"), pluginId, index, channel)
  67. @make_method('/carla-control/set_parameter_value', 'iid')
  68. def set_parameter_value_callback(self, path, args):
  69. pluginId, index, value = args
  70. self.parent.emit(SIGNAL("SetParameterValue(int, int, double)"), pluginId, index, value)
  71. @make_method('/carla-control/set_default_value', 'iid')
  72. def set_default_value_callback(self, path, args):
  73. pluginId, index, value = args
  74. self.parent.emit(SIGNAL("SetDefaultValue(int, int, double)"), pluginId, index, value)
  75. @make_method('/carla-control/set_program', 'ii')
  76. def set_program_callback(self, path, args):
  77. pluginId, index = args
  78. self.parent.emit(SIGNAL("SetProgram(int, int)"), pluginId, index)
  79. @make_method('/carla-control/set_program_count', 'ii')
  80. def set_program_count_callback(self, path, args):
  81. pluginId, count = args
  82. self.parent.emit(SIGNAL("SetProgramCount(int, int)"), pluginId, count)
  83. @make_method('/carla-control/set_program_name', 'iis')
  84. def set_program_name_callback(self, path, args):
  85. pluginId, index, name = args
  86. self.parent.emit(SIGNAL("SetProgramName(int, int, QString)"), pluginId, index, name)
  87. @make_method('/carla-control/set_midi_program', 'ii')
  88. def set_midi_program_callback(self, path, args):
  89. pluginId, index = args
  90. self.parent.emit(SIGNAL("SetMidiProgram(int, int)"), pluginId, index)
  91. @make_method('/carla-control/set_midi_program_count', 'ii')
  92. def set_midi_program_count_callback(self, path, args):
  93. pluginId, count = args
  94. self.parent.emit(SIGNAL("SetMidiProgram(int, int)"), pluginId, count)
  95. @make_method('/carla-control/set_midi_program_data', 'iiiiis')
  96. def set_midi_program_data_callback(self, path, args):
  97. pluginId, index, bank, program, name = args
  98. self.parent.emit(SIGNAL("SetMidiProgramName(int, int, int, int, int, QString)"), pluginId, index, bank, program, name)
  99. @make_method('/carla-control/set_input_peak_value', 'iid')
  100. def set_input_peak_value_callback(self, path, args):
  101. pluginId, portId, value = args
  102. self.parent.emit(SIGNAL("SetInputPeakValue(int, int, double)"), pluginId, portId, value)
  103. @make_method('/carla-control/set_output_peak_value', 'iid')
  104. def set_output_peak_value_callback(self, path, args):
  105. pluginId, portId, value = args
  106. self.parent.emit(SIGNAL("SetOutputPeakValue(int, int, double)"), pluginId, portId, value)
  107. @make_method('/carla-control/note_on', 'iiii')
  108. def note_on_callback(self, path, args):
  109. pluginId, channel, note, velo = args
  110. self.parent.emit(SIGNAL("NoteOn(int, int, int, int)"), pluginId, channel, note, velo)
  111. @make_method('/carla-control/note_off', 'iii')
  112. def note_off_callback(self, path, args):
  113. pluginId, channel, note = args
  114. self.parent.emit(SIGNAL("NoteOff(int, int, int)"), pluginId, channel, note)
  115. @make_method('/carla-control/exit', '')
  116. def exit_callback(self, path, args):
  117. self.parent.emit(SIGNAL("Exit()"))
  118. @make_method(None, None)
  119. def fallback(self, path, args):
  120. print("ControlServer::fallback(\"%s\") - unknown message, args =" % path, args)
  121. # Python Object class compatible to 'Host' on the Carla Backend code
  122. class Host(object):
  123. def __init__(self):
  124. super(Host, self).__init__()
  125. def set_active(self, plugin_id, onoff):
  126. global carla_name, to_target
  127. lo_path = "/%s/%i/set_active" % (carla_name, plugin_id)
  128. lo_send(lo_target, lo_path, 1 if onoff else 0)
  129. def set_drywet(self, plugin_id, value):
  130. global carla_name, to_target
  131. lo_path = "/%s/%i/set_drywet" % (carla_name, plugin_id)
  132. lo_send(lo_target, lo_path, value)
  133. def set_volume(self, plugin_id, value):
  134. global carla_name, to_target
  135. lo_path = "/%s/%i/set_volume" % (carla_name, plugin_id)
  136. lo_send(lo_target, lo_path, value)
  137. def set_balance_left(self, plugin_id, value):
  138. global carla_name, to_target
  139. lo_path = "/%s/%i/set_balance_left" % (carla_name, plugin_id)
  140. lo_send(lo_target, lo_path, value)
  141. def set_balance_right(self, plugin_id, value):
  142. global carla_name, to_target
  143. lo_path = "/%s/%i/set_balance_right" % (carla_name, plugin_id)
  144. lo_send(lo_target, lo_path, value)
  145. def set_parameter_value(self, plugin_id, parameter_id, value):
  146. global carla_name, to_target
  147. lo_path = "/%s/%i/set_parameter_value" % (carla_name, plugin_id)
  148. lo_send(lo_target, lo_path, parameter_id, value)
  149. def set_parameter_midi_cc(self, plugin_id, parameter_id, midi_cc):
  150. global carla_name, to_target
  151. lo_path = "/%s/%i/set_parameter_midi_cc" % (carla_name, plugin_id)
  152. lo_send(lo_target, lo_path, parameter_id, midi_cc)
  153. def set_parameter_midi_channel(self, plugin_id, parameter_id, channel):
  154. global carla_name, to_target
  155. lo_path = "/%s/%i/set_parameter_midi_channel" % (carla_name, plugin_id)
  156. lo_send(lo_target, lo_path, parameter_id, channel)
  157. def set_program(self, plugin_id, program_id):
  158. global carla_name, to_target
  159. lo_path = "/%s/%i/set_program" % (carla_name, plugin_id)
  160. lo_send(lo_target, lo_path, program_id)
  161. def set_midi_program(self, plugin_id, midi_program_id):
  162. global carla_name, to_target
  163. lo_path = "/%s/%i/set_midi_program" % (carla_name, plugin_id)
  164. lo_send(lo_target, lo_path, midi_program_id)
  165. def send_midi_note(self, plugin_id, channel, note, velocity):
  166. global carla_name, to_target
  167. if velocity:
  168. lo_path = "/%s/%i/note_on" % (carla_name, plugin_id)
  169. lo_send(lo_target, lo_path, channel, note, velocity)
  170. else:
  171. lo_path = "/%s/%i/note_off" % (carla_name, plugin_id)
  172. lo_send(lo_target, lo_path, channel, note)
  173. # About Carla Dialog
  174. class AboutW(QDialog, ui_carla_about.Ui_CarlaAboutW):
  175. def __init__(self, parent=None):
  176. super(AboutW, self).__init__(parent)
  177. self.setupUi(self)
  178. self.l_about.setText(self.tr(""
  179. "<br>Version %1"
  180. "<br>Carla is a Multi-Plugin Host for JACK - <b>OSC Bridge Version</b>.<br>"
  181. "<br>Copyright (C) 2011 falkTX<br>"
  182. "<br><i>VST is a trademark of Steinberg Media Technologies GmbH.</i>"
  183. "").arg(VERSION))
  184. self.tabWidget.removeTab(1)
  185. self.tabWidget.removeTab(1)
  186. # Main Window
  187. class CarlaControlW(QMainWindow, ui_carla_control.Ui_CarlaControlW):
  188. def __init__(self, parent=None):
  189. super(CarlaControlW, self).__init__(parent)
  190. self.setupUi(self)
  191. self.settings = QSettings("Cadence", "Carla-Control")
  192. self.loadSettings()
  193. self.lo_address = ""
  194. self.lo_server = None
  195. self.setStyleSheet("""
  196. QWidget#centralwidget {
  197. background-color: qlineargradient(spread:pad,
  198. x1:0.0, y1:0.0,
  199. x2:0.2, y2:1.0,
  200. stop:0 rgb( 7, 7, 7),
  201. stop:1 rgb(28, 28, 28)
  202. );
  203. }
  204. """)
  205. self.plugin_list = []
  206. for x in range(MAX_PLUGINS):
  207. self.plugin_list.append(None)
  208. self.act_file_refresh.setEnabled(False)
  209. self.resize(self.width(), 0)
  210. #self.connect(self.act_file_connect, SIGNAL("triggered()"), self.do_connect)
  211. #self.connect(self.act_file_refresh, SIGNAL("triggered()"), self.do_refresh)
  212. #self.connect(self.act_help_about, SIGNAL("triggered()"), self.aboutCarla)
  213. #self.connect(self.act_help_about_qt, SIGNAL("triggered()"), app, SLOT("aboutQt()"))
  214. #self.connect(self, SIGNAL("AddPluginCallback(int, QString)"), self.handleAddPluginCallback)
  215. #self.connect(self, SIGNAL("RemovePluginCallback(int)"), self.handleRemovePluginCallback)
  216. #self.connect(self, SIGNAL("SetPluginDataCallback(int, int, int, int, QString, QString, QString, QString, long)"), self.handleSetPluginDataCallback)
  217. #self.connect(self, SIGNAL("SetPluginPortsCallback(int, int, int, int, int, int, int, int)"), self.handleSetPluginPortsCallback)
  218. #self.connect(self, SIGNAL("SetParameterValueCallback(int, int, double)"), self.handleSetParameterCallback)
  219. #self.connect(self, SIGNAL("SetParameterDataCallback(int, int, int, int, QString, QString, double, double, double, double, double, double, double)"), self.handleSetParameterDataCallback)
  220. #self.connect(self, SIGNAL("SetDefaultValueCallback(int, int, double)"), self.handleSetDefaultValueCallback)
  221. #self.connect(self, SIGNAL("SetInputPeakValueCallback(int, int, double)"), self.handleSetInputPeakValueCallback)
  222. #self.connect(self, SIGNAL("SetOutputPeakValueCallback(int, int, double)"), self.handleSetOutputPeakValueCallback)
  223. #self.connect(self, SIGNAL("SetProgramCallback(int, int)"), self.handleSetProgramCallback)
  224. #self.connect(self, SIGNAL("SetProgramCountCallback(int, int)"), self.handleSetProgramCountCallback)
  225. #self.connect(self, SIGNAL("SetProgramNameCallback(int, int, QString)"), self.handleSetProgramNameCallback)
  226. #self.connect(self, SIGNAL("SetMidiProgramCallback(int, int)"), self.handleSetMidiProgramCallback)
  227. #self.connect(self, SIGNAL("SetMidiProgramCountCallback(int, int)"), self.handleSetMidiProgramCountCallback)
  228. #self.connect(self, SIGNAL("SetMidiProgramDataCallback(int, int, QString)"), self.handleSetMidiProgramDataCallback)
  229. #self.connect(self, SIGNAL("NoteOnCallback(int, int, int)"), self.handleNoteOnCallback)
  230. #self.connect(self, SIGNAL("NoteOffCallback(int, int, int)"), self.handleNoteOffCallback)
  231. #self.connect(self, SIGNAL("ExitCallback()"), self.handleExitCallback)
  232. #def do_connect(self):
  233. #global carla_name, lo_target
  234. #if (lo_target and self.lo_server):
  235. #url_text = self.lo_address
  236. #else:
  237. #url_text = "osc.udp://127.0.0.1:19000/Carla"
  238. #ans_value = QInputDialog.getText(self, self.tr("Carla Control - Connect"), self.tr("Address"), text=url_text)
  239. #if (ans_value[1]):
  240. #if (lo_target and self.lo_server):
  241. #lo_send(lo_target, "unregister")
  242. #self.act_file_refresh.setEnabled(True)
  243. #self.lo_address = QStringStr(ans_value[0])
  244. #lo_target = Address(self.lo_address)
  245. #carla_name = self.lo_address.rsplit("/", 1)[1]
  246. #print "connected to", self.lo_address, "as", carla_name
  247. #try:
  248. #self.lo_server = ControlServer(self)
  249. #except ServerError, err:
  250. #print str(err)
  251. #if (self.lo_server):
  252. #self.lo_server.start()
  253. #self.do_refresh()
  254. #else:
  255. #pass
  256. #def do_refresh(self):
  257. #global lo_target
  258. #if (lo_target and self.lo_server):
  259. #self.func_remove_all()
  260. #lo_send(lo_target, "unregister")
  261. #lo_send(lo_target, "register", self.lo_server.get_full_url())
  262. #def func_remove_all(self):
  263. #for i in range(MAX_PLUGINS):
  264. #if (self.plugin_list[i] != None):
  265. #self.handleRemovePluginCallback(i)
  266. #def handleAddPluginCallback(self, plugin_id, plugin_name):
  267. #pwidget = PluginWidget(self, plugin_id, plugin_name)
  268. #self.w_plugins.layout().addWidget(pwidget)
  269. #self.plugin_list[plugin_id] = pwidget
  270. #def handleRemovePluginCallback(self, plugin_id):
  271. #pwidget = self.plugin_list[plugin_id]
  272. #if (pwidget):
  273. #pwidget.edit_dialog.close()
  274. #pwidget.close()
  275. #pwidget.deleteLater()
  276. #self.w_plugins.layout().removeWidget(pwidget)
  277. #self.plugin_list[plugin_id] = None
  278. #def handleSetPluginDataCallback(self, plugin_id, ptype, category, hints, name, label, maker, copyright, unique_id):
  279. #pwidget = self.plugin_list[plugin_id]
  280. #if (pwidget):
  281. #pwidget.set_data(ptype, category, hints, name, label, maker, copyright, unique_id)
  282. #def handleSetPluginPortsCallback(self, plugin_id, ains, aouts, mins, mouts, cins, couts, ctotals):
  283. #pwidget = self.plugin_list[plugin_id]
  284. #if (pwidget):
  285. #pwidget.set_ports(ains, aouts, mins, mouts, cins, couts, ctotals)
  286. #def handleSetParameterCallback(self, plugin_id, parameter_id, value):
  287. #pwidget = self.plugin_list[plugin_id]
  288. #if (pwidget):
  289. #if (parameter_id < 0):
  290. #pwidget.parameter_activity_timer = ICON_STATE_ON
  291. #else:
  292. #for param in pwidget.edit_dialog.parameter_list:
  293. #if (param[1] == parameter_id):
  294. #if (param[0] == PARAMETER_INPUT):
  295. #pwidget.parameter_activity_timer = ICON_STATE_ON
  296. #break
  297. #if (parameter_id == PARAMETER_ACTIVE):
  298. #pwidget.set_active((value > 0.0), True, False)
  299. #elif (parameter_id == PARAMETER_DRYWET):
  300. #pwidget.set_drywet(value*1000, True, False)
  301. #elif (parameter_id == PARAMETER_VOLUME):
  302. #pwidget.set_vol(value*1000, True, False)
  303. #elif (parameter_id == PARAMETER_BALANCE_LEFT):
  304. #pwidget.set_balance_left(value*1000, True, False)
  305. #elif (parameter_id == PARAMETER_BALANCE_RIGHT):
  306. #pwidget.set_balance_right(value*1000, True, False)
  307. #elif (parameter_id >= 0):
  308. #pwidget.edit_dialog.set_parameter_value(parameter_id, value)
  309. #def handleSetParameterDataCallback(self, plugin_id, param_id, ptype, hints, name, label, current, x_min, x_max, x_def, x_step, x_step_small, x_step_large):
  310. #pwidget = self.plugin_list[plugin_id]
  311. #if (pwidget):
  312. #pwidget.edit_dialog.set_parameter_data(param_id, ptype, hints, name, label, current, x_min, x_max, x_def, x_step, x_step_small, x_step_large)
  313. #def handleSetDefaultValueCallback(self, plugin_id, param_id, value):
  314. #pwidget = self.plugin_list[plugin_id]
  315. #if (pwidget):
  316. #pwidget.edit_dialog.set_parameter_default_value(param_id, value)
  317. #def handleSetInputPeakValueCallback(self, plugin_id, port_id, value):
  318. #pwidget = self.plugin_list[plugin_id]
  319. #if (pwidget):
  320. #pwidget.set_input_peak_value(port_id, value)
  321. #def handleSetOutputPeakValueCallback(self, plugin_id, port_id, value):
  322. #pwidget = self.plugin_list[plugin_id]
  323. #if (pwidget):
  324. #pwidget.set_output_peak_value(port_id, value)
  325. #def handleSetProgramCallback(self, plugin_id, program_id):
  326. #pwidget = self.plugin_list[plugin_id]
  327. #if (pwidget):
  328. #pwidget.edit_dialog.set_program(program_id)
  329. #def handleSetProgramCountCallback(self, plugin_id, program_count):
  330. #pwidget = self.plugin_list[plugin_id]
  331. #if (pwidget):
  332. #pwidget.edit_dialog.set_program_count(program_count)
  333. #def handleSetProgramNameCallback(self, plugin_id, program_id, program_name):
  334. #pwidget = self.plugin_list[plugin_id]
  335. #if (pwidget):
  336. #pwidget.edit_dialog.set_program_name(program_id, program_name)
  337. #def handleSetMidiProgramCallback(self, plugin_id, midi_program_id):
  338. #pwidget = self.plugin_list[plugin_id]
  339. #if (pwidget):
  340. #pwidget.edit_dialog.set_midi_program(midi_program_id)
  341. #def handleSetMidiProgramCountCallback(self, plugin_id, midi_program_count):
  342. #pwidget = self.plugin_list[plugin_id]
  343. #if (pwidget):
  344. #pwidget.edit_dialog.set_midi_program_count(midi_program_count)
  345. #def handleSetMidiProgramDataCallback(self, plugin_id, midi_program_id, bank_id, program_id, midi_program_name):
  346. #pwidget = self.plugin_list[plugin_id]
  347. #if (pwidget):
  348. #pwidget.edit_dialog.set_midi_program_data(midi_program_id, bank_id, program_id, midi_program_name)
  349. #def handleNoteOnCallback(self, plugin_id, note, velo):
  350. #pwidget = self.plugin_list[plugin_id]
  351. #if (pwidget):
  352. #pwidget.edit_dialog.keyboard.noteOn(note, False)
  353. #def handleNoteOffCallback(self, plugin_id, note, velo):
  354. #pwidget = self.plugin_list[plugin_id]
  355. #if (pwidget):
  356. #pwidget.edit_dialog.keyboard.noteOff(note, False)
  357. #def handleExitCallback(self):
  358. #self.func_remove_all()
  359. #self.act_file_refresh.setEnabled(False)
  360. #global carla_name, lo_target
  361. #carla_name = ""
  362. #lo_target = None
  363. #self.lo_address = ""
  364. #def aboutCarla(self):
  365. #AboutW(self).exec_()
  366. def saveSettings(self):
  367. self.settings.setValue("Geometry", self.saveGeometry())
  368. def loadSettings(self):
  369. self.restoreGeometry(self.settings.value("Geometry", ""))
  370. def closeEvent(self, event):
  371. self.saveSettings()
  372. global lo_target
  373. if lo_target and self.lo_server:
  374. lo_send(lo_target, "unregister")
  375. QMainWindow.closeEvent(self, event)
  376. #--------------- main ------------------
  377. if __name__ == '__main__':
  378. # App initialization
  379. app = QApplication(sys.argv)
  380. app.setApplicationName("Carla-Control")
  381. app.setApplicationVersion(VERSION)
  382. app.setOrganizationName("falkTX")
  383. app.setWindowIcon(QIcon(":/48x48/carla-control.png"))
  384. #style = app.style().metaObject().className()
  385. #force_parameters_style = (style in ["Bespin::Style"])
  386. CarlaHost = Host()
  387. # Show GUI
  388. gui = CarlaControlW()
  389. gui.show()
  390. # Set-up custom signal handling
  391. set_up_signals(gui)
  392. # App-Loop
  393. sys.exit(app.exec_())