| @@ -54,6 +54,16 @@ CARLA_BACKEND_START_NAMESPACE | |||
| */ | |||
| static const uint MAX_DEFAULT_PLUGINS = 99; | |||
| /*! | |||
| * Maximum number of loadable plugins in rack mode. | |||
| */ | |||
| static const uint MAX_RACK_PLUGINS = 16; | |||
| /*! | |||
| * Maximum number of loadable plugins in patchbay mode. | |||
| */ | |||
| static const uint MAX_PATCHBAY_PLUGINS = 255; | |||
| /*! | |||
| * Maximum default number of parameters allowed. | |||
| * @see ENGINE_OPTION_MAX_PARAMETERS | |||
| @@ -962,7 +972,7 @@ typedef enum { | |||
| /*! | |||
| * Set the engine processing mode. | |||
| * Default is ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS on Linux and ENGINE_PROCESS_MODE_CONTINUOUS_RACK for all other OSes. | |||
| * Default is ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS on Linux and ENGINE_PROCESS_MODE_PATCHBAY for all other OSes. | |||
| * @see EngineProcessMode | |||
| */ | |||
| ENGINE_OPTION_PROCESS_MODE = 1, | |||
| @@ -1131,10 +1141,15 @@ typedef enum { | |||
| */ | |||
| ENGINE_PROCESS_MODE_CONTINUOUS_RACK = 2, | |||
| /*! | |||
| * Single client, 'patchbay' mode. | |||
| */ | |||
| ENGINE_PROCESS_MODE_PATCHBAY = 3, | |||
| /*! | |||
| * Special mode, used in plugin-bridges only. | |||
| */ | |||
| ENGINE_PROCESS_MODE_BRIDGE = 3 | |||
| ENGINE_PROCESS_MODE_BRIDGE = 4 | |||
| } EngineProcessMode; | |||
| @@ -981,7 +981,7 @@ public: | |||
| /*! | |||
| * Force the engine to resend all patchbay clients, ports and connections again. | |||
| */ | |||
| virtual bool patchbayRefresh(); | |||
| virtual bool patchbayRefresh(const bool external); | |||
| #endif | |||
| // ------------------------------------------------------------------- | |||
| @@ -1149,8 +1149,8 @@ protected: | |||
| * Virtual functions for handling patchbay state. | |||
| * Do not free returned data. | |||
| */ | |||
| virtual const char* const* getPatchbayConnections() const; | |||
| virtual void restorePatchbayConnection(const char* const sourcePort, const char* const targetPort); | |||
| virtual const char* const* getPatchbayConnections(const bool external) const; | |||
| virtual void restorePatchbayConnection(const bool external, const char* const sourcePort, const char* const targetPort); | |||
| #endif | |||
| // ------------------------------------------------------------------- | |||
| @@ -418,8 +418,10 @@ CARLA_EXPORT bool carla_patchbay_disconnect(uint connectionId); | |||
| /*! | |||
| * Force the engine to resend all patchbay clients, ports and connections again. | |||
| * @param external Wherever to show external/hardware ports instead of internal ones. | |||
| * Only valid in patchbay engine mode, other modes will ignore this. | |||
| */ | |||
| CARLA_EXPORT bool carla_patchbay_refresh(); | |||
| CARLA_EXPORT bool carla_patchbay_refresh(bool external); | |||
| /*! | |||
| * Start playback of the engine transport. | |||
| @@ -728,12 +728,12 @@ bool carla_patchbay_disconnect(uint connectionId) | |||
| return false; | |||
| } | |||
| bool carla_patchbay_refresh() | |||
| bool carla_patchbay_refresh(bool external) | |||
| { | |||
| carla_debug("carla_patchbay_refresh()"); | |||
| carla_debug("carla_patchbay_refresh(%s)", bool2str(external)); | |||
| if (gStandalone.engine != nullptr) | |||
| return gStandalone.engine->patchbayRefresh(); | |||
| return gStandalone.engine->patchbayRefresh(external); | |||
| carla_stderr2("Engine is not running"); | |||
| gStandalone.lastError = "Engine is not running"; | |||
| @@ -87,10 +87,17 @@ CarlaPlugin::CarlaPlugin(CarlaEngine* const engine, const uint id) | |||
| { | |||
| case ENGINE_PROCESS_MODE_SINGLE_CLIENT: | |||
| case ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS: | |||
| case ENGINE_PROCESS_MODE_CONTINUOUS_RACK: | |||
| CARLA_SAFE_ASSERT(id < MAX_DEFAULT_PLUGINS); | |||
| break; | |||
| case ENGINE_PROCESS_MODE_CONTINUOUS_RACK: | |||
| CARLA_SAFE_ASSERT(id < MAX_RACK_PLUGINS); | |||
| break; | |||
| case ENGINE_PROCESS_MODE_PATCHBAY: | |||
| CARLA_SAFE_ASSERT(id < MAX_PATCHBAY_PLUGINS); | |||
| break; | |||
| case ENGINE_PROCESS_MODE_BRIDGE: | |||
| CARLA_SAFE_ASSERT(id == 0); | |||
| break; | |||
| @@ -144,6 +144,12 @@ def structToDict(struct): | |||
| # Maximum default number of loadable plugins. | |||
| MAX_DEFAULT_PLUGINS = 99 | |||
| # Maximum number of loadable plugins in rack mode. | |||
| MAX_RACK_PLUGINS = 16 | |||
| # Maximum number of loadable plugins in patchbay mode. | |||
| MAX_PATCHBAY_PLUGINS = 255 | |||
| # Maximum default number of parameters allowed. | |||
| # @see ENGINE_OPTION_MAX_PARAMETERS | |||
| MAX_DEFAULT_PARAMETERS = 200 | |||
| @@ -815,8 +821,11 @@ ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS = 1 | |||
| # Processes plugins in order of Id, with forced stereo always on. | |||
| ENGINE_PROCESS_MODE_CONTINUOUS_RACK = 2 | |||
| # Single client, 'patchbay' mode. | |||
| ENGINE_PROCESS_MODE_PATCHBAY = 3 | |||
| # Special mode, used in plugin-bridges only. | |||
| ENGINE_PROCESS_MODE_BRIDGE = 3 | |||
| ENGINE_PROCESS_MODE_BRIDGE = 4 | |||
| # ------------------------------------------------------------------------------------------------------------ | |||
| # Engine Transport Mode | |||
| @@ -1229,7 +1238,7 @@ class CarlaHostMeta(object): | |||
| self.nsmOK = False | |||
| # settings | |||
| self.processMode = ENGINE_PROCESS_MODE_CONTINUOUS_RACK | |||
| self.processMode = ENGINE_PROCESS_MODE_PATCHBAY | |||
| self.transportMode = ENGINE_TRANSPORT_MODE_INTERNAL | |||
| self.nextProcessMode = self.processMode | |||
| self.processModeForced = False | |||
| @@ -1372,7 +1381,7 @@ class CarlaHostMeta(object): | |||
| # @param external Wherever to show external/hardware ports instead of internal ones. | |||
| # Only valid in patchbay engine mode, other modes will ignore this. | |||
| @abstractmethod | |||
| def patchbay_refresh(self): | |||
| def patchbay_refresh(self, external): | |||
| raise NotImplementedError | |||
| # Start playback of the engine transport. | |||
| @@ -1926,7 +1935,7 @@ class CarlaHostNull(CarlaHostMeta): | |||
| def patchbay_disconnect(self, connectionId): | |||
| return False | |||
| def patchbay_refresh(self): | |||
| def patchbay_refresh(self, external): | |||
| return False | |||
| def transport_play(self): | |||
| @@ -2208,7 +2217,7 @@ class CarlaHostDLL(CarlaHostMeta): | |||
| self.lib.carla_patchbay_disconnect.argtypes = [c_uint] | |||
| self.lib.carla_patchbay_disconnect.restype = c_bool | |||
| self.lib.carla_patchbay_refresh.argtypes = None | |||
| self.lib.carla_patchbay_refresh.argtypes = [c_bool] | |||
| self.lib.carla_patchbay_refresh.restype = c_bool | |||
| self.lib.carla_transport_play.argtypes = None | |||
| @@ -2482,8 +2491,8 @@ class CarlaHostDLL(CarlaHostMeta): | |||
| def patchbay_disconnect(self, connectionId): | |||
| return bool(self.lib.carla_patchbay_disconnect(connectionId)) | |||
| def patchbay_refresh(self): | |||
| return bool(self.lib.carla_patchbay_refresh()) | |||
| def patchbay_refresh(self, external): | |||
| return bool(self.lib.carla_patchbay_refresh(external)) | |||
| def transport_play(self): | |||
| self.lib.carla_transport_play() | |||
| @@ -2819,7 +2828,8 @@ class CarlaHostPlugin(CarlaHostMeta): | |||
| def patchbay_disconnect(self, connectionId): | |||
| return self.sendMsgAndSetError(["patchbay_disconnect", connectionId]) | |||
| def patchbay_refresh(self): | |||
| def patchbay_refresh(self, external): | |||
| # don't send external param, never used in plugins | |||
| return self.sendMsgAndSetError(["patchbay_refresh"]) | |||
| def transport_play(self): | |||
| @@ -158,7 +158,10 @@ class HostWindow(QMainWindow): | |||
| # Internal stuff (patchbay) | |||
| self.fExportImage = QImage() | |||
| self.fPeaksCleared = True | |||
| self.fExternalPatchbay = False | |||
| self.fSelectedPlugins = [] | |||
| self.fCanvasWidth = 0 | |||
| @@ -216,6 +219,11 @@ class HostWindow(QMainWindow): | |||
| self.ui.act_engine_stop.setEnabled(False) | |||
| self.ui.act_plugin_remove_all.setEnabled(False) | |||
| self.ui.act_canvas_show_internal.setChecked(False) | |||
| self.ui.act_canvas_show_internal.setVisible(False) | |||
| self.ui.act_canvas_show_external.setChecked(False) | |||
| self.ui.act_canvas_show_external.setVisible(False) | |||
| self.ui.menu_PluginMacros.setEnabled(False) | |||
| self.ui.menu_Canvas.setEnabled(False) | |||
| @@ -223,6 +231,8 @@ class HostWindow(QMainWindow): | |||
| self.ui.dockWidget.setTitleBarWidget(self.ui.dockWidgetTitleBar) | |||
| if not withCanvas: | |||
| self.ui.act_canvas_show_internal.setVisible(False) | |||
| self.ui.act_canvas_show_external.setVisible(False) | |||
| self.ui.act_canvas_arrange.setVisible(False) | |||
| self.ui.act_canvas_refresh.setVisible(False) | |||
| self.ui.act_canvas_save_image.setVisible(False) | |||
| @@ -349,7 +359,6 @@ class HostWindow(QMainWindow): | |||
| self.ui.act_file_quit.setMenuRole(QAction.QuitRole) | |||
| self.ui.act_settings_configure.setMenuRole(QAction.PreferencesRole) | |||
| self.ui.act_help_about.setMenuRole(QAction.AboutRole) | |||
| self.ui.act_help_about_juce.setMenuRole(QAction.ApplicationSpecificRole) | |||
| self.ui.act_help_about_qt.setMenuRole(QAction.AboutQtRole) | |||
| self.ui.menu_Settings.setTitle("Panels") | |||
| self.ui.menu_Help.menuAction().setVisible(False) | |||
| @@ -401,6 +410,8 @@ class HostWindow(QMainWindow): | |||
| self.ui.act_plugins_expand.triggered.connect(self.slot_pluginsExpand) | |||
| self.ui.act_plugins_panic.triggered.connect(self.slot_pluginsDisable) | |||
| self.ui.act_canvas_show_internal.triggered.connect(self.slot_canvasShowInternal) | |||
| self.ui.act_canvas_show_external.triggered.connect(self.slot_canvasShowExternal) | |||
| self.ui.act_canvas_arrange.triggered.connect(self.slot_canvasArrange) | |||
| self.ui.act_canvas_refresh.triggered.connect(self.slot_canvasRefresh) | |||
| self.ui.act_canvas_zoom_fit.triggered.connect(self.slot_canvasZoomFit) | |||
| @@ -498,6 +509,10 @@ class HostWindow(QMainWindow): | |||
| if self.host.isPlugin: | |||
| self.startTimers() | |||
| # Start in patchbay tab if using forced patchbay mode | |||
| if host.processModeForced and host.processMode == ENGINE_PROCESS_MODE_PATCHBAY and not host.isControl: | |||
| self.ui.tabWidget.setCurrentIndex(1) | |||
| # Load initial project file if set | |||
| if not (self.host.isControl or self.host.isPlugin): | |||
| projectFile = getInitialProjectFile(QApplication.instance()) | |||
| @@ -745,6 +760,23 @@ class HostWindow(QMainWindow): | |||
| self.ui.menu_PluginMacros.setEnabled(True) | |||
| self.ui.menu_Canvas.setEnabled(True) | |||
| self.ui.act_canvas_show_internal.blockSignals(True) | |||
| self.ui.act_canvas_show_external.blockSignals(True) | |||
| if processMode == ENGINE_PROCESS_MODE_PATCHBAY and not (self.host.isControl or self.host.isPlugin): | |||
| self.ui.act_canvas_show_internal.setChecked(True) | |||
| self.ui.act_canvas_show_internal.setVisible(True) | |||
| self.ui.act_canvas_show_external.setChecked(False) | |||
| self.ui.act_canvas_show_external.setVisible(True) | |||
| else: | |||
| self.ui.act_canvas_show_internal.setChecked(False) | |||
| self.ui.act_canvas_show_internal.setVisible(False) | |||
| self.ui.act_canvas_show_external.setChecked(False) | |||
| self.ui.act_canvas_show_external.setVisible(False) | |||
| self.ui.act_canvas_show_internal.blockSignals(False) | |||
| self.ui.act_canvas_show_external.blockSignals(False) | |||
| if not (self.host.isControl or self.host.isPlugin): | |||
| canSave = (self.fProjectFilename and os.path.exists(self.fProjectFilename)) or not self.fSessionManagerName | |||
| self.ui.act_file_save.setEnabled(canSave) | |||
| @@ -1166,6 +1198,28 @@ class HostWindow(QMainWindow): | |||
| # -------------------------------------------------------------------------------------------------------- | |||
| # Canvas (menu actions) | |||
| @pyqtSlot() | |||
| def slot_canvasShowInternal(self): | |||
| self.fExternalPatchbay = False | |||
| self.ui.act_canvas_show_internal.blockSignals(True) | |||
| self.ui.act_canvas_show_external.blockSignals(True) | |||
| self.ui.act_canvas_show_internal.setChecked(True) | |||
| self.ui.act_canvas_show_external.setChecked(False) | |||
| self.ui.act_canvas_show_internal.blockSignals(False) | |||
| self.ui.act_canvas_show_external.blockSignals(False) | |||
| self.slot_canvasRefresh() | |||
| @pyqtSlot() | |||
| def slot_canvasShowExternal(self): | |||
| self.fExternalPatchbay = True | |||
| self.ui.act_canvas_show_internal.blockSignals(True) | |||
| self.ui.act_canvas_show_external.blockSignals(True) | |||
| self.ui.act_canvas_show_internal.setChecked(False) | |||
| self.ui.act_canvas_show_external.setChecked(True) | |||
| self.ui.act_canvas_show_internal.blockSignals(False) | |||
| self.ui.act_canvas_show_external.blockSignals(False) | |||
| self.slot_canvasRefresh() | |||
| @pyqtSlot() | |||
| def slot_canvasArrange(self): | |||
| patchcanvas.arrange() | |||
| @@ -1178,7 +1232,7 @@ class HostWindow(QMainWindow): | |||
| return | |||
| if self.host.is_engine_running(): | |||
| self.host.patchbay_refresh() | |||
| self.host.patchbay_refresh(self.fExternalPatchbay) | |||
| self.updateMiniCanvasLater() | |||
| @@ -1502,7 +1556,7 @@ class HostWindow(QMainWindow): | |||
| if self.host.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK and self.host.isPlugin: | |||
| pass | |||
| elif self.host.is_engine_running(): | |||
| self.host.patchbay_refresh() | |||
| self.host.patchbay_refresh(self.fExternalPatchbay) | |||
| for pitem in self.fPluginList: | |||
| if pitem is None: | |||
| @@ -293,7 +293,7 @@ if LINUX: | |||
| CARLA_DEFAULT_PROCESS_MODE = ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS | |||
| CARLA_DEFAULT_TRANSPORT_MODE = ENGINE_TRANSPORT_MODE_JACK | |||
| else: | |||
| CARLA_DEFAULT_PROCESS_MODE = ENGINE_PROCESS_MODE_CONTINUOUS_RACK | |||
| CARLA_DEFAULT_PROCESS_MODE = ENGINE_PROCESS_MODE_PATCHBAY | |||
| CARLA_DEFAULT_TRANSPORT_MODE = ENGINE_TRANSPORT_MODE_INTERNAL | |||
| # Wine | |||
| @@ -259,6 +259,90 @@ static const NativePluginDescriptor sNativePluginDescriptors[] = { | |||
| /* copyright */ "GNU GPL v2+", | |||
| DESCFUNCS | |||
| }, | |||
| { | |||
| /* category */ NATIVE_PLUGIN_CATEGORY_OTHER, | |||
| /* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_SYNTH | |||
| |NATIVE_PLUGIN_HAS_UI | |||
| //|NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS | |||
| |NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD | |||
| |NATIVE_PLUGIN_USES_STATE | |||
| |NATIVE_PLUGIN_USES_TIME), | |||
| /* supports */ static_cast<NativePluginSupports>(NATIVE_PLUGIN_SUPPORTS_EVERYTHING), | |||
| /* audioIns */ 2, | |||
| /* audioOuts */ 2, | |||
| /* midiIns */ 1, | |||
| /* midiOuts */ 1, | |||
| /* paramIns */ 0, | |||
| /* paramOuts */ 0, | |||
| /* name */ "Carla-Patchbay", | |||
| /* label */ "carlapatchbay", | |||
| /* maker */ "falkTX", | |||
| /* copyright */ "GNU GPL v2+", | |||
| DESCFUNCS | |||
| }, | |||
| { | |||
| /* category */ NATIVE_PLUGIN_CATEGORY_OTHER, | |||
| /* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_SYNTH | |||
| |NATIVE_PLUGIN_HAS_UI | |||
| //|NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS | |||
| |NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD | |||
| |NATIVE_PLUGIN_USES_STATE | |||
| |NATIVE_PLUGIN_USES_TIME), | |||
| /* supports */ static_cast<NativePluginSupports>(NATIVE_PLUGIN_SUPPORTS_EVERYTHING), | |||
| /* audioIns */ 3, | |||
| /* audioOuts */ 2, | |||
| /* midiIns */ 1, | |||
| /* midiOuts */ 1, | |||
| /* paramIns */ 0, | |||
| /* paramOuts */ 0, | |||
| /* name */ "Carla-Patchbay (sidechain)", | |||
| /* label */ "carlapatchbay3s", | |||
| /* maker */ "falkTX", | |||
| /* copyright */ "GNU GPL v2+", | |||
| DESCFUNCS | |||
| }, | |||
| { | |||
| /* category */ NATIVE_PLUGIN_CATEGORY_OTHER, | |||
| /* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_SYNTH | |||
| |NATIVE_PLUGIN_HAS_UI | |||
| //|NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS | |||
| |NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD | |||
| |NATIVE_PLUGIN_USES_STATE | |||
| |NATIVE_PLUGIN_USES_TIME), | |||
| /* supports */ static_cast<NativePluginSupports>(NATIVE_PLUGIN_SUPPORTS_EVERYTHING), | |||
| /* audioIns */ 16, | |||
| /* audioOuts */ 16, | |||
| /* midiIns */ 1, | |||
| /* midiOuts */ 1, | |||
| /* paramIns */ 0, | |||
| /* paramOuts */ 0, | |||
| /* name */ "Carla-Patchbay (16chan)", | |||
| /* label */ "carlapatchbay16", | |||
| /* maker */ "falkTX", | |||
| /* copyright */ "GNU GPL v2+", | |||
| DESCFUNCS | |||
| }, | |||
| { | |||
| /* category */ NATIVE_PLUGIN_CATEGORY_OTHER, | |||
| /* hints */ static_cast<NativePluginHints>(NATIVE_PLUGIN_IS_SYNTH | |||
| |NATIVE_PLUGIN_HAS_UI | |||
| //|NATIVE_PLUGIN_NEEDS_FIXED_BUFFERS | |||
| |NATIVE_PLUGIN_NEEDS_UI_MAIN_THREAD | |||
| |NATIVE_PLUGIN_USES_STATE | |||
| |NATIVE_PLUGIN_USES_TIME), | |||
| /* supports */ static_cast<NativePluginSupports>(NATIVE_PLUGIN_SUPPORTS_EVERYTHING), | |||
| /* audioIns */ 32, | |||
| /* audioOuts */ 32, | |||
| /* midiIns */ 1, | |||
| /* midiOuts */ 1, | |||
| /* paramIns */ 0, | |||
| /* paramOuts */ 0, | |||
| /* name */ "Carla-Patchbay (32chan)", | |||
| /* label */ "carlapatchbay32", | |||
| /* maker */ "falkTX", | |||
| /* copyright */ "GNU GPL v2+", | |||
| DESCFUNCS | |||
| }, | |||
| #endif | |||
| // ----------------------------------------------------------------------- | |||
| @@ -471,10 +471,17 @@ class CarlaEmbedW(QEmbedWidget): | |||
| self.addShortcutActions(self.gui.ui.menu_Settings.actions()) | |||
| self.addShortcutActions(self.gui.ui.menu_Help.actions()) | |||
| if self.host.processMode == ENGINE_PROCESS_MODE_PATCHBAY: | |||
| self.addShortcutActions(self.gui.ui.menu_Canvas.actions()) | |||
| self.addShortcutActions(self.gui.ui.menu_Canvas_Zoom.actions()) | |||
| self.addWidget(self.gui.ui.menubar) | |||
| self.addLine() | |||
| self.addWidget(self.gui.ui.toolBar) | |||
| if self.host.processMode == ENGINE_PROCESS_MODE_PATCHBAY: | |||
| self.addLine() | |||
| self.addWidget(self.gui.centralWidget()) | |||
| self.finalSetup(self.gui, winId) | |||
| @@ -564,7 +571,7 @@ if __name__ == '__main__': | |||
| # Init host backend | |||
| host = initHost("Carla-Plugin", None, False, True, True, PluginHost) | |||
| host.processMode = ENGINE_PROCESS_MODE_CONTINUOUS_RACK | |||
| host.processMode = ENGINE_PROCESS_MODE_PATCHBAY if sys.argv[0].lower().endswith("/carla-plugin-patchbay") else ENGINE_PROCESS_MODE_CONTINUOUS_RACK | |||
| host.processModeForced = True | |||
| host.nextProcessMode = host.processMode | |||
| loadHostSettings(host) | |||