diff --git a/source/backend/CarlaHost.h b/source/backend/CarlaHost.h index 65d17dde4..5d1e17f54 100644 --- a/source/backend/CarlaHost.h +++ b/source/backend/CarlaHost.h @@ -545,6 +545,17 @@ CARLA_EXPORT uint64_t carla_get_current_transport_frame(); CARLA_EXPORT const CarlaTransportInfo* carla_get_transport_info(); #endif +/*! + * Current number of plugins loaded. + */ +CARLA_EXPORT uint32_t carla_get_current_plugin_count(); + +/*! + * Maximum number of loadable plugins allowed. + * Returns 0 if engine is not started. + */ +CARLA_EXPORT uint32_t carla_get_max_plugin_number(); + /*! * Add a new plugin. * If you don't know the binary type use the BINARY_NATIVE macro. diff --git a/source/backend/CarlaStandalone.cpp b/source/backend/CarlaStandalone.cpp index 3a5a24522..b0a0e70da 100644 --- a/source/backend/CarlaStandalone.cpp +++ b/source/backend/CarlaStandalone.cpp @@ -1291,6 +1291,24 @@ const CarlaTransportInfo* carla_get_transport_info() // ------------------------------------------------------------------------------------------------------------------- +uint32_t carla_get_current_plugin_count() +{ + if (gStandalone.engine != nullptr) + return gStandalone.engine->getCurrentPluginCount(); + + return 0; +} + +uint32_t carla_get_max_plugin_number() +{ + if (gStandalone.engine != nullptr) + return gStandalone.engine->getMaxPluginNumber(); + + return 0; +} + +// ------------------------------------------------------------------------------------------------------------------- + bool carla_add_plugin(BinaryType btype, PluginType ptype, const char* filename, const char* name, const char* label, int64_t uniqueId, const void* extraPtr) { CARLA_SAFE_ASSERT_RETURN(label != nullptr /*&& label[0] != '\0'*/, false); diff --git a/source/backend/engine/CarlaEngine.cpp b/source/backend/engine/CarlaEngine.cpp index 141abd314..3ea479567 100644 --- a/source/backend/engine/CarlaEngine.cpp +++ b/source/backend/engine/CarlaEngine.cpp @@ -729,7 +729,7 @@ bool CarlaEngine::replacePlugin(const uint id) noexcept carla_debug("CarlaEngine::replacePlugin(%i)", id); // might use this to reset - if (id == pData->curPluginCount || id == pData->maxPluginNumber) + if (id == pData->maxPluginNumber) { pData->nextPluginId = pData->maxPluginNumber; return true; diff --git a/source/carla b/source/carla index 3ecfdc540..df99b0395 100755 --- a/source/carla +++ b/source/carla @@ -79,7 +79,6 @@ class CarlaMultiW(QTabWidget): parent.ui.act_canvas_show_internal.triggered.connect(self.fPatchbay.slot_canvasShowInternal) parent.ui.act_canvas_show_external.triggered.connect(self.fPatchbay.slot_canvasShowExternal) - parent.ui.act_canvas_arrange.setEnabled(False) # TODO, later parent.ui.act_canvas_arrange.triggered.connect(self.fPatchbay.slot_canvasArrange) parent.ui.act_canvas_refresh.triggered.connect(self.fPatchbay.slot_canvasRefresh) parent.ui.act_canvas_zoom_fit.triggered.connect(self.fPatchbay.slot_canvasZoomFit) @@ -89,8 +88,20 @@ class CarlaMultiW(QTabWidget): parent.ui.act_canvas_print.triggered.connect(self.fPatchbay.slot_canvasPrint) parent.ui.act_canvas_save_image.triggered.connect(self.fPatchbay.slot_canvasSaveImage) + # TODO, later + parent.ui.act_canvas_arrange.setEnabled(False) + parent.ui.act_settings_configure.triggered.connect(self.fPatchbay.slot_configureCarla) + host.PluginAddedCallback.connect(self.fRack.slot_handlePluginAddedCallback) + host.PluginAddedCallback.connect(self.fPatchbay.slot_handlePluginAddedCallback) + host.PluginRemovedCallback.connect(self.fRack.slot_handlePluginRemovedCallback) + host.PluginRemovedCallback.connect(self.fPatchbay.slot_handlePluginRemovedCallback) + host.PluginRenamedCallback.connect(self.fRack.slot_handlePluginRenamedCallback) + host.PluginRenamedCallback.connect(self.fPatchbay.slot_handlePluginRenamedCallback) + host.PluginUnavailableCallback.connect(self.fRack.slot_handlePluginUnavailableCallback) + host.PluginUnavailableCallback.connect(self.fPatchbay.slot_handlePluginUnavailableCallback) + host.ParameterValueChangedCallback.connect(self.fRack.slot_handleParameterValueChangedCallback) host.ParameterValueChangedCallback.connect(self.fPatchbay.slot_handleParameterValueChangedCallback) host.ParameterDefaultChangedCallback.connect(self.fRack.slot_handleParameterDefaultChangedCallback) @@ -124,24 +135,16 @@ class CarlaMultiW(QTabWidget): # ----------------------------------------------------------------- - def getPluginCount(self): - return self.fRack.getPluginCount() - - # ----------------------------------------------------------------- - - def addPlugin(self, pluginId, isProjectLoading): - self.fRack.addPlugin(pluginId, isProjectLoading) - self.fPatchbay.addPlugin(pluginId, isProjectLoading) - - def removePlugin(self, pluginId): - self.fRack.removePlugin(pluginId) - self.fPatchbay.removePlugin(pluginId) + def fixCanvasPreviewSize(self): + self.fPatchbay.resize(self.fRack.size()) + self.fPatchbay.slot_miniCanvasCheckSize() - def renamePlugin(self, pluginId, newName): - self.fRack.renamePlugin(pluginId, newName) + def setUseCustomPaint(self, useCustomPaint): + if self.fUseCustomPaint != useCustomPaint: + self.fUseCustomPaint = useCustomPaint + self.update() - def disablePlugin(self, pluginId, errorMsg): - self.fRack.disablePlugin(pluginId, errorMsg) + # ----------------------------------------------------------------- def removeAllPlugins(self): self.fRack.removeAllPlugins() @@ -150,12 +153,12 @@ class CarlaMultiW(QTabWidget): # ----------------------------------------------------------------- def engineStarted(self): - pass - #self.fRack.engineStarted() - #self.fPatchbay.engineStarted() + self.fRack.engineStarted() + self.fPatchbay.engineStarted() + self.fParent.engineStarted() def engineStopped(self): - #self.fRack.engineStopped() + self.fRack.engineStopped() self.fPatchbay.engineStopped() self.fParent.engineStopped() @@ -173,7 +176,7 @@ class CarlaMultiW(QTabWidget): def projectLoadingStarted(self): self.fRack.projectLoadingStarted() - #self.fPatchbay.projectLoadingStarted() + self.fPatchbay.projectLoadingStarted() def projectLoadingFinished(self): self.fRack.projectLoadingFinished() @@ -182,6 +185,7 @@ class CarlaMultiW(QTabWidget): # ----------------------------------------------------------------- def saveSettings(self, settings): + self.fRack.saveSettings(settings) self.fPatchbay.saveSettings(settings) def showEditDialog(self, pluginId): @@ -189,15 +193,6 @@ class CarlaMultiW(QTabWidget): # ----------------------------------------------------------------- - def fixCanvasPreviewSize(self): - self.fPatchbay.resize(self.fRack.size()) - self.fPatchbay.slot_miniCanvasCheckSize() - - def setUseCustomPaint(self, useCustomPaint): - if self.fUseCustomPaint != useCustomPaint: - self.fUseCustomPaint = useCustomPaint - self.update() - def paintEvent(self, event): QTabWidget.paintEvent(self, event) @@ -257,14 +252,17 @@ class CarlaHostW(HostWindow): # ----------------------------------------------------------------- + def engineChanged(self): + self.fInfoText = "Engine running | SampleRate: %g | BufferSize: %i" % (self.host.get_sample_rate(), self.host.get_buffer_size()) + self.fInfoLabel.setText("%s | %s" % (self.fInfoText, self.fTextTransport)) + + def engineStarted(self): + self.engineChanged() + def engineStopped(self): self.fInfoText = "" self.fInfoLabel.setText("Engine stopped") - #def engineChanged(self): - #self.fInfoText = "Engine running | SampleRate: %g | BufferSize: %i" % (gCarla.sampleRate, gCarla.bufferSize) - #self.fInfoLabel.setText("%s | %s" % (self.fInfoText, self.fTextTransport)) - # ----------------------------------------------------------------- def updateInfoLabelXandSize(self): diff --git a/source/carla_backend.py b/source/carla_backend.py index a7f4bad64..521d40a0e 100644 --- a/source/carla_backend.py +++ b/source/carla_backend.py @@ -1514,6 +1514,17 @@ class CarlaHostMeta(QObject): def get_transport_info(self): raise NotImplementedError + # Current number of plugins loaded. + @abstractmethod + def get_current_plugin_count(self): + raise NotImplementedError + + # Maximum number of loadable plugins allowed. + # Returns 0 if engine is not started. + @abstractmethod + def get_max_plugin_number(self): + raise NotImplementedError + # Add a new plugin. # If you don't know the binary type use the BINARY_NATIVE macro. # @param btype Binary type @@ -2035,6 +2046,12 @@ class CarlaHostNull(CarlaHostMeta): def get_transport_info(self): return PyCarlaTransportInfo + def get_current_plugin_count(self): + return 0 + + def get_max_plugin_number(self): + return 0 + def add_plugin(self, btype, ptype, filename, name, label, uniqueId, extraPtr): return False @@ -2311,6 +2328,12 @@ class CarlaHostDLL(CarlaHostMeta): self.lib.carla_get_transport_info.argtypes = None self.lib.carla_get_transport_info.restype = POINTER(CarlaTransportInfo) + self.lib.carla_get_current_plugin_count.argtypes = None + self.lib.carla_get_current_plugin_count.restype = c_uint32 + + self.lib.carla_get_max_plugin_number.argtypes = None + self.lib.carla_get_max_plugin_number.restype = c_uint32 + self.lib.carla_add_plugin.argtypes = [c_enum, c_enum, c_char_p, c_char_p, c_char_p, c_int64, c_void_p] self.lib.carla_add_plugin.restype = c_bool @@ -2579,6 +2602,12 @@ class CarlaHostDLL(CarlaHostMeta): def get_transport_info(self): return structToDict(self.lib.carla_get_transport_info().contents) + def get_current_plugin_count(self): + return int(self.lib.carla_get_current_plugin_count()) + + def get_max_plugin_number(self): + return int(self.lib.carla_get_max_plugin_number()) + def add_plugin(self, btype, ptype, filename, name, label, uniqueId, extraPtr): cfilename = filename.encode("utf-8") if filename else None cname = name.encode("utf-8") if name else None @@ -2912,6 +2941,12 @@ class CarlaHostPlugin(CarlaHostMeta): def get_transport_info(self): return self.fTransportInfo + def get_current_plugin_count(self): + return len(self.fPluginsInfo) + + def get_max_plugin_number(self): + return 0 # TODO + def add_plugin(self, btype, ptype, filename, name, label, uniqueId, extraPtr): return self.sendMsgAndSetError(["add_plugin", btype, ptype, filename, name, label, uniqueId]) diff --git a/source/carla_host.py b/source/carla_host.py index 349be4740..85ef616bf 100644 --- a/source/carla_host.py +++ b/source/carla_host.py @@ -62,20 +62,17 @@ class HostWidgetMeta(object): # -------------------------------------------------------------------------------------------------------- - def getPluginCount(self): - raise NotImplementedError - - def addPlugin(self, pluginId, isProjectLoading): - raise NotImplementedError + #def addPlugin(self, pluginId, isProjectLoading): + #raise NotImplementedError - def removePlugin(self, pluginId): - raise NotImplementedError + #def removePlugin(self, pluginId): + #raise NotImplementedError - def renamePlugin(self, pluginId, newName): - raise NotImplementedError + #def renamePlugin(self, pluginId, newName): + #raise NotImplementedError - def disablePlugin(self, pluginId, errorMsg): - raise NotImplementedError + #def disablePlugin(self, pluginId, errorMsg): + #raise NotImplementedError def removeAllPlugins(self): raise NotImplementedError @@ -256,24 +253,14 @@ class HostWindow(QMainWindow): self.SIGUSR1.connect(self.slot_handleSIGUSR1) self.SIGTERM.connect(self.slot_handleSIGTERM) - host.DebugCallback.connect(self.slot_handleDebugCallback) - - host.PluginAddedCallback.connect(self.slot_handlePluginAddedCallback) - host.PluginRemovedCallback.connect(self.slot_handlePluginRemovedCallback) - host.PluginRenamedCallback.connect(self.slot_handlePluginRenamedCallback) - host.PluginUnavailableCallback.connect(self.slot_handlePluginUnavailableCallback) - - # parameter (rack, patchbay) - # program, midi-program, ui-state (rack, patchbay) - # note on, off (rack, patchbay) - # update, reload (rack, patchbay) - # patchbay - host.EngineStartedCallback.connect(self.slot_handleEngineStartedCallback) host.EngineStoppedCallback.connect(self.slot_handleEngineStoppedCallback) - host.SampleRateChangedCallback.connect(self.slot_handleSampleRateChangedCallback) + host.PluginAddedCallback.connect(self.slot_handlePluginAddedCallback) + host.PluginRemovedCallback.connect(self.slot_handlePluginRemovedCallback) + + host.DebugCallback.connect(self.slot_handleDebugCallback) host.InfoCallback.connect(self.slot_handleInfoCallback) host.ErrorCallback.connect(self.slot_handleErrorCallback) host.QuitCallback.connect(self.slot_handleQuitCallback) @@ -282,6 +269,7 @@ class HostWindow(QMainWindow): # Final setup self.setProperWindowTitle() + QTimer.singleShot(0, self.slot_engineStart) # -------------------------------------------------------------------------------------------------------- @@ -299,6 +287,15 @@ class HostWindow(QMainWindow): # -------------------------------------------------------------------------------------------------------- # Called by containers + def isProjectLoading(self): + return self.fIsProjectLoading + + def getSavedSettings(self): + return self.fSavedSettings + + def setLoadRDFsNeeded(self): + self.fLadspaRdfNeedsUpdate = True + def openSettingsWindow(self, hasCanvas, hasCanvasGL): hasEngine = bool(self.fSessionManagerName != "Non Session Manager") dialog = CarlaSettingsW(self, self.host, hasCanvas, hasCanvasGL, hasEngine) @@ -336,6 +333,19 @@ class HostWindow(QMainWindow): self.ui.miniCanvasPreview.setViewTheme(canvasBg, canvasBrush, canvasPen) self.ui.miniCanvasPreview.init(self.fContainer.scene, canvasWidth, canvasHeight, self.fSavedSettings[CARLA_KEY_CUSTOM_PAINTING]) + # -------------------------------------------------------------------------------------------------------- + # Called by the signal handler + + @pyqtSlot() + def slot_handleSIGUSR1(self): + print("Got SIGUSR1 -> Saving project now") + self.slot_fileSave() + + @pyqtSlot() + def slot_handleSIGTERM(self): + print("Got SIGTERM -> Closing now") + self.close() + # -------------------------------------------------------------------------------------------------------- # Internal stuff (files) @@ -382,7 +392,7 @@ class HostWindow(QMainWindow): newFile = True - if self.fContainer.getPluginCount() > 0: + if self.host.get_current_plugin_count() > 0: ask = QMessageBox.question(self, self.tr("Question"), self.tr("There are some plugins loaded, do you want to remove them now?"), QMessageBox.Yes | QMessageBox.No, QMessageBox.No) newFile = (ask == QMessageBox.Yes) @@ -516,7 +526,8 @@ class HostWindow(QMainWindow): # -------------------------------------------------------------------------------------------------------- - def startEngine(self): + @pyqtSlot() + def slot_engineStart(self): audioDriver = self.setEngineSettings() if not self.host.engine_init(audioDriver, self.fClientName): @@ -534,8 +545,9 @@ class HostWindow(QMainWindow): self.fFirstEngineInit = False - def stopEngine(self): - if self.fContainer.getPluginCount() > 0: + @pyqtSlot() + def slot_engineStop(self): + if self.host.get_current_plugin_count() > 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) @@ -550,7 +562,10 @@ class HostWindow(QMainWindow): # -------------------------------------------------------------------------------------------------------- - def handleEngineStarted(self): + @pyqtSlot(str) + def slot_handleEngineStartedCallback(self, processMode, transportMode, driverName): + self.fSampleRate = self.host.get_sample_rate() + check = self.host.is_engine_running() self.ui.menu_PluginMacros.setEnabled(check) self.ui.menu_Canvas.setEnabled(check) @@ -572,7 +587,12 @@ class HostWindow(QMainWindow): self.refreshTransport(True) self.fContainer.engineStarted() - def handleEngineStopped(self): + self.startTimers() + + @pyqtSlot() + def slot_handleEngineStoppedCallback(self): + self.killTimers() + # just in case self.ui.act_plugin_remove_all.setEnabled(False) self.fContainer.removeAllPlugins() @@ -596,62 +616,80 @@ class HostWindow(QMainWindow): self.fTextTransport = "" self.fContainer.engineStopped() + self.fSampleRate = 0.0 + + @pyqtSlot(float) + def slot_handleSampleRateChangedCallback(self, newSampleRate): + self.fSampleRate = newSampleRate + self.refreshTransport(True) + # -------------------------------------------------------------------------------------------------------- + # Internal stuff (plugins) @pyqtSlot() - def slot_engineStart(self): - self.startEngine() - #self.handleEngineStarted() + def slot_pluginAdd(self, pluginToReplace = -1): + dialog = PluginDatabaseW(self, self.host) - @pyqtSlot() - def slot_engineStop(self): - self.stopEngine() - #self.handleEngineStopped() + if not dialog.exec_(): + return - # -------------------------------------------------------------------------------------------------------- + if not self.host.is_engine_running(): + QMessageBox.warning(self, self.tr("Warning"), self.tr("Cannot add new plugins while engine is stopped")) + return - @pyqtSlot(str) - def slot_handleEngineStartedCallback(self, processMode, transportMode, driverName): - self.fSampleRate = self.host.get_sample_rate() - self.handleEngineStarted() - self.startTimers() + btype = dialog.fRetPlugin['build'] + ptype = dialog.fRetPlugin['type'] + filename = dialog.fRetPlugin['filename'] + label = dialog.fRetPlugin['label'] + uniqueId = dialog.fRetPlugin['uniqueId'] + extraPtr = self.getExtraPtr(dialog.fRetPlugin) + + if pluginToReplace >= 0: + if not self.host.replace_plugin(pluginToReplace): + CustomMessageBox(self, QMessageBox.Critical, self.tr("Error"), self.tr("Failed to replace plugin"), self.host.get_last_error(), QMessageBox.Ok, QMessageBox.Ok) + return + + ok = self.host.add_plugin(btype, ptype, filename, None, label, uniqueId, extraPtr) + + if pluginToReplace >= 0: + self.host.replace_plugin(self.host.get_max_plugin_number()) + + if not ok: + CustomMessageBox(self, QMessageBox.Critical, self.tr("Error"), self.tr("Failed to load plugin"), self.host.get_last_error(), QMessageBox.Ok, QMessageBox.Ok) @pyqtSlot() - def slot_handleEngineStoppedCallback(self): - self.killTimers() - self.handleEngineStopped() - self.fSampleRate = 0.0 + def slot_pluginRemoveAll(self): + self.ui.act_plugin_remove_all.setEnabled(False) - # -------------------------------------------------------------------------------------------------------- - # Internal stuff (timers) + count = self.host.get_current_plugin_count() - def startTimers(self): - if self.fIdleTimerFast == 0: - self.fIdleTimerFast = self.startTimer(self.fSavedSettings[CARLA_KEY_MAIN_REFRESH_INTERVAL]) + if count == 0: + return - if self.fIdleTimerSlow == 0: - self.fIdleTimerSlow = self.startTimer(self.fSavedSettings[CARLA_KEY_MAIN_REFRESH_INTERVAL]*4) + self.fContainer.projectLoadingStarted() - def restartTimersIfNeeded(self): - if self.fIdleTimerFast != 0: - self.killTimer(self.fIdleTimerFast) - self.fIdleTimerFast = self.startTimer(self.fSavedSettings[CARLA_KEY_MAIN_REFRESH_INTERVAL]) + app = QApplication.instance() + for i in range(count): + app.processEvents() + self.host.remove_plugin(count-i-1) - if self.fIdleTimerSlow != 0: - self.killTimer(self.fIdleTimerSlow) - self.fIdleTimerSlow = self.startTimer(self.fSavedSettings[CARLA_KEY_MAIN_REFRESH_INTERVAL]*4) + self.fContainer.projectLoadingFinished() - def killTimers(self): - if self.fIdleTimerFast != 0: - self.killTimer(self.fIdleTimerFast) - self.fIdleTimerFast = 0 + #self.fContainer.removeAllPlugins() + #self.host.remove_all_plugins() - if self.fIdleTimerSlow != 0: - self.killTimer(self.fIdleTimerSlow) - self.fIdleTimerSlow = 0 + # -------------------------------------------------------------------------------------------------------- - # ----------------------------------------------------------------- - # Internal stuff (plugins) + @pyqtSlot(int, str) + def slot_handlePluginAddedCallback(self, pluginId, pluginName): + self.ui.act_plugin_remove_all.setEnabled(self.host.get_current_plugin_count() > 0) + + @pyqtSlot(int) + def slot_handlePluginRemovedCallback(self, pluginId): + self.ui.act_plugin_remove_all.setEnabled(self.host.get_current_plugin_count() > 0) + + # -------------------------------------------------------------------------------------------------------- + # Internal stuff (plugin data) def getExtraPtr(self, plugin): ptype = plugin['type'] @@ -696,11 +734,35 @@ class HostWindow(QMainWindow): frLadspa.close() - # FIXME - put above? - def setLoadRDFsNeeded(self): - self.fLadspaRdfNeedsUpdate = True + # -------------------------------------------------------------------------------------------------------- + # Internal stuff (timers) - # ----------------------------------------------------------------- + def startTimers(self): + if self.fIdleTimerFast == 0: + self.fIdleTimerFast = self.startTimer(self.fSavedSettings[CARLA_KEY_MAIN_REFRESH_INTERVAL]) + + if self.fIdleTimerSlow == 0: + self.fIdleTimerSlow = self.startTimer(self.fSavedSettings[CARLA_KEY_MAIN_REFRESH_INTERVAL]*4) + + def restartTimersIfNeeded(self): + if self.fIdleTimerFast != 0: + self.killTimer(self.fIdleTimerFast) + self.fIdleTimerFast = self.startTimer(self.fSavedSettings[CARLA_KEY_MAIN_REFRESH_INTERVAL]) + + if self.fIdleTimerSlow != 0: + self.killTimer(self.fIdleTimerSlow) + self.fIdleTimerSlow = self.startTimer(self.fSavedSettings[CARLA_KEY_MAIN_REFRESH_INTERVAL]*4) + + def killTimers(self): + if self.fIdleTimerFast != 0: + self.killTimer(self.fIdleTimerFast) + self.fIdleTimerFast = 0 + + if self.fIdleTimerSlow != 0: + self.killTimer(self.fIdleTimerSlow) + self.fIdleTimerSlow = 0 + + # -------------------------------------------------------------------------------------------------------- # Internal stuff (transport) def refreshTransport(self, forced = False): @@ -708,8 +770,8 @@ class HostWindow(QMainWindow): return timeInfo = self.host.get_transport_info() - playing = bool(timeInfo['playing']) - frame = int(timeInfo['frame']) + playing = timeInfo['playing'] + frame = timeInfo['frame'] if playing != self.fLastTransportState or forced: if playing: @@ -741,6 +803,48 @@ class HostWindow(QMainWindow): self.ui.act_transport_forwards.setEnabled(enabled) self.ui.menu_Transport.setEnabled(enabled) + @pyqtSlot(bool) + def slot_transportPlayPause(self, toggled): + if not self.host.is_engine_running(): + return + + if toggled: + self.host.transport_play() + else: + self.host.transport_pause() + + self.refreshTransport() + + @pyqtSlot() + def slot_transportStop(self): + if not self.host.is_engine_running(): + return + + self.host.transport_pause() + self.host.transport_relocate(0) + + self.refreshTransport() + + @pyqtSlot() + def slot_transportBackwards(self): + if not self.host.is_engine_running(): + return + + newFrame = self.host.get_current_transport_frame() - 100000 + + if newFrame < 0: + newFrame = 0 + + self.host.transport_relocate(newFrame) + + @pyqtSlot() + def slot_transportForwards(self): + if not self.host.is_engine_running(): + return + + newFrame = self.host.get_current_transport_frame() + 100000 + self.host.transport_relocate(newFrame) + # ----------------------------------------------------------------- # Internal stuff (settings) @@ -818,131 +922,6 @@ class HostWindow(QMainWindow): # ----------------------------------------------------------------- # Internal stuff (gui) - @pyqtSlot() - def slot_pluginAdd(self, pluginToReplace = -1): - dialog = PluginDatabaseW(self, self.host) - - if not dialog.exec_(): - return - - if not self.host.is_engine_running(): - QMessageBox.warning(self, self.tr("Warning"), self.tr("Cannot add new plugins while engine is stopped")) - return - - btype = dialog.fRetPlugin['build'] - ptype = dialog.fRetPlugin['type'] - filename = dialog.fRetPlugin['filename'] - label = dialog.fRetPlugin['label'] - uniqueId = dialog.fRetPlugin['uniqueId'] - extraPtr = self.getExtraPtr(dialog.fRetPlugin) - - if pluginToReplace >= 0: - if not self.host.replace_plugin(pluginToReplace): - CustomMessageBox(self, QMessageBox.Critical, self.tr("Error"), self.tr("Failed to replace plugin"), self.host.get_last_error(), QMessageBox.Ok, QMessageBox.Ok) - return - - ok = self.host.add_plugin(btype, ptype, filename, None, label, uniqueId, extraPtr) - - if pluginToReplace >= 0: - self.host.replace_plugin(self.fContainer.getPluginCount()) - - if not ok: - CustomMessageBox(self, QMessageBox.Critical, self.tr("Error"), self.tr("Failed to load plugin"), self.host.get_last_error(), QMessageBox.Ok, QMessageBox.Ok) - - @pyqtSlot() - def slot_pluginRemoveAll(self): - self.ui.act_plugin_remove_all.setEnabled(False) - - count = self.fContainer.getPluginCount() - - if count == 0: - return - - self.fContainer.projectLoadingStarted() - - app = QApplication.instance() - for i in range(count): - app.processEvents() - self.host.remove_plugin(count-i-1) - - self.fContainer.projectLoadingFinished() - - #self.fContainer.removeAllPlugins() - #self.host.remove_all_plugins() - - # ----------------------------------------------------------------- - - # TODO clear this, move them into containers - @pyqtSlot(int, str) - def slot_handlePluginAddedCallback(self, pluginId, pluginName): - self.fContainer.addPlugin(pluginId, self.fIsProjectLoading) - - # FIXME ask host directly for plugin count - if self.fContainer.getPluginCount() == 1: - self.ui.act_plugin_remove_all.setEnabled(True) - - @pyqtSlot(int) - def slot_handlePluginRemovedCallback(self, pluginId): - self.fContainer.removePlugin(pluginId) - - # FIXME ask host directly for plugin count - if self.fContainer.getPluginCount() == 0: - self.ui.act_plugin_remove_all.setEnabled(False) - - @pyqtSlot(int, str) - def slot_handlePluginRenamedCallback(self, pluginId, newName): - self.fContainer.renamePlugin(pluginId, newName) - - @pyqtSlot(int, str) - def slot_handlePluginUnavailableCallback(self, pluginId, errorMsg): - self.fContainer.disablePlugin(pluginId, errorMsg) - - # ----------------------------------------------------------------- - - @pyqtSlot(bool) - def slot_transportPlayPause(self, toggled): - if not self.host.is_engine_running(): - return - - if toggled: - self.host.transport_play() - else: - self.host.transport_pause() - - self.refreshTransport() - - @pyqtSlot() - def slot_transportStop(self): - if not self.host.is_engine_running(): - return - - self.host.transport_pause() - self.host.transport_relocate(0) - - self.refreshTransport() - - @pyqtSlot() - def slot_transportBackwards(self): - if not self.host.is_engine_running(): - return - - newFrame = self.host.get_current_transport_frame() - 100000 - - if newFrame < 0: - newFrame = 0 - - self.host.transport_relocate(newFrame) - - @pyqtSlot() - def slot_transportForwards(self): - if not self.host.is_engine_running(): - return - - newFrame = self.host.get_current_transport_frame() + 100000 - self.host.transport_relocate(newFrame) - - # ----------------------------------------------------------------- - @pyqtSlot() def slot_aboutCarla(self): CarlaAboutW(self, self.host).exec_() @@ -1008,16 +987,6 @@ class HostWindow(QMainWindow): @pyqtSlot(int, int, int, float, str) def slot_handleDebugCallback(self, pluginId, value1, value2, value3, valueStr): print("DEBUG:", pluginId, value1, value2, value3, valueStr) - #self.ui.pte_log.appendPlainText(valueStr.replace("", "DEBUG: ").replace("", "ERROR: ").replace("", "").replace("\n", "")) - - # ----------------------------------------------------------------- - - @pyqtSlot(float) - def slot_handleSampleRateChangedCallback(self, newSampleRate): - self.fSampleRate = newSampleRate - self.refreshTransport(True) - - # ----------------------------------------------------------------- @pyqtSlot(str) def slot_handleInfoCallback(self, info): @@ -1029,19 +998,7 @@ class HostWindow(QMainWindow): @pyqtSlot() def slot_handleQuitCallback(self): - pass - - # ----------------------------------------------------------------- - - @pyqtSlot() - def slot_handleSIGUSR1(self): - print("Got SIGUSR1 -> Saving project now") - self.slot_fileSave() - - @pyqtSlot() - def slot_handleSIGTERM(self): - print("Got SIGTERM -> Closing now") - self.close() + pass # TODO # ----------------------------------------------------------------- @@ -1082,7 +1039,7 @@ class HostWindow(QMainWindow): elif self.host.is_engine_running(): self.host.set_engine_about_to_close() - count = self.fContainer.getPluginCount() + count = self.host.get_current_plugin_count() if count > 0: # simulate project loading, to disable container @@ -1099,7 +1056,7 @@ class HostWindow(QMainWindow): #self.fContainer.removeAllPlugins() #self.host.remove_all_plugins() - self.stopEngine() + self.slot_engineStop() QMainWindow.closeEvent(self, event) diff --git a/source/carla_patchbay.py b/source/carla_patchbay.py index 6a1338080..ecdb995c6 100644 --- a/source/carla_patchbay.py +++ b/source/carla_patchbay.py @@ -231,6 +231,10 @@ class CarlaPatchbayW(QFrame, PluginEditParentMeta): parent.ui.act_settings_configure.triggered.connect(self.slot_configureCarla) + host.PluginAddedCallback.connect(self.slot_handlePluginAddedCallback) + host.PluginRemovedCallback.connect(self.slot_handlePluginRemovedCallback) + host.PluginRenamedCallback.connect(self.slot_handlePluginRenamedCallback) + host.PluginUnavailableCallback.connect(self.slot_handlePluginUnavailableCallback) host.ParameterValueChangedCallback.connect(self.slot_handleParameterValueChangedCallback) host.ParameterDefaultChangedCallback.connect(self.slot_handleParameterDefaultChangedCallback) host.ParameterMidiChannelChangedCallback.connect(self.slot_handleParameterMidiChannelChangedCallback) @@ -677,6 +681,24 @@ class CarlaPatchbayW(QFrame, PluginEditParentMeta): # ----------------------------------------------------------------- + @pyqtSlot(int, str) + def slot_handlePluginAddedCallback(self, pluginId, pluginName): + self.addPlugin(pluginId, self.fParent.isProjectLoading()) + + @pyqtSlot(int) + def slot_handlePluginRemovedCallback(self, pluginId): + self.removePlugin(pluginId) + + @pyqtSlot(int, str) + def slot_handlePluginRenamedCallback(self, pluginId, newName): + self.renamePlugin(pluginId, newName) + + @pyqtSlot(int, str) + def slot_handlePluginUnavailableCallback(self, pluginId, errorMsg): + self.disablePlugin(pluginId, errorMsg) + + # ----------------------------------------------------------------- + @pyqtSlot(int, int, float) def slot_handleParameterValueChangedCallback(self, pluginId, index, value): if pluginId >= self.fPluginCount: @@ -911,7 +933,7 @@ class CarlaPatchbayW(QFrame, PluginEditParentMeta): if pluginId < 0: return if pluginId >= self.fPluginCount: - print("sorry, can't map this plugin to canvas client", pluginId, self.getPluginCount()) + print("sorry, can't map this plugin to canvas client", pluginId, self.fPluginCount) return patchcanvas.setGroupAsPlugin(clientId, pluginId, bool(self.host.get_plugin_info(pluginId)['hints'] & PLUGIN_HAS_CUSTOM_UI)) diff --git a/source/carla_rack.py b/source/carla_rack.py index 2e3fc62b4..3977e4d6b 100644 --- a/source/carla_rack.py +++ b/source/carla_rack.py @@ -84,6 +84,7 @@ class CarlaRackList(QListWidget): if False: # kdevelop likes this :) host = CarlaHostMeta() + self.host = host # ------------------------------------------------------------- @@ -210,6 +211,7 @@ class CarlaRackW(QFrame): if False: # kdevelop likes this :) host = CarlaHostMeta() + self.host = host # ------------------------------------------------------------- @@ -305,6 +307,10 @@ class CarlaRackW(QFrame): parent.ui.act_settings_configure.triggered.connect(self.slot_configureCarla) + host.PluginAddedCallback.connect(self.slot_handlePluginAddedCallback) + host.PluginRemovedCallback.connect(self.slot_handlePluginRemovedCallback) + host.PluginRenamedCallback.connect(self.slot_handlePluginRenamedCallback) + host.PluginUnavailableCallback.connect(self.slot_handlePluginUnavailableCallback) host.ParameterValueChangedCallback.connect(self.slot_handleParameterValueChangedCallback) host.ParameterDefaultChangedCallback.connect(self.slot_handleParameterDefaultChangedCallback) host.ParameterMidiChannelChangedCallback.connect(self.slot_handleParameterMidiChannelChangedCallback) @@ -323,11 +329,6 @@ class CarlaRackW(QFrame): # ----------------------------------------------------------------- - def getPluginCount(self): - return self.fPluginCount - - # ----------------------------------------------------------------- - def addPlugin(self, pluginId, isProjectLoading): pitem = CarlaRackItem(self.fRack, pluginId) @@ -542,6 +543,24 @@ class CarlaRackW(QFrame): # ----------------------------------------------------------------- + @pyqtSlot(int, str) + def slot_handlePluginAddedCallback(self, pluginId, pluginName): + self.addPlugin(pluginId, self.fParent.isProjectLoading()) + + @pyqtSlot(int) + def slot_handlePluginRemovedCallback(self, pluginId): + self.removePlugin(pluginId) + + @pyqtSlot(int, str) + def slot_handlePluginRenamedCallback(self, pluginId, newName): + self.renamePlugin(pluginId, newName) + + @pyqtSlot(int, str) + def slot_handlePluginUnavailableCallback(self, pluginId, errorMsg): + self.disablePlugin(pluginId, errorMsg) + + # ----------------------------------------------------------------- + @pyqtSlot(int, int, float) def slot_handleParameterValueChangedCallback(self, pluginId, index, value): if pluginId >= self.fPluginCount: