#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Carla plugin host # Copyright (C) 2011-2013 Filipe Coelho # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # For a full copy of the GNU General Public License see the GPL.txt file # ------------------------------------------------------------------------------------------------------------ # Imports (Global) from PyQt4.QtCore import Qt, QPointF, QSize from PyQt4.QtGui import QApplication, QDialogButtonBox, QMainWindow, QResizeEvent # ------------------------------------------------------------------------------------------------------------ # Imports (Custom Stuff) import patchcanvas import ui_carla import ui_carla_settings from carla_backend import * # FIXME, remove later from carla_shared import * # ------------------------------------------------------------------------------------------------------------ # Try Import OpenGL try: from PyQt4.QtOpenGL import QGLWidget hasGL = True except: hasGL = False # ------------------------------------------------------------------------------------------------------------ # Static Variables DEFAULT_CANVAS_WIDTH = 3100 DEFAULT_CANVAS_HEIGHT = 2400 # Tab indexes TAB_INDEX_MAIN = 0 TAB_INDEX_CANVAS = 1 TAB_INDEX_CARLA_ENGINE = 2 TAB_INDEX_CARLA_PATHS = 3 TAB_INDEX_NONE = 4 # Single and Multiple client mode is only for JACK, # but we still want to match QComboBox index to defines, # so add +2 pos padding if driverName != "JACK". PROCESS_MODE_NON_JACK_PADDING = 2 # Carla defaults CARLA_DEFAULT_PROCESS_HIGH_PRECISION = False CARLA_DEFAULT_MAX_PARAMETERS = 200 CARLA_DEFAULT_FORCE_STEREO = False CARLA_DEFAULT_USE_DSSI_VST_CHUNKS = False CARLA_DEFAULT_PREFER_PLUGIN_BRIDGES = False CARLA_DEFAULT_PREFER_UI_BRIDGES = True CARLA_DEFAULT_OSC_UI_TIMEOUT = 4000 CARLA_DEFAULT_DISABLE_CHECKS = False # PatchCanvas defines CANVAS_ANTIALIASING_SMALL = 1 CANVAS_EYECANDY_SMALL = 1 # ------------------------------------------------------------------------------------------------------------ # Settings Dialog class CarlaSettingsW(QDialog): def __init__(self, parent): QDialog.__init__(self, parent) self.ui = ui_carla_settings.Ui_CarlaSettingsW() self.ui.setupUi(self) # TODO self.ui.lw_page.hideRow(TAB_INDEX_CANVAS) # ------------------------------------------------------------- # Load settings self.loadSettings() # ------------------------------------------------------------- # Set-up GUI driverCount = Carla.host.get_engine_driver_count() for i in range(driverCount): driverName = cString(Carla.host.get_engine_driver_name(i)) self.ui.cb_engine_audio_driver.addItem(driverName) #if not hasOpenGL: #self.cb_canvas_use_opengl.setChecked(False) #self.cb_canvas_use_opengl.setEnabled(False) # ------------------------------------------------------------- # Set-up connections self.connect(self, SIGNAL("accepted()"), SLOT("slot_saveSettings()")) self.connect(self.ui.buttonBox.button(QDialogButtonBox.Reset), SIGNAL("clicked()"), SLOT("slot_resetSettings()")) self.connect(self.ui.b_main_def_folder_open, SIGNAL("clicked()"), SLOT("slot_getAndSetProjectPath()")) self.connect(self.ui.cb_engine_audio_driver, SIGNAL("currentIndexChanged(int)"), SLOT("slot_engineAudioDriverChanged()")) self.connect(self.ui.b_paths_add, SIGNAL("clicked()"), SLOT("slot_addPluginPath()")) self.connect(self.ui.b_paths_remove, SIGNAL("clicked()"), SLOT("slot_removePluginPath()")) self.connect(self.ui.b_paths_change, SIGNAL("clicked()"), SLOT("slot_changePluginPath()")) self.connect(self.ui.tw_paths, SIGNAL("currentChanged(int)"), SLOT("slot_pluginPathTabChanged(int)")) self.connect(self.ui.lw_ladspa, SIGNAL("currentRowChanged(int)"), SLOT("slot_pluginPathRowChanged(int)")) self.connect(self.ui.lw_dssi, SIGNAL("currentRowChanged(int)"), SLOT("slot_pluginPathRowChanged(int)")) self.connect(self.ui.lw_lv2, SIGNAL("currentRowChanged(int)"), SLOT("slot_pluginPathRowChanged(int)")) self.connect(self.ui.lw_vst, SIGNAL("currentRowChanged(int)"), SLOT("slot_pluginPathRowChanged(int)")) self.connect(self.ui.lw_sf2, SIGNAL("currentRowChanged(int)"), SLOT("slot_pluginPathRowChanged(int)")) # ------------------------------------------------------------- # Post-connect setup self.ui.lw_ladspa.setCurrentRow(0) self.ui.lw_dssi.setCurrentRow(0) self.ui.lw_lv2.setCurrentRow(0) self.ui.lw_vst.setCurrentRow(0) self.ui.lw_gig.setCurrentRow(0) self.ui.lw_sf2.setCurrentRow(0) self.ui.lw_sfz.setCurrentRow(0) #QTimer.singleShot(0, self, ) #self.slot_pluginPathTabChanged(self.tw_paths.currentIndex()) self.ui.lw_page.setCurrentCell(0, 0) def loadSettings(self): settings = QSettings() # --------------------------------------- self.ui.le_main_def_folder.setText(settings.value("Main/DefaultProjectFolder", HOME, type=str)) self.ui.sb_gui_refresh.setValue(settings.value("Main/RefreshInterval", 50, type=int)) # --------------------------------------- self.ui.cb_canvas_hide_groups.setChecked(settings.value("Canvas/AutoHideGroups", False, type=bool)) self.ui.cb_canvas_bezier_lines.setChecked(settings.value("Canvas/UseBezierLines", True, type=bool)) self.ui.cb_canvas_eyecandy.setCheckState(settings.value("Canvas/EyeCandy", CANVAS_EYECANDY_SMALL, type=int)) self.ui.cb_canvas_use_opengl.setChecked(settings.value("Canvas/UseOpenGL", False, type=bool)) self.ui.cb_canvas_render_aa.setCheckState(settings.value("Canvas/Antialiasing", CANVAS_ANTIALIASING_SMALL, type=int)) self.ui.cb_canvas_render_hq_aa.setChecked(settings.value("Canvas/HighQualityAntialiasing", False, type=bool)) #themeName = settings.value("Canvas/Theme", getDefaultThemeName(), type=str) #for i in range(Theme.THEME_MAX): #thisThemeName = getThemeName(i) #self.ui.cb_canvas_theme.addItem(thisThemeName) #if thisThemeName == themeName: #self.ui.cb_canvas_theme.setCurrentIndex(i) # -------------------------------------------- audioDriver = settings.value("Engine/AudioDriver", "JACK", type=str) for i in range(self.ui.cb_engine_audio_driver.count()): if self.ui.cb_engine_audio_driver.itemText(i) == audioDriver: self.ui.cb_engine_audio_driver.setCurrentIndex(i) break else: self.ui.cb_engine_audio_driver.setCurrentIndex(-1) if audioDriver == "JACK": processModeIndex = settings.value("Engine/ProcessMode", PROCESS_MODE_MULTIPLE_CLIENTS, type=int) self.ui.cb_engine_process_mode_jack.setCurrentIndex(processModeIndex) self.ui.sw_engine_process_mode.setCurrentIndex(0) else: processModeIndex = settings.value("Engine/ProcessMode", PROCESS_MODE_CONTINUOUS_RACK, type=int) processModeIndex -= PROCESS_MODE_NON_JACK_PADDING self.ui.cb_engine_process_mode_other.setCurrentIndex(processModeIndex) self.ui.sw_engine_process_mode.setCurrentIndex(1) self.ui.sb_engine_max_params.setValue(settings.value("Engine/MaxParameters", CARLA_DEFAULT_MAX_PARAMETERS, type=int)) self.ui.ch_engine_prefer_ui_bridges.setChecked(settings.value("Engine/PreferUiBridges", CARLA_DEFAULT_PREFER_UI_BRIDGES, type=bool)) self.ui.sb_engine_oscgui_timeout.setValue(settings.value("Engine/OscUiTimeout", CARLA_DEFAULT_OSC_UI_TIMEOUT, type=int)) self.ui.ch_engine_disable_checks.setChecked(settings.value("Engine/DisableChecks", CARLA_DEFAULT_DISABLE_CHECKS, type=bool)) self.ui.ch_engine_dssi_chunks.setChecked(settings.value("Engine/UseDssiVstChunks", CARLA_DEFAULT_USE_DSSI_VST_CHUNKS, type=bool)) self.ui.ch_engine_prefer_plugin_bridges.setChecked(settings.value("Engine/PreferPluginBridges", CARLA_DEFAULT_PREFER_PLUGIN_BRIDGES, type=bool)) self.ui.ch_engine_force_stereo.setChecked(settings.value("Engine/ForceStereo", CARLA_DEFAULT_FORCE_STEREO, type=bool)) # -------------------------------------------- ladspas = toList(settings.value("Paths/LADSPA", Carla.LADSPA_PATH)) dssis = toList(settings.value("Paths/DSSI", Carla.DSSI_PATH)) lv2s = toList(settings.value("Paths/LV2", Carla.LV2_PATH)) vsts = toList(settings.value("Paths/VST", Carla.VST_PATH)) gigs = toList(settings.value("Paths/GIG", Carla.GIG_PATH)) sf2s = toList(settings.value("Paths/SF2", Carla.SF2_PATH)) sfzs = toList(settings.value("Paths/SFZ", Carla.SFZ_PATH)) ladspas.sort() dssis.sort() lv2s.sort() vsts.sort() gigs.sort() sf2s.sort() sfzs.sort() for ladspa in ladspas: self.ui.lw_ladspa.addItem(ladspa) for dssi in dssis: self.ui.lw_dssi.addItem(dssi) for lv2 in lv2s: self.ui.lw_lv2.addItem(lv2) for vst in vsts: self.ui.lw_vst.addItem(vst) for gig in gigs: self.ui.lw_gig.addItem(gig) for sf2 in sf2s: self.ui.lw_sf2.addItem(sf2) for sfz in sfzs: self.ui.lw_sfz.addItem(sfz) @pyqtSlot() def slot_saveSettings(self): settings = QSettings() # --------------------------------------- settings.setValue("Main/RefreshInterval", self.ui.sb_gui_refresh.value()) settings.setValue("Main/DefaultProjectFolder", self.ui.le_main_def_folder.text()) # --------------------------------------- #settings.setValue("Canvas/Theme", self.ui.cb_canvas_theme.currentText()) #settings.setValue("Canvas/AutoHideGroups", self.ui.cb_canvas_hide_groups.isChecked()) #settings.setValue("Canvas/UseBezierLines", self.ui.cb_canvas_bezier_lines.isChecked()) #settings.setValue("Canvas/UseOpenGL", self.ui.cb_canvas_use_opengl.isChecked()) #settings.setValue("Canvas/HighQualityAntialiasing", self.ui.cb_canvas_render_hq_aa.isChecked()) ## 0, 1, 2 match their enum variants #settings.setValue("Canvas/EyeCandy", self.ui.cb_canvas_eyecandy.checkState()) #settings.setValue("Canvas/Antialiasing", self.ui.cb_canvas_render_aa.checkState()) # -------------------------------------------- audioDriver = self.ui.cb_engine_audio_driver.currentText() settings.setValue("Engine/AudioDriver", audioDriver) if audioDriver == "JACK": settings.setValue("Engine/ProcessMode", self.ui.cb_engine_process_mode_jack.currentIndex()) else: settings.setValue("Engine/ProcessMode", self.ui.cb_engine_process_mode_other.currentIndex()+PROCESS_MODE_NON_JACK_PADDING) settings.setValue("Engine/MaxParameters", self.ui.sb_engine_max_params.value()) settings.setValue("Engine/PreferUiBridges", self.ui.ch_engine_prefer_ui_bridges.isChecked()) settings.setValue("Engine/OscUiTimeout", self.ui.sb_engine_oscgui_timeout.value()) settings.setValue("Engine/DisableChecks", self.ui.ch_engine_disable_checks.isChecked()) settings.setValue("Engine/UseDssiVstChunks", self.ui.ch_engine_dssi_chunks.isChecked()) settings.setValue("Engine/PreferPluginBridges", self.ui.ch_engine_prefer_plugin_bridges.isChecked()) settings.setValue("Engine/ForceStereo", self.ui.ch_engine_force_stereo.isChecked()) # -------------------------------------------- # FIXME - find a cleaner way to do this, *.items() ? ladspas = [] dssis = [] lv2s = [] vsts = [] gigs = [] sf2s = [] sfzs = [] for i in range(self.ui.lw_ladspa.count()): ladspas.append(self.ui.lw_ladspa.item(i).text()) for i in range(self.ui.lw_dssi.count()): dssis.append(self.ui.lw_dssi.item(i).text()) for i in range(self.ui.lw_lv2.count()): lv2s.append(self.ui.lw_lv2.item(i).text()) for i in range(self.ui.lw_vst.count()): vsts.append(self.ui.lw_vst.item(i).text()) for i in range(self.ui.lw_gig.count()): gigs.append(self.ui.lw_gig.item(i).text()) for i in range(self.ui.lw_sf2.count()): sf2s.append(self.ui.lw_sf2.item(i).text()) for i in range(self.ui.lw_sfz.count()): sfzs.append(self.ui.lw_sfz.item(i).text()) settings.setValue("Paths/LADSPA", ladspas) settings.setValue("Paths/DSSI", dssis) settings.setValue("Paths/LV2", lv2s) settings.setValue("Paths/VST", vsts) settings.setValue("Paths/GIG", gigs) settings.setValue("Paths/SF2", sf2s) settings.setValue("Paths/SFZ", sfzs) @pyqtSlot() def slot_resetSettings(self): if self.ui.lw_page.currentRow() == TAB_INDEX_MAIN: self.ui.le_main_def_folder.setText(HOME) self.ui.sb_gui_refresh.setValue(50) elif self.ui.lw_page.currentRow() == TAB_INDEX_CANVAS: self.ui.cb_canvas_theme.setCurrentIndex(0) self.ui.cb_canvas_hide_groups.setChecked(False) self.ui.cb_canvas_bezier_lines.setChecked(True) self.ui.cb_canvas_eyecandy.setCheckState(Qt.PartiallyChecked) self.ui.cb_canvas_use_opengl.setChecked(False) self.ui.cb_canvas_render_aa.setCheckState(Qt.PartiallyChecked) self.ui.cb_canvas_render_hq_aa.setChecked(False) elif self.ui.lw_page.currentRow() == TAB_INDEX_CARLA_ENGINE: self.ui.cb_engine_audio_driver.setCurrentIndex(0) self.ui.sb_engine_max_params.setValue(CARLA_DEFAULT_MAX_PARAMETERS) self.ui.ch_engine_prefer_ui_bridges.setChecked(CARLA_DEFAULT_PREFER_UI_BRIDGES) self.ui.sb_engine_oscgui_timeout.setValue(CARLA_DEFAULT_OSC_UI_TIMEOUT) self.ui.ch_engine_disable_checks.setChecked(CARLA_DEFAULT_DISABLE_CHECKS) self.ui.ch_engine_dssi_chunks.setChecked(CARLA_DEFAULT_USE_DSSI_VST_CHUNKS) self.ui.ch_engine_prefer_plugin_bridges.setChecked(CARLA_DEFAULT_PREFER_PLUGIN_BRIDGES) self.ui.ch_engine_force_stereo.setChecked(CARLA_DEFAULT_FORCE_STEREO) if self.ui.cb_engine_audio_driver.currentText() == "JACK": self.ui.cb_engine_process_mode_jack.setCurrentIndex(PROCESS_MODE_MULTIPLE_CLIENTS) self.ui.sw_engine_process_mode.setCurrentIndex(0) else: self.ui.cb_engine_process_mode_other.setCurrentIndex(PROCESS_MODE_CONTINUOUS_RACK-PROCESS_MODE_NON_JACK_PADDING) self.ui.sw_engine_process_mode.setCurrentIndex(1) elif self.ui.lw_page.currentRow() == TAB_INDEX_CARLA_PATHS: if self.ui.tw_paths.currentIndex() == 0: Carla.LADSPA_PATH.sort() self.ui.lw_ladspa.clear() for ladspa in Carla.LADSPA_PATH: self.ui.lw_ladspa.addItem(ladspa) elif self.ui.tw_paths.currentIndex() == 1: Carla.DSSI_PATH.sort() self.ui.lw_dssi.clear() for dssi in Carla.DSSI_PATH: self.ui.lw_dssi.addItem(dssi) elif self.ui.tw_paths.currentIndex() == 2: Carla.LV2_PATH.sort() self.ui.lw_lv2.clear() for lv2 in Carla.LV2_PATH: self.ui.lw_lv2.addItem(lv2) elif self.ui.tw_paths.currentIndex() == 3: Carla.VST_PATH.sort() self.ui.lw_vst.clear() for vst in Carla.VST_PATH: self.ui.lw_vst.addItem(vst) elif self.ui.tw_paths.currentIndex() == 4: Carla.GIG_PATH.sort() self.ui.lw_gig.clear() for gig in Carla.GIG_PATH: self.ui.lw_gig.addItem(gig) elif self.ui.tw_paths.currentIndex() == 5: Carla.SF2_PATH.sort() self.ui.lw_sf2.clear() for sf2 in Carla.SF2_PATH: self.ui.lw_sf2.addItem(sf2) elif self.ui.tw_paths.currentIndex() == 6: Carla.SFZ_PATH.sort() self.ui.lw_sfz.clear() for sfz in Carla.SFZ_PATH: self.ui.lw_sfz.addItem(sfz) @pyqtSlot() def slot_getAndSetProjectPath(self): pass #getAndSetPath(self, self.le_main_def_folder.text(), self.le_main_def_folder) @pyqtSlot() def slot_engineAudioDriverChanged(self): if self.ui.cb_engine_audio_driver.currentText() == "JACK": self.ui.sw_engine_process_mode.setCurrentIndex(0) else: self.ui.sw_engine_process_mode.setCurrentIndex(1) @pyqtSlot() def slot_addPluginPath(self): newPath = QFileDialog.getExistingDirectory(self, self.tr("Add Path"), "", QFileDialog.ShowDirsOnly) if newPath: if self.ui.tw_paths.currentIndex() == 0: self.ui.lw_ladspa.addItem(newPath) elif self.ui.tw_paths.currentIndex() == 1: self.ui.lw_dssi.addItem(newPath) elif self.ui.tw_paths.currentIndex() == 2: self.ui.lw_lv2.addItem(newPath) elif self.ui.tw_paths.currentIndex() == 3: self.ui.lw_vst.addItem(newPath) elif self.ui.tw_paths.currentIndex() == 4: self.ui.lw_gig.addItem(newPath) elif self.ui.tw_paths.currentIndex() == 5: self.ui.lw_sf2.addItem(newPath) elif self.ui.tw_paths.currentIndex() == 6: self.ui.lw_sfz.addItem(newPath) @pyqtSlot() def slot_removePluginPath(self): if self.ui.tw_paths.currentIndex() == 0: self.ui.lw_ladspa.takeItem(self.ui.lw_ladspa.currentRow()) elif self.ui.tw_paths.currentIndex() == 1: self.ui.lw_dssi.takeItem(self.ui.lw_dssi.currentRow()) elif self.ui.tw_paths.currentIndex() == 2: self.ui.lw_lv2.takeItem(self.ui.lw_lv2.currentRow()) elif self.ui.tw_paths.currentIndex() == 3: self.ui.lw_vst.takeItem(self.ui.lw_vst.currentRow()) elif self.ui.tw_paths.currentIndex() == 4: self.ui.lw_gig.takeItem(self.ui.lw_gig.currentRow()) elif self.ui.tw_paths.currentIndex() == 5: self.ui.lw_sf2.takeItem(self.ui.lw_sf2.currentRow()) elif self.ui.tw_paths.currentIndex() == 6: self.ui.lw_sfz.takeItem(self.ui.lw_sfz.currentRow()) @pyqtSlot() def slot_changePluginPath(self): if self.ui.tw_paths.currentIndex() == 0: currentPath = self.ui.lw_ladspa.currentItem().text() elif self.ui.tw_paths.currentIndex() == 1: currentPath = self.ui.lw_dssi.currentItem().text() elif self.ui.tw_paths.currentIndex() == 2: currentPath = self.ui.lw_lv2.currentItem().text() elif self.ui.tw_paths.currentIndex() == 3: currentPath = self.ui.lw_vst.currentItem().text() elif self.ui.tw_paths.currentIndex() == 4: currentPath = self.ui.lw_gig.currentItem().text() elif self.ui.tw_paths.currentIndex() == 5: currentPath = self.ui.lw_sf2.currentItem().text() elif self.ui.tw_paths.currentIndex() == 6: currentPath = self.ui.lw_sfz.currentItem().text() else: currentPath = "" newPath = QFileDialog.getExistingDirectory(self, self.tr("Add Path"), currentPath, QFileDialog.ShowDirsOnly) if newPath: if self.ui.tw_paths.currentIndex() == 0: self.ui.lw_ladspa.currentItem().setText(newPath) elif self.ui.tw_paths.currentIndex() == 1: self.ui.lw_dssi.currentItem().setText(newPath) elif self.ui.tw_paths.currentIndex() == 2: self.ui.lw_lv2.currentItem().setText(newPath) elif self.ui.tw_paths.currentIndex() == 3: self.ui.lw_vst.currentItem().setText(newPath) elif self.ui.tw_paths.currentIndex() == 4: self.ui.lw_gig.currentItem().setText(newPath) elif self.ui.tw_paths.currentIndex() == 5: self.ui.lw_sf2.currentItem().setText(newPath) elif self.ui.tw_paths.currentIndex() == 6: self.ui.lw_sfz.currentItem().setText(newPath) @pyqtSlot(int) def slot_pluginPathTabChanged(self, index): if index == 0: row = self.ui.lw_ladspa.currentRow() elif index == 1: row = self.ui.lw_dssi.currentRow() elif index == 2: row = self.ui.lw_lv2.currentRow() elif index == 3: row = self.ui.lw_vst.currentRow() elif index == 4: row = self.ui.lw_gig.currentRow() elif index == 5: row = self.ui.lw_sf2.currentRow() elif index == 6: row = self.ui.lw_sfz.currentRow() else: row = -1 check = bool(row >= 0) self.ui.b_paths_remove.setEnabled(check) self.ui.b_paths_change.setEnabled(check) @pyqtSlot(int) def slot_pluginPathRowChanged(self, row): check = bool(row >= 0) self.ui.b_paths_remove.setEnabled(check) self.ui.b_paths_change.setEnabled(check) def done(self, r): QDialog.done(self, r) self.close() # ------------------------------------------------------------------------------------------------------------ # Main Window class CarlaMainW(QMainWindow): def __init__(self, parent=None): QMainWindow.__init__(self, parent) self.ui = ui_carla.Ui_CarlaMainW() self.ui.setupUi(self) # ------------------------------------------------------------- # Load Settings self.loadSettings(True) self.loadRDFs() self.setStyleSheet(""" QWidget#w_plugins { background-color: qlineargradient(spread:pad, x1:0.0, y1:0.0, x2:0.2, y2:1.0, stop:0 rgb( 7, 7, 7), stop:1 rgb(28, 28, 28) ); } """) # ------------------------------------------------------------- # Internal stuff self.fEngineStarted = False self.fFirstEngineInit = False self.fProjectFilename = None self.fProjectLoading = False self.fPluginCount = 0 self.fPluginList = [] self.fIdleTimerFast = 0 self.fIdleTimerSlow = 0 #self._nsmAnnounce2str = "" #self._nsmOpen1str = "" #self._nsmOpen2str = "" #self.nsm_server = None #self.nsm_url = None # ------------------------------------------------------------- # Set-up GUI stuff self.ui.act_engine_start.setEnabled(False) self.ui.act_engine_stop.setEnabled(False) self.ui.act_plugin_remove_all.setEnabled(False) # FIXME: Qt4 needs this so it properly create & resize the canvas self.ui.tabWidget.setCurrentIndex(1) self.ui.tabWidget.setCurrentIndex(0) # ------------------------------------------------------------- # Set-up Canvas self.scene = patchcanvas.PatchScene(self, self.ui.graphicsView) self.ui.graphicsView.setScene(self.scene) #self.ui.graphicsView.setRenderHint(QPainter.Antialiasing, bool(self.fSavedSettings["Canvas/Antialiasing"] == patchcanvas.ANTIALIASING_FULL)) #if self.fSavedSettings["Canvas/UseOpenGL"] and hasGL: #self.ui.graphicsView.setViewport(QGLWidget(self.ui.graphicsView)) #self.ui.graphicsView.setRenderHint(QPainter.HighQualityAntialiasing, self.fSavedSettings["Canvas/HighQualityAntialiasing"]) pOptions = patchcanvas.options_t() pOptions.theme_name = self.fSavedSettings["Canvas/Theme"] pOptions.auto_hide_groups = self.fSavedSettings["Canvas/AutoHideGroups"] pOptions.use_bezier_lines = self.fSavedSettings["Canvas/UseBezierLines"] pOptions.antialiasing = self.fSavedSettings["Canvas/Antialiasing"] pOptions.eyecandy = self.fSavedSettings["Canvas/EyeCandy"] pFeatures = patchcanvas.features_t() pFeatures.group_info = False pFeatures.group_rename = False pFeatures.port_info = False pFeatures.port_rename = False pFeatures.handle_group_pos = True patchcanvas.setOptions(pOptions) patchcanvas.setFeatures(pFeatures) patchcanvas.init("Carla", self.scene, canvasCallback, False) patchcanvas.setCanvasSize(0, 0, DEFAULT_CANVAS_WIDTH, DEFAULT_CANVAS_HEIGHT) patchcanvas.setInitialPos(DEFAULT_CANVAS_WIDTH / 2, DEFAULT_CANVAS_HEIGHT / 2) self.ui.graphicsView.setSceneRect(0, 0, DEFAULT_CANVAS_WIDTH, DEFAULT_CANVAS_HEIGHT) # ------------------------------------------------------------- # Set-up Canvas Preview self.ui.miniCanvasPreview.setRealParent(self) self.ui.miniCanvasPreview.setViewTheme(patchcanvas.canvas.theme.canvas_bg, patchcanvas.canvas.theme.rubberband_brush, patchcanvas.canvas.theme.rubberband_pen.color()) self.ui.miniCanvasPreview.init(self.scene, DEFAULT_CANVAS_WIDTH, DEFAULT_CANVAS_HEIGHT) QTimer.singleShot(100, self, SLOT("slot_miniCanvasInit()")) #self.m_fakeEdit = PluginEdit(self, -1) #self.m_curEdit = self.m_fakeEdit #self.w_edit.layout().addWidget(self.m_curEdit) #self.w_edit.layout().addStretch() # ------------------------------------------------------------- # Connect actions to functions self.connect(self.ui.act_file_new, SIGNAL("triggered()"), SLOT("slot_fileNew()")) self.connect(self.ui.act_file_open, SIGNAL("triggered()"), SLOT("slot_fileOpen()")) self.connect(self.ui.act_file_save, SIGNAL("triggered()"), SLOT("slot_fileSave()")) self.connect(self.ui.act_file_save_as, SIGNAL("triggered()"), SLOT("slot_fileSaveAs()")) self.connect(self.ui.act_engine_start, SIGNAL("triggered()"), SLOT("slot_engineStart()")) self.connect(self.ui.act_engine_stop, SIGNAL("triggered()"), SLOT("slot_engineStop()")) self.connect(self.ui.act_plugin_add, SIGNAL("triggered()"), SLOT("slot_pluginAdd()")) self.connect(self.ui.act_plugin_remove_all, SIGNAL("triggered()"), SLOT("slot_pluginRemoveAll()")) self.connect(self.ui.act_settings_configure, SIGNAL("triggered()"), SLOT("slot_configureCarla()")) self.connect(self.ui.act_help_about, SIGNAL("triggered()"), SLOT("slot_aboutCarla()")) self.connect(self.ui.act_help_about_qt, SIGNAL("triggered()"), app, SLOT("aboutQt()")) self.connect(self.ui.ch_transport, SIGNAL("currentIndexChanged(int)"), SLOT("slot_transportModeChanged(int)")) self.connect(self.ui.b_transport_play, SIGNAL("clicked(bool)"), SLOT("slot_transportPlayPause(bool)")) self.connect(self.ui.b_transport_stop, SIGNAL("clicked()"), SLOT("slot_transportStop()")) self.connect(self.ui.miniCanvasPreview, SIGNAL("miniCanvasMoved(double, double)"), SLOT("slot_miniCanvasMoved(double, double)")) self.connect(self.ui.graphicsView.horizontalScrollBar(), SIGNAL("valueChanged(int)"), SLOT("slot_horizontalScrollBarChanged(int)")) self.connect(self.ui.graphicsView.verticalScrollBar(), SIGNAL("valueChanged(int)"), SLOT("slot_verticalScrollBarChanged(int)")) self.connect(self.scene, SIGNAL("sceneGroupMoved(int, int, QPointF)"), SLOT("slot_canvasItemMoved(int, int, QPointF)")) self.connect(self.scene, SIGNAL("scaleChanged(double)"), SLOT("slot_canvasScaleChanged(double)")) self.connect(self, SIGNAL("SIGUSR1()"), SLOT("slot_handleSIGUSR1()")) self.connect(self, SIGNAL("SIGTERM()"), SLOT("slot_handleSIGTERM()")) self.connect(self, SIGNAL("DebugCallback(int, int, int, double, QString)"), SLOT("slot_handleDebugCallback(int, int, int, double, QString)")) self.connect(self, SIGNAL("PluginAddedCallback(int)"), SLOT("slot_handlePluginAddedCallback(int)")) self.connect(self, SIGNAL("PluginRemovedCallback(int)"), SLOT("slot_handlePluginRemovedCallback(int)")) self.connect(self, SIGNAL("PluginRenamedCallback(int, QString)"), SLOT("slot_handlePluginRenamedCallback(int, QString)")) self.connect(self, SIGNAL("ParameterValueChangedCallback(int, int, double)"), SLOT("slot_handleParameterValueChangedCallback(int, int, double)")) self.connect(self, SIGNAL("ParameterDefaultChangedCallback(int, int, double)"), SLOT("slot_handleParameterDefaultChangedCallback(int, int, double)")) self.connect(self, SIGNAL("ParameterMidiChannelChangedCallback(int, int, int)"), SLOT("slot_handleParameterMidiChannelChangedCallback(int, int, int)")) self.connect(self, SIGNAL("ParameterMidiCcChangedCallback(int, int, int)"), SLOT("slot_handleParameterMidiCcChangedCallback(int, int, int)")) self.connect(self, SIGNAL("ProgramChangedCallback(int, int)"), SLOT("slot_handleProgramChangedCallback(int, int)")) self.connect(self, SIGNAL("MidiProgramChangedCallback(int, int)"), SLOT("slot_handleMidiProgramChangedCallback(int, int)")) self.connect(self, SIGNAL("NoteOnCallback(int, int, int, int)"), SLOT("slot_handleNoteOnCallback(int, int, int, int)")) self.connect(self, SIGNAL("NoteOffCallback(int, int, int)"), SLOT("slot_handleNoteOffCallback(int, int, int)")) self.connect(self, SIGNAL("ShowGuiCallback(int, int)"), SLOT("slot_handleShowGuiCallback(int, int)")) self.connect(self, SIGNAL("UpdateCallback(int)"), SLOT("slot_handleUpdateCallback(int)")) self.connect(self, SIGNAL("ReloadInfoCallback(int)"), SLOT("slot_handleReloadInfoCallback(int)")) self.connect(self, SIGNAL("ReloadParametersCallback(int)"), SLOT("slot_handleReloadParametersCallback(int)")) self.connect(self, SIGNAL("ReloadProgramsCallback(int)"), SLOT("slot_handleReloadProgramsCallback(int)")) self.connect(self, SIGNAL("ReloadAllCallback(int)"), SLOT("slot_handleReloadAllCallback(int)")) self.connect(self, SIGNAL("PatchbayClientAddedCallback(int, QString)"), SLOT("slot_handlePatchbayClientAddedCallback(int, QString)")) self.connect(self, SIGNAL("PatchbayClientRemovedCallback(int)"), SLOT("slot_handlePatchbayClientRemovedCallback(int)")) self.connect(self, SIGNAL("PatchbayClientRenamedCallback(int, QString)"), SLOT("slot_handlePatchbayClientRenamedCallback(int, QString)")) self.connect(self, SIGNAL("PatchbayPortAddedCallback(int, int, int, QString)"), SLOT("slot_handlePatchbayPortAddedCallback(int, int, int, QString)")) self.connect(self, SIGNAL("PatchbayPortRemovedCallback(int)"), SLOT("slot_handlePatchbayPortRemovedCallback(int)")) self.connect(self, SIGNAL("PatchbayPortRenamedCallback(int, QString)"), SLOT("slot_handlePatchbayPortRenamedCallback(int, QString)")) self.connect(self, SIGNAL("PatchbayConnectionAddedCallback(int, int, int)"), SLOT("slot_handlePatchbayConnectionAddedCallback(int, int, int)")) self.connect(self, SIGNAL("PatchbayConnectionRemovedCallback(int)"), SLOT("slot_handlePatchbayConnectionRemovedCallback(int)")) #self.connect(self, SIGNAL("NSM_AnnounceCallback()"), SLOT("slot_handleNSM_AnnounceCallback()")) #self.connect(self, SIGNAL("NSM_Open1Callback()"), SLOT("slot_handleNSM_Open1Callback()")) #self.connect(self, SIGNAL("NSM_Open2Callback()"), SLOT("slot_handleNSM_Open2Callback()")) #self.connect(self, SIGNAL("NSM_SaveCallback()"), SLOT("slot_handleNSM_SaveCallback()")) self.connect(self, SIGNAL("ErrorCallback(QString)"), SLOT("slot_handleErrorCallback(QString)")) self.connect(self, SIGNAL("QuitCallback()"), SLOT("slot_handleQuitCallback()")) #NSM_URL = os.getenv("NSM_URL") #if NSM_URL: #Carla.host.nsm_announce(NSM_URL, os.getpid()) #else: QTimer.singleShot(0, self, SLOT("slot_engineStart()")) @pyqtSlot(float) def slot_canvasScaleChanged(self, scale): self.ui.miniCanvasPreview.setViewScale(scale) @pyqtSlot(int, int, QPointF) def slot_canvasItemMoved(self, group_id, split_mode, pos): self.ui.miniCanvasPreview.update() @pyqtSlot(int) def slot_horizontalScrollBarChanged(self, value): maximum = self.ui.graphicsView.horizontalScrollBar().maximum() if maximum == 0: xp = 0 else: xp = float(value) / maximum self.ui.miniCanvasPreview.setViewPosX(xp) @pyqtSlot(int) def slot_verticalScrollBarChanged(self, value): maximum = self.ui.graphicsView.verticalScrollBar().maximum() if maximum == 0: yp = 0 else: yp = float(value) / maximum self.ui.miniCanvasPreview.setViewPosY(yp) @pyqtSlot() def slot_miniCanvasInit(self): settings = QSettings() self.ui.graphicsView.horizontalScrollBar().setValue(settings.value("HorizontalScrollBarValue", DEFAULT_CANVAS_WIDTH / 3, type=int)) self.ui.graphicsView.verticalScrollBar().setValue(settings.value("VerticalScrollBarValue", DEFAULT_CANVAS_HEIGHT * 3 / 8, type=int)) @pyqtSlot(float, float) def slot_miniCanvasMoved(self, xp, yp): self.ui.graphicsView.horizontalScrollBar().setValue(xp * DEFAULT_CANVAS_WIDTH) self.ui.graphicsView.verticalScrollBar().setValue(yp * DEFAULT_CANVAS_HEIGHT) @pyqtSlot() def slot_miniCanvasCheckAll(self): self.slot_miniCanvasCheckSize() self.slot_horizontalScrollBarChanged(self.ui.graphicsView.horizontalScrollBar().value()) self.slot_verticalScrollBarChanged(self.ui.graphicsView.verticalScrollBar().value()) @pyqtSlot() def slot_miniCanvasCheckSize(self): self.ui.miniCanvasPreview.setViewSize(float(self.ui.graphicsView.width()) / DEFAULT_CANVAS_WIDTH, float(self.ui.graphicsView.height()) / DEFAULT_CANVAS_HEIGHT) def startEngine(self, clientName = "Carla"): # --------------------------------------------- # Engine settings settings = QSettings() Carla.processMode = settings.value("Engine/ProcessMode", PROCESS_MODE_MULTIPLE_CLIENTS, type=int) Carla.maxParameters = settings.value("Engine/MaxParameters", MAX_DEFAULT_PARAMETERS, type=int) transportMode = settings.value("Engine/TransportMode", TRANSPORT_MODE_JACK, type=int) forceStereo = settings.value("Engine/ForceStereo", False, type=bool) preferPluginBridges = settings.value("Engine/PreferPluginBridges", False, type=bool) preferUiBridges = settings.value("Engine/PreferUiBridges", True, type=bool) useDssiVstChunks = settings.value("Engine/UseDssiVstChunks", False, type=bool) oscUiTimeout = settings.value("Engine/OscUiTimeout", 40, type=int) preferredBufferSize = settings.value("Engine/PreferredBufferSize", 512, type=int) preferredSampleRate = settings.value("Engine/PreferredSampleRate", 44100, type=int) if Carla.processMode == PROCESS_MODE_CONTINUOUS_RACK: forceStereo = True elif Carla.processMode == PROCESS_MODE_MULTIPLE_CLIENTS and os.getenv("LADISH_APP_NAME"): print("LADISH detected but using multiple clients (not allowed), forcing single client now") Carla.processMode = PROCESS_MODE_SINGLE_CLIENT Carla.host.set_engine_option(OPTION_PROCESS_MODE, Carla.processMode, "") Carla.host.set_engine_option(OPTION_MAX_PARAMETERS, Carla.maxParameters, "") Carla.host.set_engine_option(OPTION_FORCE_STEREO, forceStereo, "") Carla.host.set_engine_option(OPTION_PREFER_PLUGIN_BRIDGES, preferPluginBridges, "") Carla.host.set_engine_option(OPTION_PREFER_UI_BRIDGES, preferUiBridges, "") Carla.host.set_engine_option(OPTION_USE_DSSI_VST_CHUNKS, useDssiVstChunks, "") Carla.host.set_engine_option(OPTION_OSC_UI_TIMEOUT, oscUiTimeout, "") Carla.host.set_engine_option(OPTION_PREFERRED_BUFFER_SIZE, preferredBufferSize, "") Carla.host.set_engine_option(OPTION_PREFERRED_SAMPLE_RATE, preferredSampleRate, "") # --------------------------------------------- # Start audioDriver = settings.value("Engine/AudioDriver", "JACK", type=str) if not Carla.host.engine_init(audioDriver, clientName): if self.fFirstEngineInit: self.fFirstEngineInit = False return audioError = cString(Carla.host.get_last_error()) if audioError: QMessageBox.critical(self, self.tr("Error"), self.tr("Could not connect to Audio backend '%s', possible reasons:\n%s" % (audioDriver, audioError))) else: QMessageBox.critical(self, self.tr("Error"), self.tr("Could not connect to Audio backend '%s'" % audioDriver)) return self.fEngineStarted = True self.fFirstEngineInit = False self.fPluginCount = 0 self.fPluginList = [] if Carla.processMode == PROCESS_MODE_CONTINUOUS_RACK: maxCount = MAX_RACK_PLUGINS elif Carla.processMode == PROCESS_MODE_PATCHBAY: maxCount = MAX_PATCHBAY_PLUGINS else: maxCount = MAX_DEFAULT_PLUGINS self.ui.ch_transport.blockSignals(True) self.ui.ch_transport.addItem(self.tr("Internal")) if audioDriver == "JACK": self.ui.ch_transport.addItem(self.tr("JACK")) elif transportMode == TRANSPORT_MODE_JACK: transportMode = TRANSPORT_MODE_INTERNAL self.ui.ch_transport.setCurrentIndex(transportMode) self.ui.ch_transport.blockSignals(False) for x in range(maxCount): self.fPluginList.append(None) Carla.host.set_engine_option(OPTION_TRANSPORT_MODE, transportMode, "") # Peaks self.fIdleTimerFast = self.startTimer(self.fSavedSettings["Main/RefreshInterval"]) # LEDs and edit dialog parameters self.fIdleTimerSlow = self.startTimer(self.fSavedSettings["Main/RefreshInterval"]*2) def stopEngine(self): if self.fPluginCount > 0: ask = QMessageBox.question(self, self.tr("Warning"), self.tr("There are still some plugins loaded, you need to remove them to stop the engine.\n" "Do you want to do this now?"), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) if ask != QMessageBox.Yes: return self.removeAllPlugins() if Carla.host.is_engine_running() and not Carla.host.engine_close(): print(cString(Carla.host.get_last_error())) self.fEngineStarted = False self.fPluginCount = 0 self.fPluginList = [] self.killTimer(self.fIdleTimerFast) self.killTimer(self.fIdleTimerSlow) settings = QSettings() settings.setValue("Engine/TransportMode", self.ui.ch_transport.currentIndex()) self.ui.ch_transport.blockSignals(True) self.ui.ch_transport.clear() self.ui.ch_transport.blockSignals(False) patchcanvas.clear() def loadProject(self, filename): self.fProjectFilename = filename self.setWindowTitle("Carla - %s" % os.path.basename(filename)) self.fProjectLoading = True Carla.host.load_project(filename) self.fProjectLoading = False def loadProjectLater(self, filename): self.fProjectFilename = filename self.setWindowTitle("Carla - %s" % os.path.basename(filename)) QTimer.singleShot(0, self, SLOT("slot_loadProjectLater()")) def saveProject(self, filename): self.fProjectFilename = filename self.setWindowTitle("Carla - %s" % os.path.basename(filename)) Carla.host.save_project(filename) def addPlugin(self, btype, ptype, filename, name, label, extraStuff): if not self.fEngineStarted: QMessageBox.warning(self, self.tr("Warning"), self.tr("Cannot add new plugins while engine is stopped")) return False if not Carla.host.add_plugin(btype, ptype, filename, name, label, extraStuff): CustomMessageBox(self, QMessageBox.Critical, self.tr("Error"), self.tr("Failed to load plugin"), cString(Carla.host.get_last_error()), QMessageBox.Ok, QMessageBox.Ok) return False return True def removeAllPlugins(self): while (self.ui.w_plugins.layout().takeAt(0)): pass self.ui.act_plugin_remove_all.setEnabled(False) for i in range(self.fPluginCount): pwidget = self.fPluginList[i] if pwidget is None: break self.fPluginList[i] = None pwidget.ui.edit_dialog.close() pwidget.close() pwidget.deleteLater() del pwidget self.fPluginCount = 0 Carla.host.remove_all_plugins() @pyqtSlot() def slot_fileNew(self): self.removeAllPlugins() self.fProjectFilename = None self.fProjectLoading = False self.setWindowTitle("Carla") @pyqtSlot() def slot_fileOpen(self): fileFilter = self.tr("Carla Project File (*.carxp)") filenameTry = QFileDialog.getOpenFileName(self, self.tr("Open Carla Project File"), self.fSavedSettings["Main/DefaultProjectFolder"], filter=fileFilter) if filenameTry: # FIXME - show dialog to user self.removeAllPlugins() self.loadProject(filenameTry) @pyqtSlot() def slot_fileSave(self, saveAs=False): if self.fProjectFilename and not saveAs: return self.saveProject(self.fProjectFilename) fileFilter = self.tr("Carla Project File (*.carxp)") filenameTry = QFileDialog.getSaveFileName(self, self.tr("Save Carla Project File"), self.fSavedSettings["Main/DefaultProjectFolder"], filter=fileFilter) if filenameTry: if not filenameTry.endswith(".carxp"): filenameTry += ".carxp" self.saveProject(filenameTry) @pyqtSlot() def slot_fileSaveAs(self): self.slot_fileSave(True) @pyqtSlot() def slot_loadProjectLater(self): self.fProjectLoading = True Carla.host.load_project(self.fProjectFilename) self.fProjectLoading = False @pyqtSlot() def slot_engineStart(self): self.startEngine() check = Carla.host.is_engine_running() self.ui.act_file_open.setEnabled(check) self.ui.act_engine_start.setEnabled(not check) self.ui.act_engine_stop.setEnabled(check) self.ui.act_engine_configure.setEnabled(not check) self.ui.frame_transport.setEnabled(check) @pyqtSlot() def slot_engineStop(self): self.stopEngine() check = Carla.host.is_engine_running() self.ui.act_file_open.setEnabled(check) self.ui.act_engine_start.setEnabled(not check) self.ui.act_engine_stop.setEnabled(check) self.ui.frame_transport.setEnabled(check) @pyqtSlot() def slot_pluginAdd(self): dialog = PluginDatabaseW(self) if dialog.exec_(): btype = dialog.fRetPlugin['build'] ptype = dialog.fRetPlugin['type'] filename = dialog.fRetPlugin['binary'] label = dialog.fRetPlugin['label'] extraStuff = self.getExtraStuff(dialog.fRetPlugin) self.addPlugin(btype, ptype, filename, None, label, extraStuff) @pyqtSlot() def slot_pluginRemoveAll(self): self.removeAllPlugins() self.connect(self.ui.ch_transport, SIGNAL("currentIndexChanged(int)"), SLOT("(int)")) self.connect(self.ui.b_transport_play, SIGNAL("clicked(bool)"), SLOT("(bool)")) self.connect(self.ui.b_transport_stop, SIGNAL("clicked()"), SLOT("()")) @pyqtSlot(int) def slot_transportModeChanged(self, newMode): Carla.host.set_engine_option(OPTION_TRANSPORT_MODE, newMode, "") @pyqtSlot(bool) def slot_transportPlayPause(self, toggled): if toggled: Carla.host.transport_play() else: Carla.host.transport_pause() @pyqtSlot() def slot_transportStop(self): Carla.host.transport_pause() Carla.host.transport_relocate(0) @pyqtSlot() def slot_aboutCarla(self): CarlaAboutW(self).exec_() @pyqtSlot() def slot_configureCarla(self): dialog = CarlaSettingsW(self) if dialog.exec_(): self.loadSettings(False) for pwidget in self.fPluginList: if pwidget is None: return pwidget.setRefreshRate(self.fSavedSettings["Main/RefreshInterval"]) @pyqtSlot() def slot_handleSIGUSR1(self): print("Got SIGUSR1 -> Saving project now") QTimer.singleShot(0, self, SLOT("slot_fileSave()")) @pyqtSlot() def slot_handleSIGTERM(self): print("Got SIGTERM -> Closing now") self.close() @pyqtSlot(int, int, int, float, str) def slot_handleDebugCallback(self, pluginId, value1, value2, value3, valueStr): print("DEBUG :: %i, %i, %i, %f, \"%s\")" % (pluginId, value1, value2, value3, valueStr)) @pyqtSlot(int) def slot_handlePluginAddedCallback(self, pluginId): pwidget = PluginWidget(self, pluginId) pwidget.setRefreshRate(self.fSavedSettings["Main/RefreshInterval"]) self.ui.w_plugins.layout().addWidget(pwidget) self.fPluginCount += 1 self.fPluginList[pluginId] = pwidget if not self.fProjectLoading: pwidget.setActive(True, True, True) if self.fPluginCount == 1: self.ui.act_plugin_remove_all.setEnabled(True) @pyqtSlot(int) def slot_handlePluginRemovedCallback(self, pluginId): if pluginId >= self.fPluginCount: return pwidget = self.fPluginList[pluginId] if pwidget is None: return self.fPluginList[pluginId] = None self.fPluginCount -= 1 self.ui.w_plugins.layout().removeWidget(pwidget) pwidget.ui.edit_dialog.close() pwidget.close() pwidget.deleteLater() del pwidget # push all plugins 1 slot back for i in range(pluginId, self.fPluginCount): self.fPluginList[i] = self.fPluginList[i+1] self.fPluginList[i].setId(i) if self.fPluginCount == 0: self.ui.act_plugin_remove_all.setEnabled(False) @pyqtSlot(int, str) def slot_handlePluginRenamedCallback(self, pluginId, newName): if pluginId >= self.fPluginCount: return pwidget = self.fPluginList[pluginId] if pwidget is None: return pwidget.ui.label_name.setText(newName) @pyqtSlot(int, int, float) def slot_handleParameterValueChangedCallback(self, pluginId, parameterId, value): if pluginId >= self.fPluginCount: return pwidget = self.fPluginList[pluginId] if pwidget is None: return pwidget.setParameterValue(parameterId, value) @pyqtSlot(int, int, float) def slot_handleParameterDefaultChangedCallback(self, pluginId, parameterId, value): if pluginId >= self.fPluginCount: return pwidget = self.fPluginList[pluginId] if pwidget is None: return pwidget.setParameterDefault(parameterId, value) @pyqtSlot(int, int, int) def slot_handleParameterMidiChannelChangedCallback(self, pluginId, parameterId, channel): if pluginId >= self.fPluginCount: return pwidget = self.fPluginList[pluginId] if pwidget is None: return pwidget.setParameterMidiChannel(parameterId, channel) @pyqtSlot(int, int, int) def slot_handleParameterMidiCcChangedCallback(self, pluginId, parameterId, cc): if pluginId >= self.fPluginCount: return pwidget = self.fPluginList[pluginId] if pwidget is None: return pwidget.setParameterMidiControl(parameterId, cc) @pyqtSlot(int, int) def slot_handleProgramChangedCallback(self, pluginId, programId): if pluginId >= self.fPluginCount: return pwidget = self.fPluginList[pluginId] if pwidget is None: return pwidget.setProgram(programId) @pyqtSlot(int, int) def slot_handleMidiProgramChangedCallback(self, pluginId, midiProgramId): if pluginId >= self.fPluginCount: return pwidget = self.fPluginList[pluginId] if pwidget is None: return pwidget.setMidiProgram(midiProgramId) @pyqtSlot(int, int, int, int) def slot_handleNoteOnCallback(self, pluginId, channel, note, velo): if pluginId >= self.fPluginCount: return pwidget = self.fPluginList[pluginId] if pwidget is None: return pwidget.sendNoteOn(channel, note) @pyqtSlot(int, int, int) def slot_handleNoteOffCallback(self, pluginId, channel, note): if pluginId >= self.fPluginCount: return pwidget = self.fPluginList[pluginId] if pwidget is None: return pwidget.sendNoteOff(channel, note) @pyqtSlot(int, int) def slot_handleShowGuiCallback(self, pluginId, show): if pluginId >= self.fPluginCount: return pwidget = self.fPluginList[pluginId] if pwidget is None: return if show == 0: pwidget.ui.b_gui.setChecked(False) pwidget.ui.b_gui.setEnabled(True) elif show == 1: pwidget.ui.b_gui.setChecked(True) pwidget.ui.b_gui.setEnabled(True) elif show == -1: pwidget.ui.b_gui.setChecked(False) pwidget.ui.b_gui.setEnabled(False) @pyqtSlot(int) def slot_handleUpdateCallback(self, pluginId): if pluginId >= self.fPluginCount: return pwidget = self.fPluginList[pluginId] if pwidget is None: return pwidget.ui.edit_dialog.updateInfo() @pyqtSlot(int) def slot_handleReloadInfoCallback(self, pluginId): if pluginId >= self.fPluginCount: return pwidget = self.fPluginList[pluginId] if pwidget is None: return pwidget.ui.edit_dialog.reloadInfo() @pyqtSlot(int) def slot_handleReloadParametersCallback(self, pluginId): if pluginId >= self.fPluginCount: return pwidget = self.fPluginList[pluginId] if pwidget is None: return pwidget.ui.edit_dialog.reloadParameters() @pyqtSlot(int) def slot_handleReloadProgramsCallback(self, pluginId): if pluginId >= self.fPluginCount: return pwidget = self.fPluginList[pluginId] if pwidget is None: return pwidget.ui.edit_dialog.reloadPrograms() @pyqtSlot(int) def slot_handleReloadAllCallback(self, pluginId): if pluginId >= self.fPluginCount: return pwidget = self.fPluginList[pluginId] if pwidget is None: return pwidget.ui.edit_dialog.reloadAll() @pyqtSlot(int, str) def slot_handlePatchbayClientAddedCallback(self, clientId, clientName): patchcanvas.addGroup(clientId, clientName) @pyqtSlot(int) def slot_handlePatchbayClientRemovedCallback(self, clientId): patchcanvas.removeGroup(clientId) @pyqtSlot(int, str) def slot_handlePatchbayClientRenamedCallback(self, clientId, newClientName): patchcanvas.renameGroup(clientId, newClientName) @pyqtSlot(int, int, int, str) def slot_handlePatchbayPortAddedCallback(self, clientId, portId, portFlags, portName): if (portFlags & PATCHBAY_PORT_IS_INPUT): portMode = patchcanvas.PORT_MODE_INPUT elif (portFlags & PATCHBAY_PORT_IS_OUTPUT): portMode = patchcanvas.PORT_MODE_OUTPUT else: portMode = patchcanvas.PORT_MODE_NULL if (portFlags & PATCHBAY_PORT_IS_AUDIO): portType = patchcanvas.PORT_TYPE_AUDIO_JACK elif (portFlags & PATCHBAY_PORT_IS_MIDI): portType = patchcanvas.PORT_TYPE_MIDI_JACK else: portType = patchcanvas.PORT_TYPE_NULL patchcanvas.addPort(clientId, portId, portName, portMode, portType) @pyqtSlot(int) def slot_handlePatchbayPortRemovedCallback(self, portId): patchcanvas.removePort(portId) @pyqtSlot(int, str) def slot_handlePatchbayPortRenamedCallback(self, portId, newPortName): patchcanvas.renamePort(portId, newPortName) @pyqtSlot(int, int, int) def slot_handlePatchbayConnectionAddedCallback(self, connectionId, portOutId, portInId): patchcanvas.connectPorts(connectionId, portOutId, portInId) @pyqtSlot(int) def slot_handlePatchbayConnectionRemovedCallback(self, connectionId): patchcanvas.disconnectPorts(connectionId) @pyqtSlot(str) def slot_handleErrorCallback(self, error): QMessageBox.critical(self, self.tr("Error"), error) @pyqtSlot() def slot_handleQuitCallback(self): CustomMessageBox(self, QMessageBox.Warning, self.tr("Warning"), self.tr("Engine has been stopped or crashed.\nPlease restart Carla"), self.tr("You may want to save your session now..."), QMessageBox.Ok, QMessageBox.Ok) def getExtraStuff(self, plugin): ptype = plugin['type'] if ptype == PLUGIN_LADSPA: uniqueId = plugin['uniqueId'] for rdfItem in self.fLadspaRdfList: if rdfItem.UniqueID == uniqueId: return pointer(rdfItem) elif ptype == PLUGIN_DSSI: if (plugin['hints'] & PLUGIN_HAS_GUI): gui = findDSSIGUI(plugin['binary'], plugin['name'], plugin['label']) if gui: return gui.encode("utf-8") elif ptype == PLUGIN_SF2: if plugin['name'].endswith(" (16 outputs)"): # return a dummy non-null pointer INTPOINTER = POINTER(c_int) ptr = c_int(0x1) addr = addressof(ptr) return cast(addr, INTPOINTER) return c_nullptr def loadRDFs(self): # Save RDF info for later self.fLadspaRdfList = [] if not haveLRDF: return settingsDir = os.path.join(HOME, ".config", "Cadence") frLadspaFile = os.path.join(settingsDir, "ladspa_rdf.db") if os.path.exists(frLadspaFile): frLadspa = open(frLadspaFile, 'r') try: self.fLadspaRdfList = ladspa_rdf.get_c_ladspa_rdfs(json.load(frLadspa)) except: pass frLadspa.close() def saveSettings(self): settings = QSettings() settings.setValue("Geometry", self.saveGeometry()) settings.setValue("ShowToolbar", self.ui.toolBar.isVisible()) settings.setValue("ShowTransport", self.ui.frame_transport.isVisible()) settings.setValue("HorizontalScrollBarValue", self.ui.graphicsView.horizontalScrollBar().value()) settings.setValue("VerticalScrollBarValue", self.ui.graphicsView.verticalScrollBar().value()) def loadSettings(self, geometry): settings = QSettings() if geometry: self.restoreGeometry(settings.value("Geometry", "")) showToolbar = settings.value("ShowToolbar", True, type=bool) self.ui.act_settings_show_toolbar.setChecked(showToolbar) self.ui.toolBar.setVisible(showToolbar) showTransport = settings.value("ShowTransport", True, type=bool) self.ui.act_settings_show_transport.setChecked(showTransport) self.ui.frame_transport.setVisible(showTransport) self.fSavedSettings = { "Main/DefaultProjectFolder": settings.value("Main/DefaultProjectFolder", HOME, type=str), "Main/RefreshInterval": settings.value("Main/RefreshInterval", 50, type=int), "Canvas/Theme": settings.value("Canvas/Theme", patchcanvas.getDefaultThemeName(), type=str), "Canvas/AutoHideGroups": settings.value("Canvas/AutoHideGroups", False, type=bool), "Canvas/UseBezierLines": settings.value("Canvas/UseBezierLines", True, type=bool), "Canvas/EyeCandy": settings.value("Canvas/EyeCandy", patchcanvas.EYECANDY_SMALL, type=int), "Canvas/UseOpenGL": settings.value("Canvas/UseOpenGL", False, type=bool), "Canvas/Antialiasing": settings.value("Canvas/Antialiasing", patchcanvas.ANTIALIASING_SMALL, type=int), "Canvas/HighQualityAntialiasing": settings.value("Canvas/HighQualityAntialiasing", False, type=bool) } # --------------------------------------------- # plugin checks if settings.value("Engine/DisableChecks", False, type=bool): os.environ["CARLA_DISCOVERY_NO_PROCESSING_CHECKS"] = "true" elif os.getenv("CARLA_DISCOVERY_NO_PROCESSING_CHECKS"): os.environ.pop("CARLA_DISCOVERY_NO_PROCESSING_CHECKS") # --------------------------------------------- # plugin paths Carla.LADSPA_PATH = toList(settings.value("Paths/LADSPA", Carla.LADSPA_PATH)) Carla.DSSI_PATH = toList(settings.value("Paths/DSSI", Carla.DSSI_PATH)) Carla.LV2_PATH = toList(settings.value("Paths/LV2", Carla.LV2_PATH)) Carla.VST_PATH = toList(settings.value("Paths/VST", Carla.VST_PATH)) Carla.GIG_PATH = toList(settings.value("Paths/GIG", Carla.GIG_PATH)) Carla.SF2_PATH = toList(settings.value("Paths/SF2", Carla.SF2_PATH)) Carla.SFZ_PATH = toList(settings.value("Paths/SFZ", Carla.SFZ_PATH)) os.environ["LADSPA_PATH"] = splitter.join(Carla.LADSPA_PATH) os.environ["DSSI_PATH"] = splitter.join(Carla.DSSI_PATH) os.environ["LV2_PATH"] = splitter.join(Carla.LV2_PATH) os.environ["VST_PATH"] = splitter.join(Carla.VST_PATH) os.environ["GIG_PATH"] = splitter.join(Carla.GIG_PATH) os.environ["SF2_PATH"] = splitter.join(Carla.SF2_PATH) os.environ["SFZ_PATH"] = splitter.join(Carla.SFZ_PATH) def resizeEvent(self, event): if self.ui.tabWidget.currentIndex() == 0: # Force update of 2nd tab width = self.ui.tab_plugins.width()-4 height = self.ui.tab_plugins.height()-4 self.ui.miniCanvasPreview.setViewSize(float(width) / DEFAULT_CANVAS_WIDTH, float(height) / DEFAULT_CANVAS_HEIGHT) else: QTimer.singleShot(0, self, SLOT("slot_miniCanvasCheckSize()")) QMainWindow.resizeEvent(self, event) def timerEvent(self, event): if event.timerId() == self.fIdleTimerFast: Carla.host.engine_idle() for pwidget in self.fPluginList: if pwidget is None: break pwidget.idleFast() elif event.timerId() == self.fIdleTimerSlow: for pwidget in self.fPluginList: if pwidget is None: break pwidget.idleSlow() QMainWindow.timerEvent(self, event) def closeEvent(self, event): #if self.nsm_server: #self.nsm_server.stop() self.saveSettings() if Carla.host.is_engine_running(): Carla.host.set_engine_about_to_close() self.removeAllPlugins() self.stopEngine() QMainWindow.closeEvent(self, event) # ------------------------------------------------------------------------------------------------ def canvasCallback(action, value1, value2, valueStr): if action == patchcanvas.ACTION_GROUP_INFO: pass elif action == patchcanvas.ACTION_GROUP_RENAME: pass elif action == patchcanvas.ACTION_GROUP_SPLIT: groupId = value1 patchcanvas.splitGroup(groupId) elif action == patchcanvas.ACTION_GROUP_JOIN: groupId = value1 patchcanvas.joinGroup(groupId) elif action == patchcanvas.ACTION_PORT_INFO: pass elif action == patchcanvas.ACTION_PORT_RENAME: pass elif action == patchcanvas.ACTION_PORTS_CONNECT: portIdA = value1 portIdB = value2 Carla.host.patchbay_connect(portIdA, portIdB) elif action == patchcanvas.ACTION_PORTS_DISCONNECT: connectionId = value1 Carla.host.patchbay_disconnect(connectionId) def engineCallback(ptr, action, pluginId, value1, value2, value3, valueStr): if pluginId < 0 or not Carla.gui: return if action == CALLBACK_DEBUG: Carla.gui.emit(SIGNAL("DebugCallback(int, int, int, double, QString)"), pluginId, value1, value2, value3, cString(valueStr)) elif action == CALLBACK_PLUGIN_ADDED: Carla.gui.emit(SIGNAL("PluginAddedCallback(int)"), pluginId) elif action == CALLBACK_PLUGIN_REMOVED: Carla.gui.emit(SIGNAL("PluginRemovedCallback(int)"), pluginId) elif action == CALLBACK_PLUGIN_RENAMED: Carla.gui.emit(SIGNAL("PluginRenamedCallback(int, QString)"), pluginId, valueStr) elif action == CALLBACK_PARAMETER_VALUE_CHANGED: Carla.gui.emit(SIGNAL("ParameterValueChangedCallback(int, int, double)"), pluginId, value1, value3) elif action == CALLBACK_PARAMETER_DEFAULT_CHANGED: Carla.gui.emit(SIGNAL("ParameterDefaultChangedCallback(int, int, double)"), pluginId, value1, value3) elif action == CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED: Carla.gui.emit(SIGNAL("ParameterMidiChannelChangedCallback(int, int, int)"), pluginId, value1, value2) elif action == CALLBACK_PARAMETER_MIDI_CC_CHANGED: Carla.gui.emit(SIGNAL("ParameterMidiCcChangedCallback(int, int, int)"), pluginId, value1, value2) elif action == CALLBACK_PROGRAM_CHANGED: Carla.gui.emit(SIGNAL("ProgramChangedCallback(int, int)"), pluginId, value1) elif action == CALLBACK_MIDI_PROGRAM_CHANGED: Carla.gui.emit(SIGNAL("MidiProgramChangedCallback(int, int)"), pluginId, value1) elif action == CALLBACK_NOTE_ON: Carla.gui.emit(SIGNAL("NoteOnCallback(int, int, int, int)"), pluginId, value1, value2, value3) elif action == CALLBACK_NOTE_OFF: Carla.gui.emit(SIGNAL("NoteOffCallback(int, int, int)"), pluginId, value1, value2) elif action == CALLBACK_SHOW_GUI: Carla.gui.emit(SIGNAL("ShowGuiCallback(int, int)"), pluginId, value1) elif action == CALLBACK_UPDATE: Carla.gui.emit(SIGNAL("UpdateCallback(int)"), pluginId) elif action == CALLBACK_RELOAD_INFO: Carla.gui.emit(SIGNAL("ReloadInfoCallback(int)"), pluginId) elif action == CALLBACK_RELOAD_PARAMETERS: Carla.gui.emit(SIGNAL("ReloadParametersCallback(int)"), pluginId) elif action == CALLBACK_RELOAD_PROGRAMS: Carla.gui.emit(SIGNAL("ReloadProgramsCallback(int)"), pluginId) elif action == CALLBACK_RELOAD_ALL: Carla.gui.emit(SIGNAL("ReloadAllCallback(int)"), pluginId) elif action == CALLBACK_PATCHBAY_CLIENT_ADDED: Carla.gui.emit(SIGNAL("PatchbayClientAddedCallback(int, QString)"), value1, cString(valueStr)) elif action == CALLBACK_PATCHBAY_CLIENT_REMOVED: Carla.gui.emit(SIGNAL("PatchbayClientRemovedCallback(int)"), value1) elif action == CALLBACK_PATCHBAY_CLIENT_RENAMED: Carla.gui.emit(SIGNAL("PatchbayClientRenamedCallback(int, QString)"), value1, cString(valueStr)) elif action == CALLBACK_PATCHBAY_PORT_ADDED: Carla.gui.emit(SIGNAL("PatchbayPortAddedCallback(int, int, int, QString)"), value1, value2, value3, cString(valueStr)) elif action == CALLBACK_PATCHBAY_PORT_REMOVED: Carla.gui.emit(SIGNAL("PatchbayPortRemovedCallback(int)"), value1) elif action == CALLBACK_PATCHBAY_PORT_RENAMED: Carla.gui.emit(SIGNAL("PatchbayPortRenamedCallback(int, QString)"), value1, cString(valueStr)) elif action == CALLBACK_PATCHBAY_CONNECTION_ADDED: Carla.gui.emit(SIGNAL("PatchbayConnectionAddedCallback(int, int, int)"), value1, value2, value3) elif action == CALLBACK_PATCHBAY_CONNECTION_REMOVED: Carla.gui.emit(SIGNAL("PatchbayConnectionRemovedCallback(int)"), value1) #elif action == CALLBACK_NSM_ANNOUNCE: #Carla.gui._nsmAnnounce2str = cString(Carla.host.get_last_error()) #Carla.gui.emit(SIGNAL("NSM_AnnounceCallback()")) #elif action == CALLBACK_NSM_OPEN1: #Carla.gui._nsmOpen1str = cString(valueStr) #Carla.gui.emit(SIGNAL("NSM_Open1Callback()")) #elif action == CALLBACK_NSM_OPEN2: #Carla.gui._nsmOpen2str = cString(valueStr) #Carla.gui.emit(SIGNAL("NSM_Open2Callback()")) #elif action == CALLBACK_NSM_SAVE: #Carla.gui.emit(SIGNAL("NSM_SaveCallback()")) elif action == CALLBACK_ERROR: Carla.gui.emit(SIGNAL("ErrorCallback(QString)"), cString(valueStr)) elif action == CALLBACK_QUIT: Carla.gui.emit(SIGNAL("QuitCallback()")) #--------------- main ------------------ if __name__ == '__main__': # App initialization app = QApplication(sys.argv) app.setApplicationName("Carla") app.setApplicationVersion(VERSION) app.setOrganizationName("Cadence") app.setWindowIcon(QIcon(":/scalable/carla.svg")) libPrefix = None projectFilename = None for i in range(len(app.arguments())): if i == 0: continue argument = app.arguments()[i] if argument.startswith("--with-libprefix="): libPrefix = argument.replace("--with-libprefix=", "") elif os.path.exists(argument): projectFilename = argument # Init backend Carla.host = Host(libPrefix) Carla.host.set_engine_callback(engineCallback) Carla.host.set_engine_option(OPTION_PROCESS_NAME, 0, "carla") # Set bridge paths if carla_bridge_native: Carla.host.set_engine_option(OPTION_PATH_BRIDGE_NATIVE, 0, carla_bridge_native) if carla_bridge_posix32: Carla.host.set_engine_option(OPTION_PATH_BRIDGE_POSIX32, 0, carla_bridge_posix32) if carla_bridge_posix64: Carla.host.set_engine_option(OPTION_PATH_BRIDGE_POSIX64, 0, carla_bridge_posix64) if carla_bridge_win32: Carla.host.set_engine_option(OPTION_PATH_BRIDGE_WIN32, 0, carla_bridge_win32) if carla_bridge_win64: Carla.host.set_engine_option(OPTION_PATH_BRIDGE_WIN64, 0, carla_bridge_win64) if WINDOWS: if carla_bridge_lv2_windows: Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_WINDOWS, 0, carla_bridge_lv2_windows) if carla_bridge_vst_hwnd: Carla.host.set_engine_option(OPTION_PATH_BRIDGE_VST_HWND, 0, carla_bridge_vst_hwnd) elif MACOS: if carla_bridge_lv2_cocoa: Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_COCOA, 0, carla_bridge_lv2_cocoa) if carla_bridge_vst_cocoa: Carla.host.set_engine_option(OPTION_PATH_BRIDGE_VST_COCOA, 0, carla_bridge_vst_cocoa) else: if carla_bridge_lv2_gtk2: Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_GTK2, 0, carla_bridge_lv2_gtk2) if carla_bridge_lv2_gtk3: Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_GTK3, 0, carla_bridge_lv2_gtk3) if carla_bridge_lv2_qt4: Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_QT4, 0, carla_bridge_lv2_qt4) if carla_bridge_lv2_qt5: Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_QT5, 0, carla_bridge_lv2_qt5) if carla_bridge_lv2_x11: Carla.host.set_engine_option(OPTION_PATH_BRIDGE_LV2_X11, 0, carla_bridge_lv2_x11) if carla_bridge_vst_x11: Carla.host.set_engine_option(OPTION_PATH_BRIDGE_VST_X11, 0, carla_bridge_vst_x11) # Create GUI and start engine Carla.gui = CarlaMainW() # Set-up custom signal handling setUpSignals() # Show GUI Carla.gui.show() # Load project file if set if projectFilename: Carla.gui.loadProjectLater(projectFilename) # App-Loop ret = app.exec_() # Exit properly sys.exit(ret)