2 # SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
3 # SPDX-License-Identifier: GPL-2.0-or-later
5 # ------------------------------------------------------------------------------------------------------------
10 # ------------------------------------------------------------------------------------------------------------
17 # ------------------------------------------------------------------------------------------------------------
20 from qt_compat
import qt_config
23 # This fails in some configurations, assume >= 5.6.0 in that case
25 from PyQt5
.Qt
import PYQT_VERSION
27 PYQT_VERSION
= 0x50600
29 from PyQt5
.QtCore
import (
42 from PyQt5
.QtGui
import (
49 from PyQt5
.QtWidgets
import (
60 from PyQt6
.QtCore
import (
74 from PyQt6
.QtGui
import (
83 from PyQt6
.QtWidgets
import (
91 # ------------------------------------------------------------------------------------------------------------
96 from carla_app
import *
97 from carla_backend
import *
98 from carla_backend_qt
import CarlaHostQtDLL
, CarlaHostQtNull
99 from carla_frontend
import CarlaFrontendLib
100 from carla_shared
import *
101 from carla_settings
import *
102 from carla_utils
import *
103 from carla_widgets
import *
105 from patchcanvas
import patchcanvas
106 from widgets
.digitalpeakmeter
import DigitalPeakMeter
107 from widgets
.pixmapkeyboard
import PixmapKeyboardHArea
109 # ------------------------------------------------------------------------------------------------------------
113 from PyQt5
.QtOpenGL
import QGLWidget
118 # ------------------------------------------------------------------------------------------------------------
119 # Safe exception hook, needed for PyQt5
121 def sys_excepthook(typ
, value
, tback
):
122 return sys
.__excepthook
__(typ
, value
, tback
)
124 # ------------------------------------------------------------------------------------------------------------
125 # Session Management support
127 CARLA_CLIENT_NAME
= os
.getenv("CARLA_CLIENT_NAME")
128 LADISH_APP_NAME
= os
.getenv("LADISH_APP_NAME")
129 NSM_URL
= os
.getenv("NSM_URL")
131 # ------------------------------------------------------------------------------------------------------------
134 def processMode2Str(processMode
):
135 if processMode
== ENGINE_PROCESS_MODE_SINGLE_CLIENT
:
136 return "Single client"
137 if processMode
== ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS
:
138 return "Multi client"
139 if processMode
== ENGINE_PROCESS_MODE_CONTINUOUS_RACK
:
140 return "Continuous Rack"
141 if processMode
== ENGINE_PROCESS_MODE_PATCHBAY
:
143 if processMode
== ENGINE_PROCESS_MODE_BRIDGE
:
147 # ------------------------------------------------------------------------------------------------------------
151 def __init__(self
, err
):
155 gCarla
.utils
.fflush(self
.err
)
157 def write(self
, string
):
158 gCarla
.utils
.fputs(self
.err
, string
)
160 # ------------------------------------------------------------------------------------------------------------
163 class HostWindow(QMainWindow
):
164 #class HostWindow(QMainWindow, PluginEditParentMeta, metaclass=PyQtMetaClass):
166 SIGTERM
= pyqtSignal()
167 SIGUSR1
= pyqtSignal()
170 CUSTOM_ACTION_NONE
= 0
171 CUSTOM_ACTION_APP_CLOSE
= 1
172 CUSTOM_ACTION_PROJECT_LOAD
= 2
174 # --------------------------------------------------------------------------------------------------------
176 def __init__(self
, host
, withCanvas
, parent
=None):
177 QMainWindow
.__init
__(self
, parent
)
179 self
.ui
= ui_carla_host
.Ui_CarlaHostW()
180 self
.ui
.setupUi(self
)
184 # kdevelop likes this :)
185 host
= CarlaHostNull()
188 self
._true
= c_char_p("true".encode("utf-8"))
190 self
.fParentOrSelf
= parent
or self
192 # ----------------------------------------------------------------------------------------------------
195 self
.fIdleTimerNull
= self
.startTimer(1000) # keep application signals alive
196 self
.fIdleTimerFast
= 0
197 self
.fIdleTimerSlow
= 0
199 self
.fLadspaRdfNeedsUpdate
= True
200 self
.fLadspaRdfList
= []
202 self
.fPluginCount
= 0
203 self
.fPluginList
= []
205 self
.fPluginListDialog
= None
206 self
.fFavoritePlugins
= []
208 self
.fProjectFilename
= ""
209 self
.fIsProjectLoading
= False
210 self
.fCurrentlyRemovingAllPlugins
= False
211 self
.fHasLoadedLv2Plugins
= False
213 self
.fLastTransportBPM
= 0.0
214 self
.fLastTransportFrame
= 0
215 self
.fLastTransportState
= False
217 self
.fSampleRate
= 0.0
218 self
.fOscAddressTCP
= ""
219 self
.fOscAddressUDP
= ""
222 self
.fMacClosingHelper
= True
224 # CancelableActionCallback Box
225 self
.fCancelableActionBox
= None
227 # run a custom action after engine is properly closed
228 self
.fCustomStopAction
= self
.CUSTOM_ACTION_NONE
230 # first attempt of auto-start engine doesn't show an error
231 self
.fFirstEngineInit
= True
233 # to be filled with key-value pairs of current settings
234 self
.fSavedSettings
= {}
236 # true if NSM server handles our window management
237 self
.fWindowCloseHideGui
= False
240 self
.fClientName
= "Carla-Control"
241 self
.fSessionManagerName
= "Control"
243 self
.fClientName
= "Carla-Plugin"
244 self
.fSessionManagerName
= "Plugin"
245 elif LADISH_APP_NAME
:
246 self
.fClientName
= LADISH_APP_NAME
247 self
.fSessionManagerName
= ""
248 elif NSM_URL
and host
.nsmOK
:
249 self
.fClientName
= "Carla.tmp"
250 self
.fSessionManagerName
= "Non Session Manager TMP"
251 self
.fWindowCloseHideGui
= True
253 self
.fClientName
= CARLA_CLIENT_NAME
or "Carla"
254 self
.fSessionManagerName
= ""
256 # ----------------------------------------------------------------------------------------------------
257 # Internal stuff (patchbay)
259 self
.fPeaksCleared
= True
261 self
.fExternalPatchbay
= False
262 self
.fSelectedPlugins
= []
264 self
.fCanvasWidth
= 0
265 self
.fCanvasHeight
= 0
266 self
.fMiniCanvasUpdateTimeout
= 0
268 self
.fWithCanvas
= withCanvas
270 # ----------------------------------------------------------------------------------------------------
271 # Internal stuff (logs)
273 self
.autoscrollOnNewLog
= True
274 self
.lastLogSliderPos
= 0
276 # ----------------------------------------------------------------------------------------------------
277 # Set up GUI (engine stopped)
279 if self
.host
.isPlugin
or self
.host
.isControl
:
280 self
.ui
.act_file_save
.setVisible(False)
281 self
.ui
.act_engine_start
.setEnabled(False)
282 self
.ui
.act_engine_start
.setVisible(False)
283 self
.ui
.act_engine_stop
.setEnabled(False)
284 self
.ui
.act_engine_stop
.setVisible(False)
285 self
.ui
.menu_Engine
.setEnabled(False)
286 self
.ui
.menu_Engine
.setVisible(False)
287 self
.ui
.menu_Engine
.menuAction().setVisible(False)
288 self
.ui
.tabWidget
.removeTab(2)
290 if self
.host
.isControl
:
291 self
.ui
.act_file_new
.setVisible(False)
292 self
.ui
.act_file_open
.setVisible(False)
293 self
.ui
.act_file_save_as
.setVisible(False)
294 self
.ui
.tabUtils
.removeTab(0)
296 self
.ui
.act_file_save_as
.setText(self
.tr("Export as..."))
299 self
.ui
.tabWidget
.tabBar().hide()
302 self
.ui
.act_engine_start
.setEnabled(True)
305 self
.ui
.tabWidget
.removeTab(2)
307 if self
.host
.isControl
:
308 self
.ui
.act_file_refresh
.setEnabled(False)
310 self
.ui
.act_file_connect
.setEnabled(False)
311 self
.ui
.act_file_connect
.setVisible(False)
312 self
.ui
.act_file_refresh
.setEnabled(False)
313 self
.ui
.act_file_refresh
.setVisible(False)
315 if self
.fSessionManagerName
and not self
.host
.isPlugin
:
316 self
.ui
.act_file_new
.setEnabled(False)
318 self
.ui
.act_file_open
.setEnabled(False)
319 self
.ui
.act_file_save
.setEnabled(False)
320 self
.ui
.act_file_save_as
.setEnabled(False)
321 self
.ui
.act_engine_stop
.setEnabled(False)
322 self
.ui
.act_plugin_remove_all
.setEnabled(False)
324 self
.ui
.act_canvas_show_internal
.setChecked(False)
325 self
.ui
.act_canvas_show_internal
.setVisible(False)
326 self
.ui
.act_canvas_show_external
.setChecked(False)
327 self
.ui
.act_canvas_show_external
.setVisible(False)
329 self
.ui
.menu_PluginMacros
.setEnabled(False)
330 self
.ui
.menu_Canvas
.setEnabled(False)
332 self
.ui
.dockWidgetTitleBar
= QWidget(self
)
333 self
.ui
.dockWidget
.setTitleBarWidget(self
.ui
.dockWidgetTitleBar
)
336 self
.ui
.act_canvas_show_internal
.setVisible(False)
337 self
.ui
.act_canvas_show_external
.setVisible(False)
338 self
.ui
.act_canvas_arrange
.setVisible(False)
339 self
.ui
.act_canvas_refresh
.setVisible(False)
340 self
.ui
.act_canvas_save_image
.setVisible(False)
341 self
.ui
.act_canvas_zoom_100
.setVisible(False)
342 self
.ui
.act_canvas_zoom_fit
.setVisible(False)
343 self
.ui
.act_canvas_zoom_in
.setVisible(False)
344 self
.ui
.act_canvas_zoom_out
.setVisible(False)
345 self
.ui
.act_settings_show_meters
.setVisible(False)
346 self
.ui
.act_settings_show_keyboard
.setVisible(False)
347 self
.ui
.menu_Canvas_Zoom
.setEnabled(False)
348 self
.ui
.menu_Canvas_Zoom
.setVisible(False)
349 self
.ui
.menu_Canvas_Zoom
.menuAction().setVisible(False)
350 self
.ui
.menu_Canvas
.setEnabled(False)
351 self
.ui
.menu_Canvas
.setVisible(False)
352 self
.ui
.menu_Canvas
.menuAction().setVisible(False)
353 self
.ui
.tw_miniCanvas
.hide()
354 self
.ui
.tabWidget
.removeTab(1)
356 self
.ui
.tabWidget
.tabBar().hide()
358 # ----------------------------------------------------------------------------------------------------
361 exts
= gCarla
.utils
.get_supported_file_extensions()
363 self
.fDirModel
= QFileSystemModel(self
)
364 self
.fDirModel
.setRootPath(HOME
)
365 self
.fDirModel
.setNameFilters(tuple(("*." + i
) for i
in exts
))
367 self
.ui
.fileTreeView
.setModel(self
.fDirModel
)
368 self
.ui
.fileTreeView
.setRootIndex(self
.fDirModel
.index(HOME
))
369 self
.ui
.fileTreeView
.setColumnHidden(1, True)
370 self
.ui
.fileTreeView
.setColumnHidden(2, True)
371 self
.ui
.fileTreeView
.setColumnHidden(3, True)
372 self
.ui
.fileTreeView
.setHeaderHidden(True)
374 # ----------------------------------------------------------------------------------------------------
375 # Set up GUI (transport)
377 fontMetrics
= self
.ui
.l_transport_bbt
.fontMetrics()
378 minValueWidth
= fontMetricsHorizontalAdvance(fontMetrics
, "000|00|0000")
379 minLabelWidth
= fontMetricsHorizontalAdvance(fontMetrics
, self
.ui
.label_transport_frame
.text())
381 labelTimeWidth
= fontMetricsHorizontalAdvance(fontMetrics
, self
.ui
.label_transport_time
.text())
382 labelBBTWidth
= fontMetricsHorizontalAdvance(fontMetrics
, self
.ui
.label_transport_bbt
.text())
384 if minLabelWidth
< labelTimeWidth
:
385 minLabelWidth
= labelTimeWidth
386 if minLabelWidth
< labelBBTWidth
:
387 minLabelWidth
= labelBBTWidth
389 self
.ui
.label_transport_frame
.setMinimumWidth(minLabelWidth
+ 3)
390 self
.ui
.label_transport_time
.setMinimumWidth(minLabelWidth
+ 3)
391 self
.ui
.label_transport_bbt
.setMinimumWidth(minLabelWidth
+ 3)
393 self
.ui
.l_transport_bbt
.setMinimumWidth(minValueWidth
+ 3)
394 self
.ui
.l_transport_frame
.setMinimumWidth(minValueWidth
+ 3)
395 self
.ui
.l_transport_time
.setMinimumWidth(minValueWidth
+ 3)
398 self
.ui
.b_transport_play
.setEnabled(False)
399 self
.ui
.b_transport_stop
.setEnabled(False)
400 self
.ui
.b_transport_backwards
.setEnabled(False)
401 self
.ui
.b_transport_forwards
.setEnabled(False)
402 self
.ui
.group_transport_controls
.setEnabled(False)
403 self
.ui
.group_transport_controls
.setVisible(False)
404 self
.ui
.cb_transport_link
.setEnabled(False)
405 self
.ui
.cb_transport_link
.setVisible(False)
406 self
.ui
.cb_transport_jack
.setEnabled(False)
407 self
.ui
.cb_transport_jack
.setVisible(False)
408 self
.ui
.dsb_transport_bpm
.setEnabled(False)
409 self
.ui
.dsb_transport_bpm
.setReadOnly(True)
411 self
.ui
.w_transport
.setEnabled(False)
413 # ----------------------------------------------------------------------------------------------------
416 self
.ui
.listWidget
.setHostAndParent(self
.host
, self
)
418 sb
= self
.ui
.listWidget
.verticalScrollBar()
419 self
.ui
.rackScrollBar
.setMinimum(sb
.minimum())
420 self
.ui
.rackScrollBar
.setMaximum(sb
.maximum())
421 self
.ui
.rackScrollBar
.setValue(sb
.value())
423 sb
.rangeChanged
.connect(self
.ui
.rackScrollBar
.setRange
)
424 sb
.valueChanged
.connect(self
.ui
.rackScrollBar
.setValue
)
425 self
.ui
.rackScrollBar
.rangeChanged
.connect(sb
.setRange
)
426 self
.ui
.rackScrollBar
.valueChanged
.connect(sb
.setValue
)
430 self
.ui
.rack
.setStyleSheet("""
431 CarlaRackList#CarlaRackList {
432 background-color: black;
436 # ----------------------------------------------------------------------------------------------------
437 # Set up GUI (patchbay)
439 self
.ui
.peak_in
.setChannelCount(2)
440 self
.ui
.peak_in
.setMeterColor(DigitalPeakMeter
.COLOR_BLUE
)
441 self
.ui
.peak_in
.setMeterOrientation(DigitalPeakMeter
.VERTICAL
)
442 self
.ui
.peak_in
.setFixedWidth(25)
444 self
.ui
.peak_out
.setChannelCount(2)
445 self
.ui
.peak_out
.setMeterColor(DigitalPeakMeter
.COLOR_GREEN
)
446 self
.ui
.peak_out
.setMeterOrientation(DigitalPeakMeter
.VERTICAL
)
447 self
.ui
.peak_out
.setFixedWidth(25)
449 self
.ui
.scrollArea
= PixmapKeyboardHArea(self
.ui
.patchbay
)
450 self
.ui
.keyboard
= self
.ui
.scrollArea
.keyboard
451 self
.ui
.patchbay
.layout().addWidget(self
.ui
.scrollArea
, 1, 0, 1, 0)
453 self
.ui
.scrollArea
.setEnabled(False)
455 self
.ui
.miniCanvasPreview
.setRealParent(self
)
456 self
.ui
.tw_miniCanvas
.tabBar().hide()
458 # ----------------------------------------------------------------------------------------------------
461 self
.ui
.text_logs
.textChanged
.connect(self
.slot_logButtonsState
)
462 self
.ui
.logs_clear
.clicked
.connect(self
.slot_logClear
)
463 self
.ui
.logs_save
.clicked
.connect(self
.slot_logSave
)
464 self
.ui
.logs_autoscroll
.stateChanged
.connect(self
.slot_toggleLogAutoscroll
)
465 self
.ui
.text_logs
.verticalScrollBar().valueChanged
.connect(self
.slot_logSliderMoved
)
467 # ----------------------------------------------------------------------------------------------------
468 # Set up GUI (special stuff for Mac OS)
471 self
.ui
.act_file_quit
.setMenuRole(QAction
.QuitRole
)
472 self
.ui
.act_settings_configure
.setMenuRole(QAction
.PreferencesRole
)
473 self
.ui
.act_help_about
.setMenuRole(QAction
.AboutRole
)
474 self
.ui
.act_help_about_qt
.setMenuRole(QAction
.AboutQtRole
)
475 self
.ui
.menu_Settings
.setTitle("Panels")
477 # ----------------------------------------------------------------------------------------------------
480 self
.loadSettings(True)
482 # ----------------------------------------------------------------------------------------------------
486 self
.scene
= patchcanvas
.PatchScene(self
, self
.ui
.graphicsView
)
487 self
.ui
.graphicsView
.setScene(self
.scene
)
489 if self
.fSavedSettings
[CARLA_KEY_CANVAS_USE_OPENGL
] and hasGL
:
490 self
.ui
.glView
= QGLWidget(self
)
491 self
.ui
.graphicsView
.setViewport(self
.ui
.glView
)
495 # ----------------------------------------------------------------------------------------------------
498 if self
.fSavedSettings
[CARLA_KEY_MAIN_SYSTEM_ICONS
]:
499 self
.ui
.act_file_connect
.setIcon(getIcon('network-connect', 16, 'svgz'))
500 self
.ui
.act_file_refresh
.setIcon(getIcon('view-refresh', 16, 'svgz'))
501 self
.ui
.act_file_new
.setIcon(getIcon('document-new', 16, 'svgz'))
502 self
.ui
.act_file_open
.setIcon(getIcon('document-open', 16, 'svgz'))
503 self
.ui
.act_file_save
.setIcon(getIcon('document-save', 16, 'svgz'))
504 self
.ui
.act_file_save_as
.setIcon(getIcon('document-save-as', 16, 'svgz'))
505 self
.ui
.act_file_quit
.setIcon(getIcon('application-exit', 16, 'svgz'))
506 self
.ui
.act_engine_start
.setIcon(getIcon('media-playback-start', 16, 'svgz'))
507 self
.ui
.act_engine_stop
.setIcon(getIcon('media-playback-stop', 16, 'svgz'))
508 self
.ui
.act_engine_panic
.setIcon(getIcon('dialog-warning', 16, 'svgz'))
509 self
.ui
.act_engine_config
.setIcon(getIcon('configure', 16, 'svgz'))
510 self
.ui
.act_plugin_add
.setIcon(getIcon('list-add', 16, 'svgz'))
511 self
.ui
.act_plugin_add_jack
.setIcon(getIcon('list-add', 16, 'svgz'))
512 self
.ui
.act_plugin_remove_all
.setIcon(getIcon('edit-delete', 16, 'svgz'))
513 self
.ui
.act_canvas_arrange
.setIcon(getIcon('view-sort-ascending', 16, 'svgz'))
514 self
.ui
.act_canvas_refresh
.setIcon(getIcon('view-refresh', 16, 'svgz'))
515 self
.ui
.act_canvas_zoom_fit
.setIcon(getIcon('zoom-fit-best', 16, 'svgz'))
516 self
.ui
.act_canvas_zoom_in
.setIcon(getIcon('zoom-in', 16, 'svgz'))
517 self
.ui
.act_canvas_zoom_out
.setIcon(getIcon('zoom-out', 16, 'svgz'))
518 self
.ui
.act_canvas_zoom_100
.setIcon(getIcon('zoom-original', 16, 'svgz'))
519 self
.ui
.act_settings_configure
.setIcon(getIcon('configure', 16, 'svgz'))
520 self
.ui
.b_disk_add
.setIcon(getIcon('list-add', 16, 'svgz'))
521 self
.ui
.b_disk_remove
.setIcon(getIcon('list-remove', 16, 'svgz'))
522 self
.ui
.b_transport_play
.setIcon(getIcon('media-playback-start', 16, 'svgz'))
523 self
.ui
.b_transport_stop
.setIcon(getIcon('media-playback-stop', 16, 'svgz'))
524 self
.ui
.b_transport_backwards
.setIcon(getIcon('media-seek-backward', 16, 'svgz'))
525 self
.ui
.b_transport_forwards
.setIcon(getIcon('media-seek-forward', 16, 'svgz'))
526 self
.ui
.logs_clear
.setIcon(getIcon('edit-clear', 16, 'svgz'))
527 self
.ui
.logs_save
.setIcon(getIcon('document-save', 16, 'svgz'))
529 # ----------------------------------------------------------------------------------------------------
530 # Connect actions to functions
532 self
.ui
.act_file_new
.triggered
.connect(self
.slot_fileNew
)
533 self
.ui
.act_file_open
.triggered
.connect(self
.slot_fileOpen
)
534 self
.ui
.act_file_save
.triggered
.connect(self
.slot_fileSave
)
535 self
.ui
.act_file_save_as
.triggered
.connect(self
.slot_fileSaveAs
)
537 self
.ui
.act_engine_start
.triggered
.connect(self
.slot_engineStart
)
538 self
.ui
.act_engine_stop
.triggered
.connect(self
.slot_engineStop
)
539 self
.ui
.act_engine_panic
.triggered
.connect(self
.slot_pluginsDisable
)
540 self
.ui
.act_engine_config
.triggered
.connect(self
.slot_engineConfig
)
542 self
.ui
.act_plugin_add
.triggered
.connect(self
.slot_pluginAdd
)
543 self
.ui
.act_plugin_add_jack
.triggered
.connect(self
.slot_jackAppAdd
)
544 self
.ui
.act_plugin_remove_all
.triggered
.connect(self
.slot_confirmRemoveAll
)
546 self
.ui
.act_plugins_enable
.triggered
.connect(self
.slot_pluginsEnable
)
547 self
.ui
.act_plugins_disable
.triggered
.connect(self
.slot_pluginsDisable
)
548 self
.ui
.act_plugins_volume100
.triggered
.connect(self
.slot_pluginsVolume100
)
549 self
.ui
.act_plugins_mute
.triggered
.connect(self
.slot_pluginsMute
)
550 self
.ui
.act_plugins_wet100
.triggered
.connect(self
.slot_pluginsWet100
)
551 self
.ui
.act_plugins_bypass
.triggered
.connect(self
.slot_pluginsBypass
)
552 self
.ui
.act_plugins_center
.triggered
.connect(self
.slot_pluginsCenter
)
553 self
.ui
.act_plugins_compact
.triggered
.connect(self
.slot_pluginsCompact
)
554 self
.ui
.act_plugins_expand
.triggered
.connect(self
.slot_pluginsExpand
)
556 self
.ui
.act_settings_show_toolbar
.toggled
.connect(self
.slot_showToolbar
)
557 self
.ui
.act_settings_show_meters
.toggled
.connect(self
.slot_showCanvasMeters
)
558 self
.ui
.act_settings_show_keyboard
.toggled
.connect(self
.slot_showCanvasKeyboard
)
559 self
.ui
.act_settings_show_side_panel
.toggled
.connect(self
.slot_showSidePanel
)
560 self
.ui
.act_settings_configure
.triggered
.connect(self
.slot_configureCarla
)
562 self
.ui
.act_help_about
.triggered
.connect(self
.slot_aboutCarla
)
563 self
.ui
.act_help_about_qt
.triggered
.connect(self
.slot_aboutQt
)
565 self
.ui
.cb_disk
.currentIndexChanged
.connect(self
.slot_diskFolderChanged
)
566 self
.ui
.b_disk_add
.clicked
.connect(self
.slot_diskFolderAdd
)
567 self
.ui
.b_disk_remove
.clicked
.connect(self
.slot_diskFolderRemove
)
568 self
.ui
.fileTreeView
.doubleClicked
.connect(self
.slot_fileTreeDoubleClicked
)
570 self
.ui
.b_transport_play
.clicked
.connect(self
.slot_transportPlayPause
)
571 self
.ui
.b_transport_stop
.clicked
.connect(self
.slot_transportStop
)
572 self
.ui
.b_transport_backwards
.clicked
.connect(self
.slot_transportBackwards
)
573 self
.ui
.b_transport_forwards
.clicked
.connect(self
.slot_transportForwards
)
574 self
.ui
.dsb_transport_bpm
.valueChanged
.connect(self
.slot_transportBpmChanged
)
575 self
.ui
.cb_transport_jack
.clicked
.connect(self
.slot_transportJackEnabled
)
576 self
.ui
.cb_transport_link
.clicked
.connect(self
.slot_transportLinkEnabled
)
578 self
.ui
.b_xruns
.clicked
.connect(self
.slot_xrunClear
)
580 self
.ui
.listWidget
.customContextMenuRequested
.connect(self
.slot_showPluginActionsMenu
)
582 self
.ui
.keyboard
.noteOn
.connect(self
.slot_noteOn
)
583 self
.ui
.keyboard
.noteOff
.connect(self
.slot_noteOff
)
585 self
.ui
.tabWidget
.currentChanged
.connect(self
.slot_tabChanged
)
586 self
.ui
.toolBar
.visibilityChanged
.connect(self
.slot_toolbarVisibilityChanged
)
589 self
.ui
.act_canvas_show_internal
.triggered
.connect(self
.slot_canvasShowInternal
)
590 self
.ui
.act_canvas_show_external
.triggered
.connect(self
.slot_canvasShowExternal
)
591 self
.ui
.act_canvas_arrange
.triggered
.connect(self
.slot_canvasArrange
)
592 self
.ui
.act_canvas_refresh
.triggered
.connect(self
.slot_canvasRefresh
)
593 self
.ui
.act_canvas_zoom_fit
.triggered
.connect(self
.slot_canvasZoomFit
)
594 self
.ui
.act_canvas_zoom_in
.triggered
.connect(self
.slot_canvasZoomIn
)
595 self
.ui
.act_canvas_zoom_out
.triggered
.connect(self
.slot_canvasZoomOut
)
596 self
.ui
.act_canvas_zoom_100
.triggered
.connect(self
.slot_canvasZoomReset
)
597 self
.ui
.act_canvas_save_image
.triggered
.connect(self
.slot_canvasSaveImage
)
598 self
.ui
.act_canvas_save_image_2x
.triggered
.connect(self
.slot_canvasSaveImage
)
599 self
.ui
.act_canvas_save_image_4x
.triggered
.connect(self
.slot_canvasSaveImage
)
600 self
.ui
.act_canvas_copy_clipboard
.triggered
.connect(self
.slot_canvasCopyToClipboard
)
601 self
.ui
.act_canvas_arrange
.setEnabled(False) # TODO, later
602 self
.ui
.graphicsView
.horizontalScrollBar().valueChanged
.connect(self
.slot_horizontalScrollBarChanged
)
603 self
.ui
.graphicsView
.verticalScrollBar().valueChanged
.connect(self
.slot_verticalScrollBarChanged
)
604 self
.ui
.miniCanvasPreview
.miniCanvasMoved
.connect(self
.slot_miniCanvasMoved
)
605 self
.scene
.scaleChanged
.connect(self
.slot_canvasScaleChanged
)
606 self
.scene
.pluginSelected
.connect(self
.slot_canvasPluginSelected
)
607 self
.scene
.selectionChanged
.connect(self
.slot_canvasSelectionChanged
)
609 self
.SIGUSR1
.connect(self
.slot_handleSIGUSR1
)
610 self
.SIGTERM
.connect(self
.slot_handleSIGTERM
)
612 host
.EngineStartedCallback
.connect(self
.slot_handleEngineStartedCallback
)
613 host
.EngineStoppedCallback
.connect(self
.slot_handleEngineStoppedCallback
)
614 host
.TransportModeChangedCallback
.connect(self
.slot_handleTransportModeChangedCallback
)
615 host
.BufferSizeChangedCallback
.connect(self
.slot_handleBufferSizeChangedCallback
)
616 host
.SampleRateChangedCallback
.connect(self
.slot_handleSampleRateChangedCallback
)
617 host
.CancelableActionCallback
.connect(self
.slot_handleCancelableActionCallback
)
618 host
.ProjectLoadFinishedCallback
.connect(self
.slot_handleProjectLoadFinishedCallback
)
620 host
.PluginAddedCallback
.connect(self
.slot_handlePluginAddedCallback
)
621 host
.PluginRemovedCallback
.connect(self
.slot_handlePluginRemovedCallback
)
622 host
.ReloadAllCallback
.connect(self
.slot_handleReloadAllCallback
)
624 host
.NoteOnCallback
.connect(self
.slot_handleNoteOnCallback
)
625 host
.NoteOffCallback
.connect(self
.slot_handleNoteOffCallback
)
627 host
.UpdateCallback
.connect(self
.slot_handleUpdateCallback
)
630 host
.PatchbayClientAddedCallback
.connect(self
.slot_handlePatchbayClientAddedCallback
)
631 host
.PatchbayClientRemovedCallback
.connect(self
.slot_handlePatchbayClientRemovedCallback
)
632 host
.PatchbayClientRenamedCallback
.connect(self
.slot_handlePatchbayClientRenamedCallback
)
633 host
.PatchbayClientDataChangedCallback
.connect(self
.slot_handlePatchbayClientDataChangedCallback
)
634 host
.PatchbayClientPositionChangedCallback
.connect(self
.slot_handlePatchbayClientPositionChangedCallback
)
635 host
.PatchbayPortAddedCallback
.connect(self
.slot_handlePatchbayPortAddedCallback
)
636 host
.PatchbayPortRemovedCallback
.connect(self
.slot_handlePatchbayPortRemovedCallback
)
637 host
.PatchbayPortChangedCallback
.connect(self
.slot_handlePatchbayPortChangedCallback
)
638 host
.PatchbayPortGroupAddedCallback
.connect(self
.slot_handlePatchbayPortGroupAddedCallback
)
639 host
.PatchbayPortGroupRemovedCallback
.connect(self
.slot_handlePatchbayPortGroupRemovedCallback
)
640 host
.PatchbayPortGroupChangedCallback
.connect(self
.slot_handlePatchbayPortGroupChangedCallback
)
641 host
.PatchbayConnectionAddedCallback
.connect(self
.slot_handlePatchbayConnectionAddedCallback
)
642 host
.PatchbayConnectionRemovedCallback
.connect(self
.slot_handlePatchbayConnectionRemovedCallback
)
644 host
.NSMCallback
.connect(self
.slot_handleNSMCallback
)
646 host
.DebugCallback
.connect(self
.slot_handleDebugCallback
)
647 host
.InfoCallback
.connect(self
.slot_handleInfoCallback
)
648 host
.ErrorCallback
.connect(self
.slot_handleErrorCallback
)
649 host
.QuitCallback
.connect(self
.slot_handleQuitCallback
)
650 host
.InlineDisplayRedrawCallback
.connect(self
.slot_handleInlineDisplayRedrawCallback
)
652 # ----------------------------------------------------------------------------------------------------
655 self
.ui
.text_logs
.clear()
656 self
.slot_logButtonsState(False)
657 self
.setProperWindowTitle()
659 # Disable non-supported features
660 features
= gCarla
.utils
.get_supported_features()
662 if "link" not in features
:
663 self
.ui
.cb_transport_link
.setEnabled(False)
664 self
.ui
.cb_transport_link
.setVisible(False)
666 # Plugin needs to have timers always running so it receives messages
667 if self
.host
.isPlugin
or self
.host
.isRemote
:
670 # Qt needs this so it properly creates & resizes the canvas
671 self
.ui
.tabWidget
.blockSignals(True)
672 self
.ui
.tabWidget
.setCurrentIndex(1)
673 self
.ui
.tabWidget
.setCurrentIndex(0)
674 self
.ui
.tabWidget
.blockSignals(False)
676 # Start in patchbay tab if using forced patchbay mode
677 if host
.processModeForced
and host
.processMode
== ENGINE_PROCESS_MODE_PATCHBAY
:
678 self
.ui
.tabWidget
.setCurrentIndex(1)
680 # Load initial project file if set
681 if not (self
.host
.isControl
or self
.host
.isPlugin
):
682 projectFile
= getInitialProjectFile(QApplication
.instance())
685 self
.loadProjectLater(projectFile
)
687 # For NSM we wait for the open message
688 if NSM_URL
and host
.nsmOK
:
689 host
.nsm_ready(NSM_CALLBACK_INIT
)
692 if not host
.isControl
:
693 QTimer
.singleShot(0, self
.slot_engineStart
)
695 # --------------------------------------------------------------------------------------------------------
696 # Manage visibility state, needed for NSM
698 def hideForNSM(self
):
699 for pitem
in reversed(self
.fPluginList
):
702 pitem
.getWidget().hideCustomUI()
705 def showIfNeeded(self
):
707 self
.ui
.act_file_quit
.setText(self
.tr("Hide"))
708 QApplication
.instance().setQuitOnLastWindowClosed(False)
712 # --------------------------------------------------------------------------------------------------------
715 def compactPlugin(self
, pluginId
):
716 if pluginId
> self
.fPluginCount
:
719 pitem
= self
.fPluginList
[pluginId
]
724 pitem
.recreateWidget(True)
726 def changePluginColor(self
, pluginId
, color
, colorStr
):
727 if pluginId
> self
.fPluginCount
:
730 pitem
= self
.fPluginList
[pluginId
]
735 self
.host
.set_custom_data(pluginId
, CUSTOM_DATA_TYPE_PROPERTY
, "CarlaColor", colorStr
)
736 pitem
.recreateWidget(newColor
= color
)
738 def changePluginSkin(self
, pluginId
, skin
):
739 if pluginId
> self
.fPluginCount
:
742 pitem
= self
.fPluginList
[pluginId
]
747 self
.host
.set_custom_data(pluginId
, CUSTOM_DATA_TYPE_PROPERTY
, "CarlaSkin", skin
)
748 if skin
not in ("default","rncbc","presets","mpresets"):
749 pitem
.recreateWidget(newSkin
= skin
, newColor
= (255,255,255))
751 pitem
.recreateWidget(newSkin
= skin
)
753 def findPluginInPatchbay(self
, pluginId
):
754 if pluginId
> self
.fPluginCount
:
757 if self
.fExternalPatchbay
:
758 self
.slot_canvasShowInternal()
760 if not patchcanvas
.focusGroupUsingPluginId(pluginId
):
761 name
= self
.host
.get_plugin_info(pluginId
)['name']
762 if not patchcanvas
.focusGroupUsingGroupName(name
):
765 self
.ui
.tabWidget
.setCurrentIndex(1)
767 def switchPlugins(self
, pluginIdA
, pluginIdB
):
768 if pluginIdA
== pluginIdB
:
770 if pluginIdA
< 0 or pluginIdB
< 0:
772 if pluginIdA
>= self
.fPluginCount
or pluginIdB
>= self
.fPluginCount
:
775 self
.host
.switch_plugins(pluginIdA
, pluginIdB
)
777 itemA
= self
.fPluginList
[pluginIdA
]
778 compactA
= itemA
.isCompacted()
779 guiShownA
= itemA
.isGuiShown()
781 itemB
= self
.fPluginList
[pluginIdB
]
782 compactB
= itemB
.isCompacted()
783 guiShownB
= itemB
.isGuiShown()
785 itemA
.setPluginId(pluginIdA
)
786 itemA
.recreateWidget2(compactB
, guiShownB
)
788 itemB
.setPluginId(pluginIdB
)
789 itemB
.recreateWidget2(compactA
, guiShownA
)
792 self
.slot_canvasRefresh()
794 def setLoadRDFsNeeded(self
):
795 self
.fLadspaRdfNeedsUpdate
= True
797 def setProperWindowTitle(self
):
798 title
= self
.fClientName
800 if self
.fProjectFilename
and not self
.host
.nsmOK
:
801 title
+= " - %s" % os
.path
.basename(self
.fProjectFilename
)
802 if self
.fSessionManagerName
:
803 title
+= " (%s)" % self
.fSessionManagerName
805 self
.setWindowTitle(title
)
807 def updateBufferSize(self
, newBufferSize
):
808 if self
.fBufferSize
== newBufferSize
:
810 self
.fBufferSize
= newBufferSize
811 self
.ui
.cb_buffer_size
.clear()
812 self
.ui
.cb_buffer_size
.addItem(str(newBufferSize
))
813 self
.ui
.cb_buffer_size
.setCurrentIndex(0)
815 def updateSampleRate(self
, newSampleRate
):
816 if self
.fSampleRate
== newSampleRate
:
818 self
.fSampleRate
= newSampleRate
819 self
.ui
.cb_sample_rate
.clear()
820 self
.ui
.cb_sample_rate
.addItem(str(newSampleRate
))
821 self
.ui
.cb_sample_rate
.setCurrentIndex(0)
822 self
.refreshTransport(True)
824 # --------------------------------------------------------------------------------------------------------
827 def loadProjectNow(self
):
828 if not self
.fProjectFilename
:
829 return qCritical("ERROR: loading project without filename set")
830 if self
.host
.nsmOK
and not os
.path
.exists(self
.fProjectFilename
):
833 self
.projectLoadingStarted()
834 self
.fIsProjectLoading
= True
836 if not self
.host
.load_project(self
.fProjectFilename
):
837 self
.fIsProjectLoading
= False
838 self
.projectLoadingFinished(True)
840 CustomMessageBox(self
, QMessageBox
.Critical
, self
.tr("Error"), self
.tr("Failed to load project"),
841 self
.host
.get_last_error(),
842 QMessageBox
.Ok
, QMessageBox
.Ok
)
844 def loadProjectLater(self
, filename
):
845 self
.fProjectFilename
= QFileInfo(filename
).absoluteFilePath()
846 self
.setProperWindowTitle()
847 QTimer
.singleShot(1, self
.slot_loadProjectNow
)
849 def saveProjectNow(self
):
850 if not self
.fProjectFilename
:
851 return qCritical("ERROR: saving project without filename set")
853 if not self
.host
.save_project(self
.fProjectFilename
):
854 CustomMessageBox(self
, QMessageBox
.Critical
, self
.tr("Error"), self
.tr("Failed to save project"),
855 self
.host
.get_last_error(),
856 QMessageBox
.Ok
, QMessageBox
.Ok
)
859 def projectLoadingStarted(self
):
860 self
.ui
.rack
.setEnabled(False)
861 self
.ui
.graphicsView
.setEnabled(False)
863 def projectLoadingFinished(self
, refreshCanvas
):
864 self
.ui
.rack
.setEnabled(True)
865 self
.ui
.graphicsView
.setEnabled(True)
867 if self
.fCustomStopAction
== self
.CUSTOM_ACTION_APP_CLOSE
or not self
.fWithCanvas
:
870 if refreshCanvas
and not self
.loadExternalCanvasGroupPositionsIfNeeded(self
.fProjectFilename
):
871 QTimer
.singleShot(1, self
.slot_canvasRefresh
)
873 def loadExternalCanvasGroupPositionsIfNeeded(self
, filename
):
874 extrafile
= filename
.rsplit(".",1)[0]+".json"
875 if not os
.path
.exists(extrafile
):
878 with
open(filename
, "r") as fh
:
879 if "".join(fh
.readlines(90)).find("<CARLA-PROJECT VERSION='2.0'>") < 0:
882 with
open(extrafile
, "r") as fh
:
884 canvasdata
= json
.load(fh
)['canvas']
888 print("NOTICE: loading old-style canvas group positions via legacy json file")
889 patchcanvas
.restoreGroupPositions(canvasdata
)
890 QTimer
.singleShot(1, self
.slot_canvasRefresh
)
893 # --------------------------------------------------------------------------------------------------------
894 # Files (menu actions)
897 def slot_fileNew(self
):
898 if self
.fPluginCount
> 0 and QMessageBox
.question(self
, self
.tr("New File"),
899 self
.tr("Plugins that are currently loaded will be removed. Are you sure?"),
900 QMessageBox
.Yes|QMessageBox
.No
) == QMessageBox
.No
:
903 self
.pluginRemoveAll()
904 self
.fProjectFilename
= ""
905 self
.setProperWindowTitle()
906 self
.host
.clear_project_filename()
909 def slot_fileOpen(self
):
910 fileFilter
= self
.tr("Carla Project File (*.carxp);;Carla Preset File (*.carxs)")
911 filename
, ok
= QFileDialog
.getOpenFileName(self
, self
.tr("Open Carla Project File"), self
.fSavedSettings
[CARLA_KEY_MAIN_PROJECT_FOLDER
], filter=fileFilter
)
913 # FIXME use ok value, test if it works as expected
919 if self
.fPluginCount
> 0:
920 ask
= QMessageBox
.question(self
, self
.tr("Question"), self
.tr("There are some plugins loaded, do you want to remove them now?"),
921 QMessageBox
.Yes | QMessageBox
.No
, QMessageBox
.No
)
922 newFile
= (ask
== QMessageBox
.Yes
)
925 self
.pluginRemoveAll()
926 self
.fProjectFilename
= filename
927 self
.setProperWindowTitle()
928 self
.loadProjectNow()
930 filenameOld
= self
.fProjectFilename
931 self
.fProjectFilename
= filename
932 self
.loadProjectNow()
933 self
.fProjectFilename
= filenameOld
936 def slot_fileSave(self
, saveAs
=False):
937 if self
.fProjectFilename
and not saveAs
:
938 return self
.saveProjectNow()
940 fileFilter
= self
.tr("Carla Project File (*.carxp)")
941 filename
, ok
= QFileDialog
.getSaveFileName(self
, self
.tr("Save Carla Project File"), self
.fSavedSettings
[CARLA_KEY_MAIN_PROJECT_FOLDER
], filter=fileFilter
)
943 # FIXME use ok value, test if it works as expected
947 if not filename
.lower().endswith(".carxp"):
950 if self
.fProjectFilename
!= filename
:
951 self
.fProjectFilename
= filename
952 self
.setProperWindowTitle()
954 self
.saveProjectNow()
957 def slot_fileSaveAs(self
):
958 self
.slot_fileSave(True)
961 def slot_loadProjectNow(self
):
962 self
.loadProjectNow()
964 # --------------------------------------------------------------------------------------------------------
965 # Engine (menu actions)
968 def slot_engineStart(self
):
969 audioDriver
= setEngineSettings(self
.host
, self
.fSavedSettings
)
971 firstInit
= self
.fFirstEngineInit
972 self
.fFirstEngineInit
= False
974 self
.ui
.text_logs
.appendPlainText("======= Starting engine =======")
976 if self
.host
.engine_init(audioDriver
, self
.fClientName
):
977 if firstInit
and not (self
.host
.isControl
or self
.host
.isPlugin
):
978 settings
= QSafeSettings()
979 lastBpm
= settings
.value("LastBPM", 120.0, float)
982 self
.host
.transport_bpm(lastBpm
)
986 self
.ui
.text_logs
.appendPlainText("Failed to start engine on first try, ignored")
989 audioError
= self
.host
.get_last_error()
992 QMessageBox
.critical(self
, self
.tr("Error"),
993 self
.tr("Could not connect to Audio backend '%s', possible reasons:\n%s" % (audioDriver
, audioError
)))
995 QMessageBox
.critical(self
, self
.tr("Error"),
996 self
.tr("Could not connect to Audio backend '%s'" % audioDriver
))
999 def slot_engineStop(self
, forced
= False):
1000 self
.ui
.text_logs
.appendPlainText("======= Stopping engine =======")
1002 if self
.fPluginCount
== 0 or not self
.host
.is_engine_running():
1003 self
.engineStopFinal()
1007 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"
1008 "Do you want to do this now?"),
1009 QMessageBox
.Yes | QMessageBox
.No
, QMessageBox
.No
)
1010 if ask
!= QMessageBox
.Yes
:
1013 return self
.slot_engineStopTryAgain()
1016 def slot_engineConfig(self
):
1017 engineRunning
= self
.host
.is_engine_running()
1020 dialog
= RuntimeDriverSettingsW(self
.fParentOrSelf
, self
.host
)
1023 if self
.host
.isPlugin
:
1024 driverName
= "Plugin"
1026 elif self
.host
.audioDriverForced
:
1027 driverName
= self
.host
.audioDriverForced
1030 settings
= QSafeSettings()
1031 driverName
= settings
.value(CARLA_KEY_ENGINE_AUDIO_DRIVER
, CARLA_DEFAULT_AUDIO_DRIVER
, str)
1032 for i
in range(self
.host
.get_engine_driver_count()):
1033 if self
.host
.get_engine_driver_name(i
) == driverName
:
1039 dialog
= DriverSettingsW(self
.fParentOrSelf
, self
.host
, driverIndex
, driverName
)
1040 dialog
.ui
.ico_restart
.hide()
1041 dialog
.ui
.label_restart
.hide()
1044 if not dialog
.exec_():
1047 audioDevice
, bufferSize
, sampleRate
= dialog
.getValues()
1050 self
.host
.set_engine_buffer_size_and_sample_rate(bufferSize
, sampleRate
)
1052 self
.host
.set_engine_option(ENGINE_OPTION_AUDIO_DEVICE
, 0, audioDevice
)
1053 self
.host
.set_engine_option(ENGINE_OPTION_AUDIO_BUFFER_SIZE
, bufferSize
, "")
1054 self
.host
.set_engine_option(ENGINE_OPTION_AUDIO_SAMPLE_RATE
, sampleRate
, "")
1057 def slot_engineStopTryAgain(self
):
1058 if self
.host
.is_engine_running() and not self
.host
.set_engine_about_to_close():
1059 QTimer
.singleShot(0, self
.slot_engineStopTryAgain
)
1062 self
.engineStopFinal()
1065 def engineStopFinal(self
):
1066 patchcanvas
.handleAllPluginsRemoved()
1069 if self
.fCustomStopAction
== self
.CUSTOM_ACTION_PROJECT_LOAD
:
1070 self
.removeAllPlugins()
1072 self
.fProjectFilename
= ""
1073 self
.setProperWindowTitle()
1074 if self
.fPluginCount
!= 0:
1075 self
.fCurrentlyRemovingAllPlugins
= True
1076 self
.projectLoadingStarted()
1078 if self
.host
.is_engine_running() and not self
.host
.remove_all_plugins():
1079 self
.ui
.text_logs
.appendPlainText("Failed to remove all plugins, error was:")
1080 self
.ui
.text_logs
.appendPlainText(self
.host
.get_last_error())
1082 if not self
.host
.engine_close():
1083 self
.ui
.text_logs
.appendPlainText("Failed to stop engine, error was:")
1084 self
.ui
.text_logs
.appendPlainText(self
.host
.get_last_error())
1086 if self
.fCustomStopAction
== self
.CUSTOM_ACTION_APP_CLOSE
:
1088 elif self
.fCustomStopAction
== self
.CUSTOM_ACTION_PROJECT_LOAD
:
1089 self
.slot_engineStart()
1090 self
.loadProjectNow()
1091 self
.host
.nsm_ready(NSM_CALLBACK_OPEN
)
1093 self
.fCustomStopAction
= self
.CUSTOM_ACTION_NONE
1095 # --------------------------------------------------------------------------------------------------------
1096 # Engine (host callbacks)
1098 @pyqtSlot(int, int, int, int, float, str)
1099 def slot_handleEngineStartedCallback(self
, pluginCount
, processMode
, transportMode
, bufferSize
, sampleRate
, driverName
):
1100 self
.ui
.menu_PluginMacros
.setEnabled(True)
1101 self
.ui
.menu_Canvas
.setEnabled(True)
1102 self
.ui
.w_transport
.setEnabled(True)
1104 self
.ui
.act_canvas_show_internal
.blockSignals(True)
1105 self
.ui
.act_canvas_show_external
.blockSignals(True)
1107 if processMode
== ENGINE_PROCESS_MODE_PATCHBAY
and not self
.host
.isPlugin
:
1108 self
.ui
.act_canvas_show_internal
.setChecked(True)
1109 self
.ui
.act_canvas_show_internal
.setVisible(True)
1110 self
.ui
.act_canvas_show_external
.setChecked(False)
1111 self
.ui
.act_canvas_show_external
.setVisible(True)
1112 self
.fExternalPatchbay
= False
1114 self
.ui
.act_canvas_show_internal
.setChecked(False)
1115 self
.ui
.act_canvas_show_internal
.setVisible(False)
1116 self
.ui
.act_canvas_show_external
.setChecked(True)
1117 self
.ui
.act_canvas_show_external
.setVisible(False)
1118 self
.fExternalPatchbay
= not self
.host
.isPlugin
1120 self
.ui
.act_canvas_show_internal
.blockSignals(False)
1121 self
.ui
.act_canvas_show_external
.blockSignals(False)
1123 if not (self
.host
.isControl
or self
.host
.isPlugin
):
1124 canSave
= (self
.fProjectFilename
and os
.path
.exists(self
.fProjectFilename
)) or not self
.fSessionManagerName
1125 self
.ui
.act_file_save
.setEnabled(canSave
)
1126 self
.ui
.act_engine_start
.setEnabled(False)
1127 self
.ui
.act_engine_stop
.setEnabled(True)
1129 if not self
.host
.isPlugin
:
1130 self
.enableTransport(transportMode
!= ENGINE_TRANSPORT_MODE_DISABLED
)
1132 if self
.host
.isPlugin
or not self
.fSessionManagerName
:
1133 self
.ui
.act_file_open
.setEnabled(True)
1134 self
.ui
.act_file_save_as
.setEnabled(True)
1136 self
.ui
.cb_transport_jack
.setChecked(transportMode
== ENGINE_TRANSPORT_MODE_JACK
)
1137 self
.ui
.cb_transport_jack
.setEnabled(driverName
== "JACK" and processMode
!= ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS
)
1139 if self
.ui
.cb_transport_link
.isEnabled():
1140 self
.ui
.cb_transport_link
.setChecked(":link:" in self
.host
.transportExtra
)
1142 self
.updateBufferSize(bufferSize
)
1143 self
.updateSampleRate(int(sampleRate
))
1144 self
.refreshRuntimeInfo(0.0, 0)
1147 self
.ui
.text_logs
.appendPlainText("======= Engine started ========")
1148 self
.ui
.text_logs
.appendPlainText("Carla engine started, details:")
1149 self
.ui
.text_logs
.appendPlainText(" Driver name: %s" % driverName
)
1150 self
.ui
.text_logs
.appendPlainText(" Sample rate: %i" % int(sampleRate
))
1151 self
.ui
.text_logs
.appendPlainText(" Process mode: %s" % processMode2Str(processMode
))
1154 def slot_handleEngineStoppedCallback(self
):
1155 self
.ui
.text_logs
.appendPlainText("======= Engine stopped ========")
1157 if self
.fWithCanvas
:
1163 self
.removeAllPlugins()
1164 self
.refreshRuntimeInfo(0.0, 0)
1166 self
.ui
.menu_PluginMacros
.setEnabled(False)
1167 self
.ui
.menu_Canvas
.setEnabled(False)
1168 self
.ui
.w_transport
.setEnabled(False)
1170 if not (self
.host
.isControl
or self
.host
.isPlugin
):
1171 self
.ui
.act_file_save
.setEnabled(False)
1172 self
.ui
.act_engine_start
.setEnabled(True)
1173 self
.ui
.act_engine_stop
.setEnabled(False)
1175 if self
.host
.isPlugin
or not self
.fSessionManagerName
:
1176 self
.ui
.act_file_open
.setEnabled(False)
1177 self
.ui
.act_file_save_as
.setEnabled(False)
1180 def slot_handleTransportModeChangedCallback(self
, transportMode
, transportExtra
):
1181 self
.enableTransport(transportMode
!= ENGINE_TRANSPORT_MODE_DISABLED
)
1183 self
.ui
.cb_transport_jack
.setChecked(transportMode
== ENGINE_TRANSPORT_MODE_JACK
)
1184 self
.ui
.cb_transport_link
.setChecked(":link:" in transportExtra
)
1187 def slot_handleBufferSizeChangedCallback(self
, newBufferSize
):
1188 self
.updateBufferSize(newBufferSize
)
1191 def slot_handleSampleRateChangedCallback(self
, newSampleRate
):
1192 self
.updateSampleRate(int(newSampleRate
))
1194 @pyqtSlot(int, bool, str)
1195 def slot_handleCancelableActionCallback(self
, pluginId
, started
, action
):
1196 if self
.fCancelableActionBox
is not None:
1197 self
.fCancelableActionBox
.close()
1200 self
.fCancelableActionBox
= QMessageBox(self
)
1201 self
.fCancelableActionBox
.setIcon(QMessageBox
.Information
)
1202 self
.fCancelableActionBox
.setWindowTitle(self
.tr("Action in progress"))
1203 self
.fCancelableActionBox
.setText(action
)
1204 self
.fCancelableActionBox
.setInformativeText(self
.tr("An action is in progress, please wait..."))
1205 self
.fCancelableActionBox
.setStandardButtons(QMessageBox
.Cancel
)
1206 self
.fCancelableActionBox
.setDefaultButton(QMessageBox
.Cancel
)
1207 self
.fCancelableActionBox
.buttonClicked
.connect(self
.slot_canlableActionBoxClicked
)
1208 self
.fCancelableActionBox
.show()
1211 self
.fCancelableActionBox
= None
1214 def slot_canlableActionBoxClicked(self
):
1215 self
.host
.cancel_engine_action()
1218 def slot_handleProjectLoadFinishedCallback(self
):
1219 self
.fIsProjectLoading
= False
1220 self
.projectLoadingFinished(False)
1222 # --------------------------------------------------------------------------------------------------------
1225 def removeAllPlugins(self
):
1226 self
.ui
.act_plugin_remove_all
.setEnabled(False)
1227 patchcanvas
.handleAllPluginsRemoved()
1229 while self
.ui
.listWidget
.takeItem(0):
1232 self
.clearSideStuff()
1234 for pitem
in self
.fPluginList
:
1241 self
.fPluginCount
= 0
1242 self
.fPluginList
= []
1244 # --------------------------------------------------------------------------------------------------------
1245 # Plugins (menu actions)
1247 def showAddPluginDialog(self
):
1248 # TODO self.fHasLoadedLv2Plugins
1249 if self
.fPluginListDialog
is None:
1251 'showPluginBridges': self
.fSavedSettings
[CARLA_KEY_EXPERIMENTAL_PLUGIN_BRIDGES
],
1252 'showWineBridges': self
.fSavedSettings
[CARLA_KEY_EXPERIMENTAL_WINE_BRIDGES
],
1253 'useSystemIcons': self
.fSavedSettings
[CARLA_KEY_MAIN_SYSTEM_ICONS
],
1254 'wineAutoPrefix': self
.fSavedSettings
[CARLA_KEY_WINE_AUTO_PREFIX
],
1255 'wineExecutable': self
.fSavedSettings
[CARLA_KEY_WINE_EXECUTABLE
],
1256 'wineFallbackPrefix': self
.fSavedSettings
[CARLA_KEY_WINE_FALLBACK_PREFIX
],
1258 self
.fPluginListDialog
= d
= gCarla
.felib
.createPluginListDialog(self
.fParentOrSelf
, hostSettings
)
1260 gCarla
.felib
.setPluginListDialogPath(d
, PLUGIN_LADSPA
, self
.fSavedSettings
[CARLA_KEY_PATHS_LADSPA
])
1261 gCarla
.felib
.setPluginListDialogPath(d
, PLUGIN_DSSI
, self
.fSavedSettings
[CARLA_KEY_PATHS_DSSI
])
1262 gCarla
.felib
.setPluginListDialogPath(d
, PLUGIN_LV2
, self
.fSavedSettings
[CARLA_KEY_PATHS_LV2
])
1263 gCarla
.felib
.setPluginListDialogPath(d
, PLUGIN_VST2
, self
.fSavedSettings
[CARLA_KEY_PATHS_VST2
])
1264 gCarla
.felib
.setPluginListDialogPath(d
, PLUGIN_VST3
, self
.fSavedSettings
[CARLA_KEY_PATHS_VST3
])
1265 gCarla
.felib
.setPluginListDialogPath(d
, PLUGIN_SF2
, self
.fSavedSettings
[CARLA_KEY_PATHS_SF2
])
1266 gCarla
.felib
.setPluginListDialogPath(d
, PLUGIN_SFZ
, self
.fSavedSettings
[CARLA_KEY_PATHS_SFZ
])
1267 gCarla
.felib
.setPluginListDialogPath(d
, PLUGIN_JSFX
, self
.fSavedSettings
[CARLA_KEY_PATHS_JSFX
])
1268 gCarla
.felib
.setPluginListDialogPath(d
, PLUGIN_CLAP
, self
.fSavedSettings
[CARLA_KEY_PATHS_CLAP
])
1270 ret
= gCarla
.felib
.execPluginListDialog(self
.fPluginListDialog
)
1273 #if dialog.fFavoritePluginsChanged:
1274 #self.fFavoritePlugins = dialog.fFavoritePlugins
1279 if not self
.host
.is_engine_running():
1280 QMessageBox
.warning(self
, self
.tr("Warning"), self
.tr("Cannot add new plugins while engine is stopped"))
1283 btype
= ret
['build']
1285 filename
= ret
['filename']
1286 label
= ret
['label']
1287 uniqueId
= ret
['uniqueId']
1290 return (btype
, ptype
, filename
, label
, uniqueId
, extraPtr
)
1292 def showAddJackAppDialog(self
):
1293 ret
= gCarla
.felib
.createAndExecJackAppDialog(self
.fParentOrSelf
, self
.fProjectFilename
)
1298 if not self
.host
.is_engine_running():
1299 QMessageBox
.warning(self
, self
.tr("Warning"), self
.tr("Cannot add new plugins while engine is stopped"))
1305 def slot_favoritePluginAdd(self
):
1306 plugin
= self
.sender().data()
1311 if not self
.host
.add_plugin(plugin
['build'], plugin
['type'], plugin
['filename'], None,
1312 plugin
['label'], plugin
['uniqueId'], None, PLUGIN_OPTIONS_NULL
):
1313 # remove plugin from favorites
1315 self
.fFavoritePlugins
.remove(plugin
)
1319 settingsDBf
= QSafeSettings("falkTX", "CarlaDatabase2")
1320 settingsDBf
.setValue("PluginDatabase/Favorites", self
.fFavoritePlugins
)
1324 CustomMessageBox(self
,
1325 QMessageBox
.Critical
,
1327 self
.tr("Failed to load plugin"),
1328 self
.host
.get_last_error(), QMessageBox
.Ok
, QMessageBox
.Ok
)
1331 def slot_showPluginActionsMenu(self
):
1334 menu
.addSection("Plugins")
1335 menu
.addAction(self
.ui
.act_plugin_add
)
1337 if len(self
.fFavoritePlugins
) != 0:
1338 fmenu
= QMenu("Add from favorites", self
)
1339 for p
in self
.fFavoritePlugins
:
1340 act
= fmenu
.addAction(p
['name'])
1342 act
.triggered
.connect(self
.slot_favoritePluginAdd
)
1345 menu
.addAction(self
.ui
.act_plugin_remove_all
)
1347 menu
.addSection("All plugins (macros)")
1348 menu
.addAction(self
.ui
.act_plugins_enable
)
1349 menu
.addAction(self
.ui
.act_plugins_disable
)
1351 menu
.addAction(self
.ui
.act_plugins_volume100
)
1352 menu
.addAction(self
.ui
.act_plugins_mute
)
1354 menu
.addAction(self
.ui
.act_plugins_wet100
)
1355 menu
.addAction(self
.ui
.act_plugins_bypass
)
1357 menu
.addAction(self
.ui
.act_plugins_center
)
1359 menu
.addAction(self
.ui
.act_plugins_compact
)
1360 menu
.addAction(self
.ui
.act_plugins_expand
)
1362 menu
.exec_(QCursor
.pos())
1365 def slot_pluginAdd(self
):
1366 data
= self
.showAddPluginDialog()
1371 btype
, ptype
, filename
, label
, uniqueId
, extraPtr
= data
1373 if not self
.host
.add_plugin(btype
, ptype
, filename
, None, label
, uniqueId
, extraPtr
, PLUGIN_OPTIONS_NULL
):
1374 CustomMessageBox(self
, QMessageBox
.Critical
, self
.tr("Error"), self
.tr("Failed to load plugin"),
1375 self
.host
.get_last_error(), QMessageBox
.Ok
, QMessageBox
.Ok
)
1378 def slot_confirmRemoveAll(self
):
1379 if self
.fPluginCount
== 0:
1382 if QMessageBox
.question(self
, self
.tr("Remove All"),
1383 self
.tr("Are you sure you want to remove all plugins?"),
1384 QMessageBox
.Yes|QMessageBox
.No
) == QMessageBox
.No
:
1387 self
.pluginRemoveAll()
1389 def pluginRemoveAll(self
):
1390 if self
.fPluginCount
== 0:
1393 self
.fCurrentlyRemovingAllPlugins
= True
1394 self
.projectLoadingStarted()
1396 if not self
.host
.remove_all_plugins():
1397 self
.projectLoadingFinished(True)
1398 self
.fCurrentlyRemovingAllPlugins
= False
1399 CustomMessageBox(self
, QMessageBox
.Warning, self
.tr("Error"), self
.tr("Operation failed"),
1400 self
.host
.get_last_error(), QMessageBox
.Ok
, QMessageBox
.Ok
)
1403 def slot_jackAppAdd(self
):
1404 data
= self
.showAddJackAppDialog()
1409 if not data
['command']:
1410 CustomMessageBox(self
, QMessageBox
.Critical
, self
.tr("Error"), self
.tr("Cannot add jack application"),
1411 self
.tr("command is empty"), QMessageBox
.Ok
, QMessageBox
.Ok
)
1414 if not self
.host
.add_plugin(BINARY_NATIVE
, PLUGIN_JACK
,
1415 data
['command'], data
['name'], data
['labelSetup'],
1416 0, None, PLUGIN_OPTIONS_NULL
):
1417 CustomMessageBox(self
, QMessageBox
.Critical
, self
.tr("Error"), self
.tr("Failed to load plugin"),
1418 self
.host
.get_last_error(), QMessageBox
.Ok
, QMessageBox
.Ok
)
1420 # --------------------------------------------------------------------------------------------------------
1424 def slot_pluginsEnable(self
):
1425 if not self
.host
.is_engine_running():
1428 for pitem
in self
.fPluginList
:
1432 pitem
.getWidget().setActive(True, True, True)
1435 def slot_pluginsDisable(self
):
1436 if not self
.host
.is_engine_running():
1439 for pitem
in self
.fPluginList
:
1443 pitem
.getWidget().setActive(False, True, True)
1446 def slot_pluginsVolume100(self
):
1447 if not self
.host
.is_engine_running():
1450 for pitem
in self
.fPluginList
:
1454 pitem
.getWidget().setInternalParameter(PLUGIN_CAN_VOLUME
, 1.0)
1457 def slot_pluginsMute(self
):
1458 if not self
.host
.is_engine_running():
1461 for pitem
in self
.fPluginList
:
1465 pitem
.getWidget().setInternalParameter(PLUGIN_CAN_VOLUME
, 0.0)
1468 def slot_pluginsWet100(self
):
1469 if not self
.host
.is_engine_running():
1472 for pitem
in self
.fPluginList
:
1476 pitem
.getWidget().setInternalParameter(PLUGIN_CAN_DRYWET
, 1.0)
1479 def slot_pluginsBypass(self
):
1480 if not self
.host
.is_engine_running():
1483 for pitem
in self
.fPluginList
:
1487 pitem
.getWidget().setInternalParameter(PLUGIN_CAN_DRYWET
, 0.0)
1490 def slot_pluginsCenter(self
):
1491 if not self
.host
.is_engine_running():
1494 for pitem
in self
.fPluginList
:
1498 pitem
.getWidget().setInternalParameter(PARAMETER_BALANCE_LEFT
, -1.0)
1499 pitem
.getWidget().setInternalParameter(PARAMETER_BALANCE_RIGHT
, 1.0)
1500 pitem
.getWidget().setInternalParameter(PARAMETER_PANNING
, 0.0)
1503 def slot_pluginsCompact(self
):
1504 for pitem
in self
.fPluginList
:
1510 def slot_pluginsExpand(self
):
1511 for pitem
in self
.fPluginList
:
1516 # --------------------------------------------------------------------------------------------------------
1517 # Plugins (host callbacks)
1519 @pyqtSlot(int, int, str)
1520 def slot_handlePluginAddedCallback(self
, pluginId
, pluginType
, pluginName
):
1521 if pluginId
!= self
.fPluginCount
:
1522 print("ERROR: pluginAdded mismatch Id:", pluginId
, self
.fPluginCount
)
1523 pitem
= self
.getPluginItem(pluginId
)
1524 pitem
.recreateWidget()
1527 pitem
= self
.ui
.listWidget
.createItem(pluginId
, self
.fSavedSettings
[CARLA_KEY_MAIN_CLASSIC_SKIN
])
1528 self
.fPluginList
.append(pitem
)
1529 self
.fPluginCount
+= 1
1531 self
.ui
.act_plugin_remove_all
.setEnabled(self
.fPluginCount
> 0)
1533 if pluginType
== PLUGIN_LV2
:
1534 self
.fHasLoadedLv2Plugins
= True
1537 def slot_handlePluginRemovedCallback(self
, pluginId
):
1538 if self
.fWithCanvas
:
1539 patchcanvas
.handlePluginRemoved(pluginId
)
1541 if pluginId
in self
.fSelectedPlugins
:
1542 self
.clearSideStuff()
1544 if self
.fPluginCount
== 0:
1547 pitem
= self
.getPluginItem(pluginId
)
1549 self
.fPluginCount
-= 1
1550 self
.fPluginList
.pop(pluginId
)
1551 self
.ui
.listWidget
.takeItem(pluginId
)
1553 if pitem
is not None:
1557 if self
.fPluginCount
== 0:
1558 self
.ui
.act_plugin_remove_all
.setEnabled(False)
1559 if self
.fCurrentlyRemovingAllPlugins
:
1560 self
.fCurrentlyRemovingAllPlugins
= False
1561 self
.projectLoadingFinished(False)
1564 # push all plugins 1 slot back
1565 for i
in range(pluginId
, self
.fPluginCount
):
1566 pitem
= self
.fPluginList
[i
]
1567 pitem
.setPluginId(i
)
1569 self
.ui
.act_plugin_remove_all
.setEnabled(True)
1571 # --------------------------------------------------------------------------------------------------------
1574 def clearSideStuff(self
):
1575 if self
.fWithCanvas
:
1576 self
.scene
.clearSelection()
1578 self
.fSelectedPlugins
= []
1580 self
.ui
.keyboard
.allNotesOff(False)
1581 self
.ui
.scrollArea
.setEnabled(False)
1583 self
.fPeaksCleared
= True
1584 self
.ui
.peak_in
.displayMeter(1, 0.0, True)
1585 self
.ui
.peak_in
.displayMeter(2, 0.0, True)
1586 self
.ui
.peak_out
.displayMeter(1, 0.0, True)
1587 self
.ui
.peak_out
.displayMeter(2, 0.0, True)
1589 def setupCanvas(self
):
1590 pOptions
= patchcanvas
.options_t()
1591 pOptions
.theme_name
= self
.fSavedSettings
[CARLA_KEY_CANVAS_THEME
]
1592 pOptions
.auto_hide_groups
= self
.fSavedSettings
[CARLA_KEY_CANVAS_AUTO_HIDE_GROUPS
]
1593 pOptions
.auto_select_items
= self
.fSavedSettings
[CARLA_KEY_CANVAS_AUTO_SELECT_ITEMS
]
1594 pOptions
.use_bezier_lines
= self
.fSavedSettings
[CARLA_KEY_CANVAS_USE_BEZIER_LINES
]
1595 pOptions
.antialiasing
= self
.fSavedSettings
[CARLA_KEY_CANVAS_ANTIALIASING
]
1596 pOptions
.inline_displays
= self
.fSavedSettings
[CARLA_KEY_CANVAS_INLINE_DISPLAYS
]
1598 if self
.fSavedSettings
[CARLA_KEY_CANVAS_FANCY_EYE_CANDY
]:
1599 pOptions
.eyecandy
= patchcanvas
.EYECANDY_FULL
1600 elif self
.fSavedSettings
[CARLA_KEY_CANVAS_EYE_CANDY
]:
1601 pOptions
.eyecandy
= patchcanvas
.EYECANDY_SMALL
1603 pOptions
.eyecandy
= patchcanvas
.EYECANDY_NONE
1605 pFeatures
= patchcanvas
.features_t()
1606 pFeatures
.group_info
= False
1607 pFeatures
.group_rename
= False
1608 pFeatures
.port_info
= False
1609 pFeatures
.port_rename
= False
1610 pFeatures
.handle_group_pos
= False
1612 patchcanvas
.setOptions(pOptions
)
1613 patchcanvas
.setFeatures(pFeatures
)
1614 patchcanvas
.init("Carla2", self
.scene
, canvasCallback
, False)
1616 tryCanvasSize
= self
.fSavedSettings
[CARLA_KEY_CANVAS_SIZE
].split("x")
1618 if len(tryCanvasSize
) == 2 and tryCanvasSize
[0].isdigit() and tryCanvasSize
[1].isdigit():
1619 self
.fCanvasWidth
= int(tryCanvasSize
[0])
1620 self
.fCanvasHeight
= int(tryCanvasSize
[1])
1622 self
.fCanvasWidth
= CARLA_DEFAULT_CANVAS_SIZE_WIDTH
1623 self
.fCanvasHeight
= CARLA_DEFAULT_CANVAS_SIZE_HEIGHT
1625 patchcanvas
.setCanvasSize(0, 0, self
.fCanvasWidth
, self
.fCanvasHeight
)
1626 patchcanvas
.setInitialPos(self
.fCanvasWidth
/ 2, self
.fCanvasHeight
/ 2)
1627 self
.ui
.graphicsView
.setSceneRect(0, 0, self
.fCanvasWidth
, self
.fCanvasHeight
)
1629 self
.ui
.miniCanvasPreview
.setViewTheme(patchcanvas
.canvas
.theme
.canvas_bg
, patchcanvas
.canvas
.theme
.rubberband_brush
, patchcanvas
.canvas
.theme
.rubberband_pen
.color())
1630 self
.ui
.miniCanvasPreview
.init(self
.scene
, self
.fCanvasWidth
, self
.fCanvasHeight
, self
.fSavedSettings
[CARLA_KEY_CUSTOM_PAINTING
])
1632 if self
.fSavedSettings
[CARLA_KEY_CANVAS_ANTIALIASING
] != patchcanvas
.ANTIALIASING_NONE
:
1633 self
.ui
.graphicsView
.setRenderHint(QPainter
.Antialiasing
, True)
1635 fullAA
= self
.fSavedSettings
[CARLA_KEY_CANVAS_ANTIALIASING
] == patchcanvas
.ANTIALIASING_FULL
1636 self
.ui
.graphicsView
.setRenderHint(QPainter
.SmoothPixmapTransform
, fullAA
)
1637 self
.ui
.graphicsView
.setRenderHint(QPainter
.TextAntialiasing
, fullAA
)
1639 if self
.fSavedSettings
[CARLA_KEY_CANVAS_USE_OPENGL
] and hasGL
and QPainter
.HighQualityAntialiasing
is not None:
1640 self
.ui
.graphicsView
.setRenderHint(QPainter
.HighQualityAntialiasing
, self
.fSavedSettings
[CARLA_KEY_CANVAS_HQ_ANTIALIASING
])
1643 self
.ui
.graphicsView
.setRenderHint(QPainter
.Antialiasing
, False)
1645 if self
.fSavedSettings
[CARLA_KEY_CANVAS_FULL_REPAINTS
]:
1646 self
.ui
.graphicsView
.setViewportUpdateMode(QGraphicsView
.FullViewportUpdate
)
1648 self
.ui
.graphicsView
.setViewportUpdateMode(QGraphicsView
.MinimalViewportUpdate
)
1650 def updateCanvasInitialPos(self
):
1651 x
= self
.ui
.graphicsView
.horizontalScrollBar().value() + self
.width()/4
1652 y
= self
.ui
.graphicsView
.verticalScrollBar().value() + self
.height()/4
1653 patchcanvas
.setInitialPos(x
, y
)
1655 def updateMiniCanvasLater(self
):
1656 QTimer
.singleShot(self
.fMiniCanvasUpdateTimeout
, self
.ui
.miniCanvasPreview
.update
)
1658 # --------------------------------------------------------------------------------------------------------
1659 # Canvas (menu actions)
1662 def slot_canvasShowInternal(self
):
1663 self
.fExternalPatchbay
= False
1664 self
.ui
.act_canvas_show_internal
.blockSignals(True)
1665 self
.ui
.act_canvas_show_external
.blockSignals(True)
1666 self
.ui
.act_canvas_show_internal
.setChecked(True)
1667 self
.ui
.act_canvas_show_external
.setChecked(False)
1668 self
.ui
.act_canvas_show_internal
.blockSignals(False)
1669 self
.ui
.act_canvas_show_external
.blockSignals(False)
1670 self
.slot_canvasRefresh()
1673 def slot_canvasShowExternal(self
):
1674 self
.fExternalPatchbay
= True
1675 self
.ui
.act_canvas_show_internal
.blockSignals(True)
1676 self
.ui
.act_canvas_show_external
.blockSignals(True)
1677 self
.ui
.act_canvas_show_internal
.setChecked(False)
1678 self
.ui
.act_canvas_show_external
.setChecked(True)
1679 self
.ui
.act_canvas_show_internal
.blockSignals(False)
1680 self
.ui
.act_canvas_show_external
.blockSignals(False)
1681 self
.slot_canvasRefresh()
1684 def slot_canvasArrange(self
):
1685 patchcanvas
.arrange()
1688 def slot_canvasRefresh(self
):
1691 if self
.host
.processMode
== ENGINE_PROCESS_MODE_CONTINUOUS_RACK
and self
.host
.isPlugin
:
1694 if self
.host
.is_engine_running():
1695 self
.host
.patchbay_refresh(self
.fExternalPatchbay
)
1697 self
.updateMiniCanvasLater()
1700 def slot_canvasZoomFit(self
):
1701 self
.scene
.zoom_fit()
1704 def slot_canvasZoomIn(self
):
1705 self
.scene
.zoom_in()
1708 def slot_canvasZoomOut(self
):
1709 self
.scene
.zoom_out()
1712 def slot_canvasZoomReset(self
):
1713 self
.scene
.zoom_reset()
1715 def _canvasImageRender(self
, zoom
= 1.0):
1716 image
= QImage(self
.scene
.width()*zoom
, self
.scene
.height()*zoom
, QImage
.Format_RGB32
)
1717 painter
= QPainter(image
)
1719 painter
.setRenderHints(painter
.renderHints() | QPainter
.Antialiasing | QPainter
.TextAntialiasing
)
1720 self
.scene
.clearSelection()
1721 self
.scene
.render(painter
)
1726 def _canvasImageWrite(self
, iw
: QImageWriter
, imgFormat
: bytes
, image
: QImage
):
1727 iw
.setFormat(imgFormat
)
1728 iw
.setCompression(-1)
1729 if QT_VERSION
>= 0x50500:
1730 iw
.setOptimizedWrite(True)
1734 def slot_canvasSaveImage(self
):
1735 if self
.fProjectFilename
:
1736 dir = QFileInfo(self
.fProjectFilename
).absoluteDir().absolutePath()
1738 dir = self
.fSavedSettings
[CARLA_KEY_MAIN_PROJECT_FOLDER
]
1740 fileDialog
= QFileDialog(self
)
1741 fileDialog
.setAcceptMode(QFileDialog
.AcceptSave
)
1742 fileDialog
.setDirectory(dir)
1743 fileDialog
.setFileMode(QFileDialog
.AnyFile
)
1744 fileDialog
.setMimeTypeFilters(("image/png", "image/jpeg"))
1745 fileDialog
.setNameFilter(self
.tr("Images (*.png *.jpg)"))
1746 fileDialog
.setOptions(QFileDialog
.DontUseCustomDirectoryIcons
)
1747 fileDialog
.setWindowTitle(self
.tr("Save Image"))
1749 ok
= fileDialog
.exec_()
1754 newPath
= fileDialog
.selectedFiles()
1756 if len(newPath
) != 1:
1759 newPath
= newPath
[0]
1761 if QT_VERSION
>= 0x50900:
1762 if fileDialog
.selectedMimeTypeFilter() == "image/jpeg":
1767 if newPath
.lower().endswith((".jpg", ".jpeg")):
1772 sender
= self
.sender()
1773 if sender
== self
.ui
.act_canvas_save_image_2x
:
1775 elif sender
== self
.ui
.act_canvas_save_image_4x
:
1780 image
= self
._canvasImageRender
(zoom
)
1781 iw
= QImageWriter(newPath
)
1782 self
._canvasImageWrite
(iw
, imgFormat
, image
)
1785 def slot_canvasCopyToClipboard(self
):
1787 buffer.open(QIODevice
.WriteOnly
)
1789 image
= self
._canvasImageRender
()
1790 iw
= QImageWriter(buffer, b
"PNG")
1791 self
._canvasImageWrite
(iw
, b
"PNG", image
)
1795 mimeData
= QMimeData()
1796 mimeData
.setData("image/png", buffer.buffer());
1798 QApplication
.clipboard().setMimeData(mimeData
)
1800 # --------------------------------------------------------------------------------------------------------
1801 # Canvas (canvas callbacks)
1804 def slot_canvasSelectionChanged(self
):
1805 self
.updateMiniCanvasLater()
1808 def slot_canvasScaleChanged(self
, scale
):
1809 self
.ui
.miniCanvasPreview
.setViewScale(scale
)
1812 def slot_canvasPluginSelected(self
, pluginList
):
1813 self
.ui
.keyboard
.allNotesOff(False)
1814 self
.ui
.scrollArea
.setEnabled(len(pluginList
) != 0) # and self.fPluginCount > 0
1815 self
.fSelectedPlugins
= pluginList
1817 # --------------------------------------------------------------------------------------------------------
1818 # Canvas (host callbacks)
1820 @pyqtSlot(int, int, int, str)
1821 def slot_handlePatchbayClientAddedCallback(self
, clientId
, clientIcon
, pluginId
, clientName
):
1822 pcSplit
= patchcanvas
.SPLIT_UNDEF
1823 pcIcon
= patchcanvas
.ICON_APPLICATION
1825 if clientIcon
== PATCHBAY_ICON_PLUGIN
:
1826 pcIcon
= patchcanvas
.ICON_PLUGIN
1827 if clientIcon
== PATCHBAY_ICON_HARDWARE
:
1828 pcIcon
= patchcanvas
.ICON_HARDWARE
1829 elif clientIcon
== PATCHBAY_ICON_CARLA
:
1831 elif clientIcon
== PATCHBAY_ICON_DISTRHO
:
1832 pcIcon
= patchcanvas
.ICON_DISTRHO
1833 elif clientIcon
== PATCHBAY_ICON_FILE
:
1834 pcIcon
= patchcanvas
.ICON_FILE
1836 patchcanvas
.addGroup(clientId
, clientName
, pcSplit
, pcIcon
)
1838 self
.updateMiniCanvasLater()
1842 if pluginId
>= self
.fPluginCount
and pluginId
!= MAIN_CARLA_PLUGIN_ID
:
1843 print("Error mapping plugin to canvas client:", clientName
)
1846 if pluginId
== MAIN_CARLA_PLUGIN_ID
:
1848 hasInlineDisplay
= False
1850 hints
= self
.host
.get_plugin_info(pluginId
)['hints']
1851 hasCustomUI
= bool(hints
& PLUGIN_HAS_CUSTOM_UI
)
1852 hasInlineDisplay
= bool(hints
& PLUGIN_HAS_INLINE_DISPLAY
)
1854 patchcanvas
.setGroupAsPlugin(clientId
, pluginId
, hasCustomUI
, hasInlineDisplay
)
1857 def slot_handlePatchbayClientRemovedCallback(self
, clientId
):
1858 patchcanvas
.removeGroup(clientId
)
1859 self
.updateMiniCanvasLater()
1862 def slot_handlePatchbayClientRenamedCallback(self
, clientId
, newClientName
):
1863 patchcanvas
.renameGroup(clientId
, newClientName
)
1864 self
.updateMiniCanvasLater()
1866 @pyqtSlot(int, int, int)
1867 def slot_handlePatchbayClientDataChangedCallback(self
, clientId
, clientIcon
, pluginId
):
1868 pcIcon
= patchcanvas
.ICON_APPLICATION
1870 if clientIcon
== PATCHBAY_ICON_PLUGIN
:
1871 pcIcon
= patchcanvas
.ICON_PLUGIN
1872 if clientIcon
== PATCHBAY_ICON_HARDWARE
:
1873 pcIcon
= patchcanvas
.ICON_HARDWARE
1874 elif clientIcon
== PATCHBAY_ICON_CARLA
:
1876 elif clientIcon
== PATCHBAY_ICON_DISTRHO
:
1877 pcIcon
= patchcanvas
.ICON_DISTRHO
1878 elif clientIcon
== PATCHBAY_ICON_FILE
:
1879 pcIcon
= patchcanvas
.ICON_FILE
1881 patchcanvas
.setGroupIcon(clientId
, pcIcon
)
1882 self
.updateMiniCanvasLater()
1886 if pluginId
>= self
.fPluginCount
and pluginId
!= MAIN_CARLA_PLUGIN_ID
:
1887 print("sorry, can't map this plugin to canvas client", pluginId
, self
.fPluginCount
)
1890 if pluginId
== MAIN_CARLA_PLUGIN_ID
:
1892 hasInlineDisplay
= False
1894 hints
= self
.host
.get_plugin_info(pluginId
)['hints']
1895 hasCustomUI
= bool(hints
& PLUGIN_HAS_CUSTOM_UI
)
1896 hasInlineDisplay
= bool(hints
& PLUGIN_HAS_INLINE_DISPLAY
)
1898 patchcanvas
.setGroupAsPlugin(clientId
, pluginId
, hasCustomUI
, hasInlineDisplay
)
1900 @pyqtSlot(int, int, int, int, int)
1901 def slot_handlePatchbayClientPositionChangedCallback(self
, clientId
, x1
, y1
, x2
, y2
):
1902 if (x1
!= 0 and x2
!= 0) or (y1
!= 0 and y2
!= 0):
1903 patchcanvas
.splitGroup(clientId
)
1905 patchcanvas
.joinGroup(clientId
)
1906 patchcanvas
.setGroupPosFull(clientId
, x1
, y1
, x2
, y2
)
1907 self
.updateMiniCanvasLater()
1909 @pyqtSlot(int, int, int, int, str)
1910 def slot_handlePatchbayPortAddedCallback(self
, clientId
, portId
, portFlags
, portGroupId
, portName
):
1911 if portFlags
& PATCHBAY_PORT_IS_INPUT
:
1912 portMode
= patchcanvas
.PORT_MODE_INPUT
1914 portMode
= patchcanvas
.PORT_MODE_OUTPUT
1916 if portFlags
& PATCHBAY_PORT_TYPE_AUDIO
:
1917 portType
= patchcanvas
.PORT_TYPE_AUDIO_JACK
1919 elif portFlags
& PATCHBAY_PORT_TYPE_CV
:
1920 portType
= patchcanvas
.PORT_TYPE_PARAMETER
1922 elif portFlags
& PATCHBAY_PORT_TYPE_MIDI
:
1923 portType
= patchcanvas
.PORT_TYPE_MIDI_JACK
1926 portType
= patchcanvas
.PORT_TYPE_NULL
1929 patchcanvas
.addPort(clientId
, portId
, portName
, portMode
, portType
, isAlternate
)
1930 self
.updateMiniCanvasLater()
1933 def slot_handlePatchbayPortRemovedCallback(self
, groupId
, portId
):
1934 patchcanvas
.removePort(groupId
, portId
)
1935 self
.updateMiniCanvasLater()
1937 @pyqtSlot(int, int, int, int, str)
1938 def slot_handlePatchbayPortChangedCallback(self
, groupId
, portId
, portFlags
, portGroupId
, newPortName
):
1939 patchcanvas
.renamePort(groupId
, portId
, newPortName
)
1940 self
.updateMiniCanvasLater()
1942 @pyqtSlot(int, int, int, str)
1943 def slot_handlePatchbayPortGroupAddedCallback(self
, groupId
, portId
, portGroupId
, newPortName
):
1948 def slot_handlePatchbayPortGroupRemovedCallback(self
, groupId
, portId
):
1952 @pyqtSlot(int, int, int, str)
1953 def slot_handlePatchbayPortGroupChangedCallback(self
, groupId
, portId
, portGroupId
, newPortName
):
1957 @pyqtSlot(int, int, int, int, int)
1958 def slot_handlePatchbayConnectionAddedCallback(self
, connectionId
, groupOutId
, portOutId
, groupInId
, portInId
):
1959 patchcanvas
.connectPorts(connectionId
, groupOutId
, portOutId
, groupInId
, portInId
)
1960 self
.updateMiniCanvasLater()
1962 @pyqtSlot(int, int, int)
1963 def slot_handlePatchbayConnectionRemovedCallback(self
, connectionId
, portOutId
, portInId
):
1964 patchcanvas
.disconnectPorts(connectionId
)
1965 self
.updateMiniCanvasLater()
1967 # --------------------------------------------------------------------------------------------------------
1970 def saveSettings(self
):
1971 settings
= QSafeSettings()
1973 settings
.setValue("Geometry", self
.saveGeometry())
1974 settings
.setValue("ShowToolbar", self
.ui
.toolBar
.isEnabled())
1975 settings
.setValue("ShowSidePanel", self
.ui
.dockWidget
.isEnabled())
1979 for i
in range(self
.ui
.cb_disk
.count()):
1980 diskFolders
.append(self
.ui
.cb_disk
.itemData(i
))
1982 settings
.setValue("DiskFolders", diskFolders
)
1983 settings
.setValue("LastBPM", self
.fLastTransportBPM
)
1985 settings
.setValue("ShowMeters", self
.ui
.act_settings_show_meters
.isChecked())
1986 settings
.setValue("ShowKeyboard", self
.ui
.act_settings_show_keyboard
.isChecked())
1987 settings
.setValue("HorizontalScrollBarValue", self
.ui
.graphicsView
.horizontalScrollBar().value())
1988 settings
.setValue("VerticalScrollBarValue", self
.ui
.graphicsView
.verticalScrollBar().value())
1990 settings
.setValue(CARLA_KEY_ENGINE_TRANSPORT_MODE
, self
.host
.transportMode
)
1991 settings
.setValue(CARLA_KEY_ENGINE_TRANSPORT_EXTRA
, self
.host
.transportExtra
)
1995 def loadSettings(self
, firstTime
):
1996 settings
= QSafeSettings()
1998 if self
.fPluginListDialog
is not None:
1999 gCarla
.felib
.destroyPluginListDialog(self
.fPluginListDialog
)
2000 self
.fPluginListDialog
= None
2003 geometry
= settings
.value("Geometry", QByteArray(), QByteArray
)
2004 if not geometry
.isNull():
2005 self
.restoreGeometry(geometry
)
2007 showToolbar
= settings
.value("ShowToolbar", True, bool)
2008 self
.ui
.act_settings_show_toolbar
.setChecked(showToolbar
)
2009 self
.ui
.toolBar
.blockSignals(True)
2010 self
.ui
.toolBar
.setEnabled(showToolbar
)
2011 self
.ui
.toolBar
.setVisible(showToolbar
)
2012 self
.ui
.toolBar
.blockSignals(False)
2014 #if settings.contains("SplitterState"):
2015 #self.ui.splitter.restoreState(settings.value("SplitterState", b""))
2017 #self.ui.splitter.setSizes([210, 99999])
2019 showSidePanel
= settings
.value("ShowSidePanel", True, bool)
2020 self
.ui
.act_settings_show_side_panel
.setChecked(showSidePanel
)
2021 self
.slot_showSidePanel(showSidePanel
)
2023 diskFolders
= settings
.value("DiskFolders", [HOME
], list)
2025 self
.ui
.cb_disk
.setItemData(0, HOME
)
2027 for i
in range(len(diskFolders
)):
2029 folder
= diskFolders
[i
]
2030 self
.ui
.cb_disk
.addItem(os
.path
.basename(folder
), folder
)
2032 #if MACOS and not settings.value(CARLA_KEY_MAIN_USE_PRO_THEME, True, bool):
2033 # self.setUnifiedTitleAndToolBarOnMac(True)
2035 showMeters
= settings
.value("ShowMeters", True, bool)
2036 self
.ui
.act_settings_show_meters
.setChecked(showMeters
)
2037 self
.ui
.peak_in
.setVisible(showMeters
)
2038 self
.ui
.peak_out
.setVisible(showMeters
)
2040 showKeyboard
= settings
.value("ShowKeyboard", True, bool)
2041 self
.ui
.act_settings_show_keyboard
.setChecked(showKeyboard
)
2042 self
.ui
.scrollArea
.setVisible(showKeyboard
)
2044 settingsDBf
= QSafeSettings("falkTX", "CarlaDatabase2")
2045 self
.fFavoritePlugins
= settingsDBf
.value("PluginDatabase/Favorites", [], list)
2047 QTimer
.singleShot(100, self
.slot_restoreCanvasScrollbarValues
)
2049 # TODO - complete this
2050 oldSettings
= self
.fSavedSettings
2052 if self
.host
.audioDriverForced
is not None:
2053 audioDriver
= self
.host
.audioDriverForced
2055 audioDriver
= settings
.value(CARLA_KEY_ENGINE_AUDIO_DRIVER
, CARLA_DEFAULT_AUDIO_DRIVER
, str)
2057 audioDriverPrefix
= CARLA_KEY_ENGINE_DRIVER_PREFIX
+ audioDriver
2059 self
.fSavedSettings
= {
2060 CARLA_KEY_MAIN_PROJECT_FOLDER
: settings
.value(CARLA_KEY_MAIN_PROJECT_FOLDER
, CARLA_DEFAULT_MAIN_PROJECT_FOLDER
, str),
2061 CARLA_KEY_MAIN_CONFIRM_EXIT
: settings
.value(CARLA_KEY_MAIN_CONFIRM_EXIT
, CARLA_DEFAULT_MAIN_CONFIRM_EXIT
, bool),
2062 CARLA_KEY_MAIN_CLASSIC_SKIN
: settings
.value(CARLA_KEY_MAIN_CLASSIC_SKIN
, CARLA_DEFAULT_MAIN_CLASSIC_SKIN
, bool),
2063 CARLA_KEY_MAIN_REFRESH_INTERVAL
: settings
.value(CARLA_KEY_MAIN_REFRESH_INTERVAL
, CARLA_DEFAULT_MAIN_REFRESH_INTERVAL
, int),
2064 CARLA_KEY_MAIN_SYSTEM_ICONS
: settings
.value(CARLA_KEY_MAIN_SYSTEM_ICONS
, CARLA_DEFAULT_MAIN_SYSTEM_ICONS
, bool),
2065 CARLA_KEY_MAIN_EXPERIMENTAL
: settings
.value(CARLA_KEY_MAIN_EXPERIMENTAL
, CARLA_DEFAULT_MAIN_EXPERIMENTAL
, bool),
2066 CARLA_KEY_CANVAS_THEME
: settings
.value(CARLA_KEY_CANVAS_THEME
, CARLA_DEFAULT_CANVAS_THEME
, str),
2067 CARLA_KEY_CANVAS_SIZE
: settings
.value(CARLA_KEY_CANVAS_SIZE
, CARLA_DEFAULT_CANVAS_SIZE
, str),
2068 CARLA_KEY_CANVAS_AUTO_HIDE_GROUPS
: settings
.value(CARLA_KEY_CANVAS_AUTO_HIDE_GROUPS
, CARLA_DEFAULT_CANVAS_AUTO_HIDE_GROUPS
, bool),
2069 CARLA_KEY_CANVAS_AUTO_SELECT_ITEMS
: settings
.value(CARLA_KEY_CANVAS_AUTO_SELECT_ITEMS
, CARLA_DEFAULT_CANVAS_AUTO_SELECT_ITEMS
, bool),
2070 CARLA_KEY_CANVAS_USE_BEZIER_LINES
: settings
.value(CARLA_KEY_CANVAS_USE_BEZIER_LINES
, CARLA_DEFAULT_CANVAS_USE_BEZIER_LINES
, bool),
2071 CARLA_KEY_CANVAS_EYE_CANDY
: settings
.value(CARLA_KEY_CANVAS_EYE_CANDY
, CARLA_DEFAULT_CANVAS_EYE_CANDY
, bool),
2072 CARLA_KEY_CANVAS_FANCY_EYE_CANDY
: settings
.value(CARLA_KEY_CANVAS_FANCY_EYE_CANDY
, CARLA_DEFAULT_CANVAS_FANCY_EYE_CANDY
, bool),
2073 CARLA_KEY_CANVAS_USE_OPENGL
: settings
.value(CARLA_KEY_CANVAS_USE_OPENGL
, CARLA_DEFAULT_CANVAS_USE_OPENGL
, bool),
2074 CARLA_KEY_CANVAS_ANTIALIASING
: settings
.value(CARLA_KEY_CANVAS_ANTIALIASING
, CARLA_DEFAULT_CANVAS_ANTIALIASING
, int),
2075 CARLA_KEY_CANVAS_HQ_ANTIALIASING
: settings
.value(CARLA_KEY_CANVAS_HQ_ANTIALIASING
, CARLA_DEFAULT_CANVAS_HQ_ANTIALIASING
, bool),
2076 CARLA_KEY_CANVAS_FULL_REPAINTS
: settings
.value(CARLA_KEY_CANVAS_FULL_REPAINTS
, CARLA_DEFAULT_CANVAS_FULL_REPAINTS
, bool),
2077 CARLA_KEY_CUSTOM_PAINTING
: (settings
.value(CARLA_KEY_MAIN_USE_PRO_THEME
, True, bool) and
2078 settings
.value(CARLA_KEY_MAIN_PRO_THEME_COLOR
, "Black", str).lower() == "black"),
2081 CARLA_KEY_ENGINE_AUDIO_DRIVER
: audioDriver
,
2082 CARLA_KEY_ENGINE_AUDIO_DEVICE
: settings
.value(audioDriverPrefix
+"/Device", "", str),
2083 CARLA_KEY_ENGINE_BUFFER_SIZE
: settings
.value(audioDriverPrefix
+"/BufferSize", CARLA_DEFAULT_AUDIO_BUFFER_SIZE
, int),
2084 CARLA_KEY_ENGINE_SAMPLE_RATE
: settings
.value(audioDriverPrefix
+"/SampleRate", CARLA_DEFAULT_AUDIO_SAMPLE_RATE
, int),
2085 CARLA_KEY_ENGINE_TRIPLE_BUFFER
: settings
.value(audioDriverPrefix
+"/TripleBuffer", CARLA_DEFAULT_AUDIO_TRIPLE_BUFFER
, bool),
2088 CARLA_KEY_PATHS_AUDIO
: splitter
.join(settings
.value(CARLA_KEY_PATHS_AUDIO
, CARLA_DEFAULT_FILE_PATH_AUDIO
, list)),
2089 CARLA_KEY_PATHS_MIDI
: splitter
.join(settings
.value(CARLA_KEY_PATHS_MIDI
, CARLA_DEFAULT_FILE_PATH_MIDI
, list)),
2092 CARLA_KEY_PATHS_LADSPA
: splitter
.join(settings
.value(CARLA_KEY_PATHS_LADSPA
, CARLA_DEFAULT_LADSPA_PATH
, list)),
2093 CARLA_KEY_PATHS_DSSI
: splitter
.join(settings
.value(CARLA_KEY_PATHS_DSSI
, CARLA_DEFAULT_DSSI_PATH
, list)),
2094 CARLA_KEY_PATHS_LV2
: splitter
.join(settings
.value(CARLA_KEY_PATHS_LV2
, CARLA_DEFAULT_LV2_PATH
, list)),
2095 CARLA_KEY_PATHS_VST2
: splitter
.join(settings
.value(CARLA_KEY_PATHS_VST2
, CARLA_DEFAULT_VST2_PATH
, list)),
2096 CARLA_KEY_PATHS_VST3
: splitter
.join(settings
.value(CARLA_KEY_PATHS_VST3
, CARLA_DEFAULT_VST3_PATH
, list)),
2097 CARLA_KEY_PATHS_SF2
: splitter
.join(settings
.value(CARLA_KEY_PATHS_SF2
, CARLA_DEFAULT_SF2_PATH
, list)),
2098 CARLA_KEY_PATHS_SFZ
: splitter
.join(settings
.value(CARLA_KEY_PATHS_SFZ
, CARLA_DEFAULT_SFZ_PATH
, list)),
2099 CARLA_KEY_PATHS_JSFX
: splitter
.join(settings
.value(CARLA_KEY_PATHS_JSFX
, CARLA_DEFAULT_JSFX_PATH
, list)),
2100 CARLA_KEY_PATHS_CLAP
: splitter
.join(settings
.value(CARLA_KEY_PATHS_CLAP
, CARLA_DEFAULT_CLAP_PATH
, list)),
2103 CARLA_KEY_OSC_ENABLED
: settings
.value(CARLA_KEY_OSC_ENABLED
, CARLA_DEFAULT_OSC_ENABLED
, bool),
2104 CARLA_KEY_OSC_TCP_PORT_ENABLED
: settings
.value(CARLA_KEY_OSC_TCP_PORT_ENABLED
, CARLA_DEFAULT_OSC_TCP_PORT_ENABLED
, bool),
2105 CARLA_KEY_OSC_TCP_PORT_RANDOM
: settings
.value(CARLA_KEY_OSC_TCP_PORT_RANDOM
, CARLA_DEFAULT_OSC_TCP_PORT_RANDOM
, bool),
2106 CARLA_KEY_OSC_TCP_PORT_NUMBER
: settings
.value(CARLA_KEY_OSC_TCP_PORT_NUMBER
, CARLA_DEFAULT_OSC_TCP_PORT_NUMBER
, int),
2107 CARLA_KEY_OSC_UDP_PORT_ENABLED
: settings
.value(CARLA_KEY_OSC_UDP_PORT_ENABLED
, CARLA_DEFAULT_OSC_UDP_PORT_ENABLED
, bool),
2108 CARLA_KEY_OSC_UDP_PORT_RANDOM
: settings
.value(CARLA_KEY_OSC_UDP_PORT_RANDOM
, CARLA_DEFAULT_OSC_UDP_PORT_RANDOM
, bool),
2109 CARLA_KEY_OSC_UDP_PORT_NUMBER
: settings
.value(CARLA_KEY_OSC_UDP_PORT_NUMBER
, CARLA_DEFAULT_OSC_UDP_PORT_NUMBER
, int),
2112 CARLA_KEY_WINE_EXECUTABLE
: settings
.value(CARLA_KEY_WINE_EXECUTABLE
, CARLA_DEFAULT_WINE_EXECUTABLE
, str),
2113 CARLA_KEY_WINE_AUTO_PREFIX
: settings
.value(CARLA_KEY_WINE_AUTO_PREFIX
, CARLA_DEFAULT_WINE_AUTO_PREFIX
, bool),
2114 CARLA_KEY_WINE_FALLBACK_PREFIX
: settings
.value(CARLA_KEY_WINE_FALLBACK_PREFIX
, CARLA_DEFAULT_WINE_FALLBACK_PREFIX
, str),
2115 CARLA_KEY_WINE_RT_PRIO_ENABLED
: settings
.value(CARLA_KEY_WINE_RT_PRIO_ENABLED
, CARLA_DEFAULT_WINE_RT_PRIO_ENABLED
, bool),
2116 CARLA_KEY_WINE_BASE_RT_PRIO
: settings
.value(CARLA_KEY_WINE_BASE_RT_PRIO
, CARLA_DEFAULT_WINE_BASE_RT_PRIO
, int),
2117 CARLA_KEY_WINE_SERVER_RT_PRIO
: settings
.value(CARLA_KEY_WINE_SERVER_RT_PRIO
, CARLA_DEFAULT_WINE_SERVER_RT_PRIO
, int),
2119 # experimental switches
2120 CARLA_KEY_EXPERIMENTAL_PLUGIN_BRIDGES
:
2121 settings
.value(CARLA_KEY_EXPERIMENTAL_PLUGIN_BRIDGES
, CARLA_DEFAULT_EXPERIMENTAL_PLUGIN_BRIDGES
, bool),
2122 CARLA_KEY_EXPERIMENTAL_WINE_BRIDGES
:
2123 settings
.value(CARLA_KEY_EXPERIMENTAL_WINE_BRIDGES
, CARLA_DEFAULT_EXPERIMENTAL_WINE_BRIDGES
, bool),
2126 if not self
.host
.isControl
:
2127 self
.fSavedSettings
[CARLA_KEY_CANVAS_INLINE_DISPLAYS
] = settings
.value(CARLA_KEY_CANVAS_INLINE_DISPLAYS
, CARLA_DEFAULT_CANVAS_INLINE_DISPLAYS
, bool)
2129 self
.fSavedSettings
[CARLA_KEY_CANVAS_INLINE_DISPLAYS
] = False
2131 settings2
= QSafeSettings("falkTX", "Carla2")
2133 if self
.host
.experimental
:
2134 visible
= settings2
.value(CARLA_KEY_EXPERIMENTAL_JACK_APPS
, CARLA_DEFAULT_EXPERIMENTAL_JACK_APPS
, bool)
2135 self
.ui
.act_plugin_add_jack
.setVisible(visible
)
2137 self
.ui
.act_plugin_add_jack
.setVisible(False)
2139 self
.fMiniCanvasUpdateTimeout
= 1000 if self
.fSavedSettings
[CARLA_KEY_CANVAS_FANCY_EYE_CANDY
] else 0
2141 setEngineSettings(self
.host
, self
.fSavedSettings
)
2142 self
.restartTimersIfNeeded()
2144 if oldSettings
.get(CARLA_KEY_MAIN_CLASSIC_SKIN
, None) not in (self
.fSavedSettings
[CARLA_KEY_MAIN_CLASSIC_SKIN
], None):
2145 newSkin
= "classic" if self
.fSavedSettings
[CARLA_KEY_MAIN_CLASSIC_SKIN
] else None
2147 for pitem
in self
.fPluginList
:
2150 pitem
.recreateWidget(newSkin
= newSkin
)
2154 # --------------------------------------------------------------------------------------------------------
2155 # Settings (helpers)
2157 def enableTransport(self
, enabled
):
2158 self
.ui
.group_transport_controls
.setEnabled(enabled
)
2159 self
.ui
.group_transport_settings
.setEnabled(enabled
)
2162 def slot_restoreCanvasScrollbarValues(self
):
2163 settings
= QSafeSettings()
2164 horiz
= settings
.value("HorizontalScrollBarValue", int(self
.ui
.graphicsView
.horizontalScrollBar().maximum()/2), int)
2165 vertc
= settings
.value("VerticalScrollBarValue", int(self
.ui
.graphicsView
.verticalScrollBar().maximum()/2), int)
2166 self
.ui
.graphicsView
.horizontalScrollBar().setValue(horiz
)
2167 self
.ui
.graphicsView
.verticalScrollBar().setValue(vertc
)
2169 # --------------------------------------------------------------------------------------------------------
2170 # Settings (menu actions)
2173 def slot_showSidePanel(self
, yesNo
):
2174 self
.ui
.dockWidget
.setEnabled(yesNo
)
2175 self
.ui
.dockWidget
.setVisible(yesNo
)
2178 def slot_showToolbar(self
, yesNo
):
2179 self
.ui
.toolBar
.blockSignals(True)
2180 self
.ui
.toolBar
.setEnabled(yesNo
)
2181 self
.ui
.toolBar
.setVisible(yesNo
)
2182 self
.ui
.toolBar
.blockSignals(False)
2185 def slot_showCanvasMeters(self
, yesNo
):
2186 self
.ui
.peak_in
.setVisible(yesNo
)
2187 self
.ui
.peak_out
.setVisible(yesNo
)
2188 QTimer
.singleShot(0, self
.slot_miniCanvasCheckAll
)
2191 def slot_showCanvasKeyboard(self
, yesNo
):
2192 self
.ui
.scrollArea
.setVisible(yesNo
)
2193 QTimer
.singleShot(0, self
.slot_miniCanvasCheckAll
)
2196 def slot_configureCarla(self
):
2197 dialog
= CarlaSettingsW(self
.fParentOrSelf
, self
.host
, True, hasGL
)
2198 if not dialog
.exec_():
2201 self
.loadSettings(False)
2203 if self
.fWithCanvas
:
2206 self
.slot_miniCanvasCheckAll()
2208 if self
.host
.processMode
== ENGINE_PROCESS_MODE_CONTINUOUS_RACK
and self
.host
.isPlugin
:
2210 elif self
.host
.is_engine_running():
2211 self
.host
.patchbay_refresh(self
.fExternalPatchbay
)
2213 # --------------------------------------------------------------------------------------------------------
2214 # About (menu actions)
2217 def slot_aboutCarla(self
):
2218 CarlaAboutW(self
.fParentOrSelf
, self
.host
).exec_()
2221 def slot_aboutQt(self
):
2222 QApplication
.instance().aboutQt()
2224 # --------------------------------------------------------------------------------------------------------
2225 # Disk (menu actions)
2228 def slot_diskFolderChanged(self
, index
):
2233 self
.ui
.b_disk_remove
.setEnabled(False)
2235 filename
= self
.ui
.cb_disk
.itemData(index
)
2236 self
.ui
.b_disk_remove
.setEnabled(True)
2238 self
.fDirModel
.setRootPath(filename
)
2239 self
.ui
.fileTreeView
.setRootIndex(self
.fDirModel
.index(filename
))
2242 def slot_diskFolderAdd(self
):
2243 newPath
= QFileDialog
.getExistingDirectory(self
, self
.tr("New Folder"), "", QFileDialog
.ShowDirsOnly
)
2246 if newPath
[-1] == os
.sep
:
2247 newPath
= newPath
[:-1]
2248 self
.ui
.cb_disk
.addItem(os
.path
.basename(newPath
), newPath
)
2249 self
.ui
.cb_disk
.setCurrentIndex(self
.ui
.cb_disk
.count()-1)
2250 self
.ui
.b_disk_remove
.setEnabled(True)
2253 def slot_diskFolderRemove(self
):
2254 index
= self
.ui
.cb_disk
.currentIndex()
2259 self
.ui
.cb_disk
.removeItem(index
)
2261 if self
.ui
.cb_disk
.currentIndex() == 0:
2262 self
.ui
.b_disk_remove
.setEnabled(False)
2264 @pyqtSlot(QModelIndex
)
2265 def slot_fileTreeDoubleClicked(self
, modelIndex
):
2266 filename
= self
.fDirModel
.filePath(modelIndex
)
2268 if not self
.ui
.listWidget
.isDragUrlValid(filename
):
2271 if not self
.host
.load_file(filename
):
2272 CustomMessageBox(self
, QMessageBox
.Critical
, self
.tr("Error"),
2273 self
.tr("Failed to load file"),
2274 self
.host
.get_last_error(), QMessageBox
.Ok
, QMessageBox
.Ok
)
2277 if filename
.endswith(".carxp"):
2278 self
.loadExternalCanvasGroupPositionsIfNeeded(filename
)
2280 # --------------------------------------------------------------------------------------------------------
2283 def refreshTransport(self
, forced
= False):
2284 if not self
.ui
.l_transport_time
.isVisible():
2286 if self
.fSampleRate
== 0.0 or not self
.host
.is_engine_running():
2289 timeInfo
= self
.host
.get_transport_info()
2290 playing
= timeInfo
['playing']
2291 frame
= timeInfo
['frame']
2292 bpm
= timeInfo
['bpm']
2294 if playing
!= self
.fLastTransportState
or forced
:
2296 if self
.fSavedSettings
[CARLA_KEY_MAIN_SYSTEM_ICONS
]:
2297 icon
= getIcon('media-playback-pause', 16, 'svgz')
2299 icon
= QIcon(":/16x16/media-playback-pause.svgz")
2300 self
.ui
.b_transport_play
.setChecked(True)
2301 self
.ui
.b_transport_play
.setIcon(icon
)
2302 #self.ui.b_transport_play.setText(self.tr("&Pause"))
2304 if self
.fSavedSettings
[CARLA_KEY_MAIN_SYSTEM_ICONS
]:
2305 icon
= getIcon('media-playback-start', 16, 'svgz')
2307 icon
= QIcon(":/16x16/media-playback-start.svgz")
2308 self
.ui
.b_transport_play
.setChecked(False)
2309 self
.ui
.b_transport_play
.setIcon(icon
)
2310 #self.ui.b_play.setText(self.tr("&Play"))
2312 self
.fLastTransportState
= playing
2314 if frame
!= self
.fLastTransportFrame
or forced
:
2315 self
.fLastTransportFrame
= frame
2317 time
= frame
/ self
.fSampleRate
2319 mins
= (time
/ 60) % 60
2320 hrs
= (time
/ 3600) % 60
2321 self
.ui
.l_transport_time
.setText("%02i:%02i:%02i" % (hrs
, mins
, secs
))
2323 frame1
= frame
% 1000
2324 frame2
= (frame
/ 1000) % 1000
2325 frame3
= (frame
/ 1000000) % 1000
2326 self
.ui
.l_transport_frame
.setText("%03i'%03i'%03i" % (frame3
, frame2
, frame1
))
2328 bar
= timeInfo
['bar']
2329 beat
= timeInfo
['beat']
2330 tick
= timeInfo
['tick']
2331 self
.ui
.l_transport_bbt
.setText("%03i|%02i|%04i" % (bar
, beat
, tick
))
2333 if bpm
!= self
.fLastTransportBPM
or forced
:
2334 self
.fLastTransportBPM
= bpm
2337 self
.ui
.dsb_transport_bpm
.blockSignals(True)
2338 self
.ui
.dsb_transport_bpm
.setValue(bpm
)
2339 self
.ui
.dsb_transport_bpm
.blockSignals(False)
2340 self
.ui
.dsb_transport_bpm
.setStyleSheet("")
2342 self
.ui
.dsb_transport_bpm
.setStyleSheet("QDoubleSpinBox { color: palette(mid); }")
2344 # --------------------------------------------------------------------------------------------------------
2345 # Transport (menu actions)
2348 def slot_transportPlayPause(self
, toggled
):
2349 if self
.host
.isPlugin
or not self
.host
.is_engine_running():
2353 self
.host
.transport_play()
2355 self
.host
.transport_pause()
2357 self
.refreshTransport()
2360 def slot_transportStop(self
):
2361 if self
.host
.isPlugin
or not self
.host
.is_engine_running():
2364 self
.host
.transport_pause()
2365 self
.host
.transport_relocate(0)
2367 self
.refreshTransport()
2370 def slot_transportBackwards(self
):
2371 if self
.host
.isPlugin
or not self
.host
.is_engine_running():
2374 newFrame
= self
.host
.get_current_transport_frame() - 100000
2379 self
.host
.transport_relocate(newFrame
)
2382 def slot_transportBpmChanged(self
, newValue
):
2383 self
.host
.transport_bpm(newValue
)
2386 def slot_transportForwards(self
):
2387 if self
.fSampleRate
== 0.0 or self
.host
.isPlugin
or not self
.host
.is_engine_running():
2390 newFrame
= self
.host
.get_current_transport_frame() + int(self
.fSampleRate
*2.5)
2391 self
.host
.transport_relocate(newFrame
)
2394 def slot_transportJackEnabled(self
, clicked
):
2395 if not self
.host
.is_engine_running():
2397 self
.host
.transportMode
= ENGINE_TRANSPORT_MODE_JACK
if clicked
else ENGINE_TRANSPORT_MODE_INTERNAL
2398 self
.host
.set_engine_option(ENGINE_OPTION_TRANSPORT_MODE
,
2399 self
.host
.transportMode
,
2400 self
.host
.transportExtra
)
2403 def slot_transportLinkEnabled(self
, clicked
):
2404 if not self
.host
.is_engine_running():
2406 extra
= ":link:" if clicked
else ""
2407 self
.host
.transportExtra
= extra
2408 self
.host
.set_engine_option(ENGINE_OPTION_TRANSPORT_MODE
,
2409 self
.host
.transportMode
,
2410 self
.host
.transportExtra
)
2412 # --------------------------------------------------------------------------------------------------------
2416 def slot_xrunClear(self
):
2417 self
.host
.clear_engine_xruns()
2419 # --------------------------------------------------------------------------------------------------------
2423 def slot_horizontalScrollBarChanged(self
, value
):
2424 maximum
= self
.ui
.graphicsView
.horizontalScrollBar().maximum()
2428 xp
= float(value
) / maximum
2429 self
.ui
.miniCanvasPreview
.setViewPosX(xp
)
2430 self
.updateCanvasInitialPos()
2433 def slot_verticalScrollBarChanged(self
, value
):
2434 maximum
= self
.ui
.graphicsView
.verticalScrollBar().maximum()
2438 yp
= float(value
) / maximum
2439 self
.ui
.miniCanvasPreview
.setViewPosY(yp
)
2440 self
.updateCanvasInitialPos()
2442 # --------------------------------------------------------------------------------------------------------
2446 def slot_noteOn(self
, note
):
2447 if self
.fPluginCount
== 0:
2450 for pluginId
in self
.fSelectedPlugins
:
2451 self
.host
.send_midi_note(pluginId
, 0, note
, 100)
2453 pedit
= self
.getPluginEditDialog(pluginId
)
2454 pedit
.noteOn(0, note
, 100)
2457 def slot_noteOff(self
, note
):
2458 if self
.fPluginCount
== 0:
2461 for pluginId
in self
.fSelectedPlugins
:
2462 self
.host
.send_midi_note(pluginId
, 0, note
, 0)
2464 pedit
= self
.getPluginEditDialog(pluginId
)
2465 pedit
.noteOff(0, note
)
2467 # --------------------------------------------------------------------------------------------------------
2468 # Canvas keyboard (host callbacks)
2470 @pyqtSlot(int, int, int, int)
2471 def slot_handleNoteOnCallback(self
, pluginId
, channel
, note
, velocity
):
2472 if pluginId
in self
.fSelectedPlugins
:
2473 self
.ui
.keyboard
.sendNoteOn(note
, False)
2475 @pyqtSlot(int, int, int)
2476 def slot_handleNoteOffCallback(self
, pluginId
, channel
, note
):
2477 if pluginId
in self
.fSelectedPlugins
:
2478 self
.ui
.keyboard
.sendNoteOff(note
, False)
2480 # --------------------------------------------------------------------------------------------------------
2483 def slot_handleUpdateCallback(self
, pluginId
):
2484 pitem
= self
.getPluginItem(pluginId
)
2489 wasCompacted
= pitem
.isCompacted()
2490 isCompacted
= wasCompacted
2492 check
= self
.host
.get_custom_data_value(pluginId
, CUSTOM_DATA_TYPE_PROPERTY
, "CarlaSkinIsCompacted")
2495 isCompacted
= bool(check
== "true")
2497 if wasCompacted
== isCompacted
:
2500 pitem
.recreateWidget(True)
2502 # --------------------------------------------------------------------------------------------------------
2506 def slot_miniCanvasCheckAll(self
):
2507 self
.slot_miniCanvasCheckSize()
2508 self
.slot_horizontalScrollBarChanged(self
.ui
.graphicsView
.horizontalScrollBar().value())
2509 self
.slot_verticalScrollBarChanged(self
.ui
.graphicsView
.verticalScrollBar().value())
2512 def slot_miniCanvasCheckSize(self
):
2513 if self
.fCanvasWidth
== 0 or self
.fCanvasHeight
== 0:
2516 currentIndex
= self
.ui
.tabWidget
.currentIndex()
2518 if currentIndex
== 1:
2519 width
= self
.ui
.graphicsView
.width()
2520 height
= self
.ui
.graphicsView
.height()
2522 self
.ui
.tabWidget
.blockSignals(True)
2523 self
.ui
.tabWidget
.setCurrentIndex(1)
2524 width
= self
.ui
.graphicsView
.width()
2525 height
= self
.ui
.graphicsView
.height()
2526 self
.ui
.tabWidget
.setCurrentIndex(currentIndex
)
2527 self
.ui
.tabWidget
.blockSignals(False)
2529 self
.scene
.updateLimits()
2531 self
.ui
.miniCanvasPreview
.setViewSize(float(width
)/self
.fCanvasWidth
, float(height
)/self
.fCanvasHeight
)
2533 @pyqtSlot(float, float)
2534 def slot_miniCanvasMoved(self
, xp
, yp
):
2535 hsb
= self
.ui
.graphicsView
.horizontalScrollBar()
2536 vsb
= self
.ui
.graphicsView
.verticalScrollBar()
2537 hsb
.setValue(xp
* hsb
.maximum())
2538 vsb
.setValue(yp
* vsb
.maximum())
2539 self
.updateCanvasInitialPos()
2541 # --------------------------------------------------------------------------------------------------------
2542 # Logs autoscroll, save and clear
2545 def slot_toggleLogAutoscroll(self
, checkState
):
2546 self
.autoscrollOnNewLog
= checkState
== Qt
.Checked
2547 if self
.autoscrollOnNewLog
:
2548 self
.ui
.text_logs
.verticalScrollBar().setValue(self
.ui
.text_logs
.verticalScrollBar().maximum())
2551 def slot_logSliderMoved(self
, slider_pos
):
2552 if self
.ui
.text_logs
.verticalScrollBar().hasTracking() or self
.autoscrollOnNewLog
:
2553 self
.lastLogSliderPos
= slider_pos
2555 self
.ui
.text_logs
.verticalScrollBar().setValue(self
.lastLogSliderPos
)
2558 def slot_logButtonsState(self
, enabled
=True):
2559 self
.ui
.logs_clear
.setEnabled(enabled
)
2560 self
.ui
.logs_save
.setEnabled(enabled
)
2563 def slot_logSave(self
):
2564 filename
= os
.path
.join(self
.fSavedSettings
[CARLA_KEY_MAIN_PROJECT_FOLDER
], 'carla_log.txt')
2565 filename
, _
= QFileDialog
.getSaveFileName(self
, self
.tr("Save Logs"), filename
)
2571 with
open(filename
, "w") as logfile
:
2572 logfile
.write(self
.ui
.text_logs
.toPlainText())
2578 def slot_logClear(self
):
2579 self
.ui
.text_logs
.clear()
2580 self
.ui
.text_logs
.appendPlainText("======= Logs cleared ========")
2581 self
.slot_logButtonsState(False)
2583 # --------------------------------------------------------------------------------------------------------
2586 def startTimers(self
):
2587 if self
.fIdleTimerFast
== 0:
2588 self
.fIdleTimerFast
= self
.startTimer(self
.fSavedSettings
[CARLA_KEY_MAIN_REFRESH_INTERVAL
])
2590 if self
.fIdleTimerSlow
== 0:
2591 self
.fIdleTimerSlow
= self
.startTimer(self
.fSavedSettings
[CARLA_KEY_MAIN_REFRESH_INTERVAL
]*4)
2593 def restartTimersIfNeeded(self
):
2594 if self
.fIdleTimerFast
!= 0:
2595 self
.killTimer(self
.fIdleTimerFast
)
2596 self
.fIdleTimerFast
= self
.startTimer(self
.fSavedSettings
[CARLA_KEY_MAIN_REFRESH_INTERVAL
])
2598 if self
.fIdleTimerSlow
!= 0:
2599 self
.killTimer(self
.fIdleTimerSlow
)
2600 self
.fIdleTimerSlow
= self
.startTimer(self
.fSavedSettings
[CARLA_KEY_MAIN_REFRESH_INTERVAL
]*4)
2602 def killTimers(self
):
2603 if self
.fIdleTimerFast
!= 0:
2604 self
.killTimer(self
.fIdleTimerFast
)
2605 self
.fIdleTimerFast
= 0
2607 if self
.fIdleTimerSlow
!= 0:
2608 self
.killTimer(self
.fIdleTimerSlow
)
2609 self
.fIdleTimerSlow
= 0
2611 # --------------------------------------------------------------------------------------------------------
2615 def slot_toolbarVisibilityChanged(self
, visible
):
2616 self
.ui
.toolBar
.blockSignals(True)
2617 self
.ui
.toolBar
.setEnabled(visible
)
2618 self
.ui
.toolBar
.blockSignals(False)
2619 self
.ui
.act_settings_show_toolbar
.setChecked(visible
)
2622 def slot_tabChanged(self
, index
):
2626 self
.ui
.graphicsView
.setFocus()
2629 def slot_handleReloadAllCallback(self
, pluginId
):
2630 if pluginId
>= self
.fPluginCount
:
2633 pitem
= self
.fPluginList
[pluginId
]
2637 pitem
.recreateWidget()
2639 # --------------------------------------------------------------------------------------------------------
2641 @pyqtSlot(int, int, str)
2642 def slot_handleNSMCallback(self
, opcode
, valueInt
, valueStr
):
2643 if opcode
== NSM_CALLBACK_INIT
:
2647 elif opcode
== NSM_CALLBACK_ERROR
:
2651 elif opcode
== NSM_CALLBACK_ANNOUNCE
:
2652 self
.fFirstEngineInit
= False
2653 self
.fSessionManagerName
= valueStr
2654 self
.setProperWindowTitle()
2656 # If NSM server does not support optional-gui, revert our initial assumptions that it does
2657 if (valueInt
& (1 << 1)) == 0x0:
2658 self
.fWindowCloseHideGui
= False
2659 self
.ui
.act_file_quit
.setText(self
.tr("&Quit"))
2660 QApplication
.instance().setQuitOnLastWindowClosed(True)
2664 elif opcode
== NSM_CALLBACK_OPEN
:
2665 self
.fProjectFilename
= QFileInfo(valueStr
+".carxp").absoluteFilePath()
2666 self
.setProperWindowTitle()
2668 self
.fCustomStopAction
= self
.CUSTOM_ACTION_PROJECT_LOAD
2669 self
.slot_engineStop(True)
2673 elif opcode
== NSM_CALLBACK_SAVE
:
2674 self
.saveProjectNow()
2677 elif opcode
== NSM_CALLBACK_SESSION_IS_LOADED
:
2681 elif opcode
== NSM_CALLBACK_SHOW_OPTIONAL_GUI
:
2685 elif opcode
== NSM_CALLBACK_HIDE_OPTIONAL_GUI
:
2689 elif opcode
== NSM_CALLBACK_SET_CLIENT_NAME_ID
:
2690 self
.fClientName
= valueStr
2693 self
.host
.nsm_ready(opcode
)
2695 # --------------------------------------------------------------------------------------------------------
2697 def fixLogText(self
, text
):
2698 return text
.replace("\x1b[30;1m", "").replace("\x1b[31m", "").replace("\x1b[0m", "")
2700 @pyqtSlot(int, int, int, int, float, str)
2701 def slot_handleDebugCallback(self
, pluginId
, value1
, value2
, value3
, valuef
, valueStr
):
2702 self
.ui
.text_logs
.appendPlainText(self
.fixLogText(valueStr
))
2705 def slot_handleInfoCallback(self
, info
):
2706 QMessageBox
.information(self
, "Information", info
)
2709 def slot_handleErrorCallback(self
, error
):
2710 QMessageBox
.critical(self
, "Error", error
)
2713 def slot_handleQuitCallback(self
):
2714 self
.fIsProjectLoading
= False
2716 self
.removeAllPlugins()
2717 self
.projectLoadingFinished(False)
2720 def slot_handleInlineDisplayRedrawCallback(self
, pluginId
):
2722 if self
.fIdleTimerSlow
!= 0 and self
.fIdleTimerFast
!= 0 and pluginId
< self
.fPluginCount
and not self
.fIsProjectLoading
:
2723 patchcanvas
.redrawPluginGroup(pluginId
)
2725 # --------------------------------------------------------------------------------------------------------
2728 def slot_handleSIGUSR1(self
):
2729 print("Got SIGUSR1 -> Saving project now")
2730 self
.slot_fileSave()
2733 def slot_handleSIGTERM(self
):
2734 print("Got SIGTERM -> Closing now")
2735 self
.fCustomStopAction
= self
.CUSTOM_ACTION_APP_CLOSE
2738 # --------------------------------------------------------------------------------------------------------
2741 def getExtraPtr(self
, plugin
):
2742 ptype
= plugin
['type']
2744 if ptype
== PLUGIN_LADSPA
:
2745 uniqueId
= plugin
['uniqueId']
2747 self
.maybeLoadRDFs()
2749 for rdfItem
in self
.fLadspaRdfList
:
2750 if rdfItem
.UniqueID
== uniqueId
:
2751 return pointer(rdfItem
)
2753 elif ptype
== PLUGIN_SF2
:
2754 if plugin
['name'].lower().endswith(" (16 outputs)"):
2759 def maybeLoadRDFs(self
):
2760 if not self
.fLadspaRdfNeedsUpdate
:
2763 self
.fLadspaRdfNeedsUpdate
= False
2764 self
.fLadspaRdfList
= []
2769 settingsDir
= os
.path
.join(HOME
, ".config", "falkTX")
2770 frLadspaFile
= os
.path
.join(settingsDir
, "ladspa_rdf.db")
2772 if os
.path
.exists(frLadspaFile
):
2773 frLadspa
= open(frLadspaFile
, 'r')
2776 self
.fLadspaRdfList
= ladspa_rdf
.get_c_ladspa_rdfs(json
.load(frLadspa
))
2782 # --------------------------------------------------------------------------------------------------------
2784 def getPluginCount(self
):
2785 return self
.fPluginCount
2787 def getPluginItem(self
, pluginId
):
2788 if pluginId
>= self
.fPluginCount
:
2791 pitem
= self
.fPluginList
[pluginId
]
2795 #return CarlaRackItem(self, 0, False)
2799 def getPluginEditDialog(self
, pluginId
):
2800 if pluginId
>= self
.fPluginCount
:
2803 pitem
= self
.fPluginList
[pluginId
]
2807 return PluginEdit(self
, self
.host
, 0)
2809 return pitem
.getEditDialog()
2811 def getPluginSlotWidget(self
, pluginId
):
2812 if pluginId
>= self
.fPluginCount
:
2815 pitem
= self
.fPluginList
[pluginId
]
2819 #return AbstractPluginSlot()
2821 return pitem
.getWidget()
2823 # --------------------------------------------------------------------------------------------------------
2825 def waitForPendingEvents(self
):
2828 # --------------------------------------------------------------------------------------------------------
2831 def showEvent(self
, event
):
2832 self
.getAndRefreshRuntimeInfo()
2833 self
.refreshTransport(True)
2834 QMainWindow
.showEvent(self
, event
)
2836 if QT_VERSION
>= 0x50600:
2837 self
.host
.set_engine_option(ENGINE_OPTION_FRONTEND_UI_SCALE
, int(self
.devicePixelRatioF() * 1000), "")
2838 print("Frontend pixel ratio is", self
.devicePixelRatioF())
2840 # set our gui as parent for all plugins UIs
2841 if self
.host
.manageUIs
and not self
.host
.isControl
:
2843 nsViewPtr
= int(self
.winId())
2844 winIdStr
= "%x" % gCarla
.utils
.cocoa_get_window(nsViewPtr
)
2845 elif WINDOWS
or QApplication
.platformName() == "xcb":
2846 winIdStr
= "%x" % int(self
.winId())
2849 self
.host
.set_engine_option(ENGINE_OPTION_FRONTEND_WIN_ID
, 0, winIdStr
)
2851 def hideEvent(self
, event
):
2853 if not self
.host
.isControl
:
2854 self
.host
.set_engine_option(ENGINE_OPTION_FRONTEND_WIN_ID
, 0, "0")
2856 QMainWindow
.hideEvent(self
, event
)
2858 # --------------------------------------------------------------------------------------------------------
2861 def resizeEvent(self
, event
):
2862 QMainWindow
.resizeEvent(self
, event
)
2864 if self
.fWithCanvas
:
2865 self
.slot_miniCanvasCheckSize()
2867 # --------------------------------------------------------------------------------------------------------
2870 def refreshRuntimeInfo(self
, load
, xruns
):
2871 txt1
= str(xruns
) if (xruns
>= 0) else "--"
2872 txt2
= "" if (xruns
== 1) else "s"
2873 self
.ui
.b_xruns
.setText("%s Xrun%s" % (txt1
, txt2
))
2874 self
.ui
.pb_dsp_load
.setValue(int(load
))
2876 def getAndRefreshRuntimeInfo(self
):
2877 if not self
.ui
.pb_dsp_load
.isVisible():
2879 if not self
.host
.is_engine_running():
2881 info
= self
.host
.get_runtime_engine_info()
2882 self
.refreshRuntimeInfo(info
['load'], info
['xruns'])
2885 self
.host
.engine_idle()
2886 self
.refreshTransport()
2888 if self
.fPluginCount
== 0 or self
.fCurrentlyRemovingAllPlugins
:
2891 for pitem
in self
.fPluginList
:
2895 pitem
.getWidget().idleFast()
2897 for pluginId
in self
.fSelectedPlugins
:
2898 self
.fPeaksCleared
= False
2899 if self
.ui
.peak_in
.isVisible():
2900 self
.ui
.peak_in
.displayMeter(1, self
.host
.get_input_peak_value(pluginId
, True))
2901 self
.ui
.peak_in
.displayMeter(2, self
.host
.get_input_peak_value(pluginId
, False))
2902 if self
.ui
.peak_out
.isVisible():
2903 self
.ui
.peak_out
.displayMeter(1, self
.host
.get_output_peak_value(pluginId
, True))
2904 self
.ui
.peak_out
.displayMeter(2, self
.host
.get_output_peak_value(pluginId
, False))
2907 if self
.fPeaksCleared
:
2910 self
.fPeaksCleared
= True
2911 self
.ui
.peak_in
.displayMeter(1, 0.0, True)
2912 self
.ui
.peak_in
.displayMeter(2, 0.0, True)
2913 self
.ui
.peak_out
.displayMeter(1, 0.0, True)
2914 self
.ui
.peak_out
.displayMeter(2, 0.0, True)
2917 self
.getAndRefreshRuntimeInfo()
2919 if self
.fPluginCount
== 0 or self
.fCurrentlyRemovingAllPlugins
:
2922 for pitem
in self
.fPluginList
:
2926 pitem
.getWidget().idleSlow()
2928 def timerEvent(self
, event
):
2929 if event
.timerId() == self
.fIdleTimerFast
:
2932 elif event
.timerId() == self
.fIdleTimerSlow
:
2935 QMainWindow
.timerEvent(self
, event
)
2937 # --------------------------------------------------------------------------------------------------------
2938 # color/style change event
2940 def changeEvent(self
, event
):
2941 if event
.type() in (QEvent
.PaletteChange
, QEvent
.StyleChange
):
2943 QMainWindow
.changeEvent(self
, event
)
2945 def updateStyle(self
):
2946 # Rack padding images setup
2947 rack_imgL
= QImage(":/bitmaps/rack_padding_left.png")
2948 rack_imgR
= QImage(":/bitmaps/rack_padding_right.png")
2952 if PYQT_VERSION
>= 0x50600:
2953 value_fix
= 1.0/(1.0-rack_imgL
.scaled(1, 1, Qt
.IgnoreAspectRatio
, Qt
.SmoothTransformation
).pixelColor(0,0).blackF())
2957 rack_pal
= self
.ui
.rack
.palette()
2958 bg_color
= rack_pal
.window().color()
2959 fg_color
= rack_pal
.text().color()
2960 bg_value
= 1.0 - bg_color
.blackF()
2961 if bg_value
!= 0.0 and bg_value
< min_value
:
2962 pad_color
= bg_color
.lighter(int(100*min_value
/bg_value
*value_fix
))
2964 pad_color
= QColor
.fromHsvF(0.0, 0.0, min_value
*value_fix
)
2966 painter
= QPainter()
2967 fillRect
= rack_imgL
.rect().adjusted(-1,-1,1,1)
2969 painter
.begin(rack_imgL
)
2970 painter
.setCompositionMode(QPainter
.CompositionMode_Multiply
)
2971 painter
.setBrush(pad_color
)
2972 painter
.drawRect(fillRect
)
2974 rack_pixmapL
= QPixmap(rack_imgL
)
2975 self
.imgL_palette
= QPalette()
2976 self
.imgL_palette
.setBrush(QPalette
.Window
, QBrush(rack_pixmapL
))
2977 self
.ui
.pad_left
.setPalette(self
.imgL_palette
)
2978 self
.ui
.pad_left
.setAutoFillBackground(True)
2980 painter
.begin(rack_imgR
)
2981 painter
.setCompositionMode(QPainter
.CompositionMode_Multiply
)
2982 painter
.setBrush(pad_color
)
2983 painter
.drawRect(fillRect
)
2985 rack_pixmapR
= QPixmap(rack_imgR
)
2986 self
.imgR_palette
= QPalette()
2987 self
.imgR_palette
.setBrush(QPalette
.Window
, QBrush(rack_pixmapR
))
2988 self
.ui
.pad_right
.setPalette(self
.imgR_palette
)
2989 self
.ui
.pad_right
.setAutoFillBackground(True)
2991 # qt's rgba is actually argb, so convert that
2992 bg_color_value
= bg_color
.rgba()
2993 bg_color_value
= ((bg_color_value
& 0xffffff) << 8) |
(bg_color_value
>> 24)
2995 fg_color_value
= fg_color
.rgba()
2996 fg_color_value
= ((fg_color_value
& 0xffffff) << 8) |
(fg_color_value
>> 24)
2998 self
.host
.set_engine_option(ENGINE_OPTION_FRONTEND_BACKGROUND_COLOR
, bg_color_value
, "")
2999 self
.host
.set_engine_option(ENGINE_OPTION_FRONTEND_FOREGROUND_COLOR
, fg_color_value
, "")
3001 # --------------------------------------------------------------------------------------------------------
3004 #def paintEvent(self, event):
3005 #QMainWindow.paintEvent(self, event)
3007 #if MACOS or not self.fSavedSettings[CARLA_KEY_CUSTOM_PAINTING]:
3010 #painter = QPainter(self)
3011 #painter.setBrush(QColor(36, 36, 36))
3012 #painter.setPen(QColor(62, 62, 62))
3013 #painter.drawRect(1, self.height()/2, self.width()-3, self.height()-self.height()/2-1)
3015 # --------------------------------------------------------------------------------------------------------
3018 def shouldIgnoreClose(self
):
3019 if self
.host
.isControl
or self
.host
.isPlugin
:
3021 if self
.fCustomStopAction
== self
.CUSTOM_ACTION_APP_CLOSE
:
3023 if self
.fWindowCloseHideGui
:
3025 if self
.fSavedSettings
[CARLA_KEY_MAIN_CONFIRM_EXIT
]:
3026 return QMessageBox
.question(self
, self
.tr("Quit"),
3027 self
.tr("Are you sure you want to quit Carla?"),
3028 QMessageBox
.Yes|QMessageBox
.No
) == QMessageBox
.No
3031 def closeEvent(self
, event
):
3032 if self
.shouldIgnoreClose():
3036 if self
.fWindowCloseHideGui
and self
.fCustomStopAction
!= self
.CUSTOM_ACTION_APP_CLOSE
:
3038 self
.host
.nsm_ready(NSM_CALLBACK_HIDE_OPTIONAL_GUI
)
3041 patchcanvas
.handleAllPluginsRemoved()
3043 if MACOS
and self
.fMacClosingHelper
and not (self
.host
.isControl
or self
.host
.isPlugin
):
3044 self
.fCustomStopAction
= self
.CUSTOM_ACTION_APP_CLOSE
3045 self
.fMacClosingHelper
= False
3048 for i
in reversed(range(self
.fPluginCount
)):
3049 self
.host
.show_custom_ui(i
, False)
3051 QTimer
.singleShot(100, self
.close
)
3057 if self
.host
.is_engine_running() and not (self
.host
.isControl
or self
.host
.isPlugin
):
3058 if not self
.slot_engineStop(True):
3059 self
.fCustomStopAction
= self
.CUSTOM_ACTION_APP_CLOSE
3063 QMainWindow
.closeEvent(self
, event
)
3065 # if we reach this point, fully close ourselves
3067 QApplication
.instance().quit()
3069 # ------------------------------------------------------------------------------------------------
3072 def canvasCallback(action
, value1
, value2
, valueStr
):
3073 host
= gCarla
.gui
.host
3075 if gCarla
.gui
.fCustomStopAction
== HostWindow
.CUSTOM_ACTION_APP_CLOSE
:
3078 if action
== patchcanvas
.ACTION_GROUP_INFO
:
3081 elif action
== patchcanvas
.ACTION_GROUP_RENAME
:
3084 elif action
== patchcanvas
.ACTION_GROUP_SPLIT
:
3086 patchcanvas
.splitGroup(groupId
)
3087 gCarla
.gui
.updateMiniCanvasLater()
3089 elif action
== patchcanvas
.ACTION_GROUP_JOIN
:
3091 patchcanvas
.joinGroup(groupId
)
3092 gCarla
.gui
.updateMiniCanvasLater()
3094 elif action
== patchcanvas
.ACTION_GROUP_POSITION
:
3095 if gCarla
.gui
.fIsProjectLoading
:
3097 if not host
.is_engine_running():
3100 x1
, y1
, x2
, y2
= tuple(int(i
) for i
in valueStr
.split(":"))
3101 host
.patchbay_set_group_pos(gCarla
.gui
.fExternalPatchbay
, groupId
, x1
, y1
, x2
, y2
)
3102 gCarla
.gui
.updateMiniCanvasLater()
3104 elif action
== patchcanvas
.ACTION_PORT_INFO
:
3107 elif action
== patchcanvas
.ACTION_PORT_RENAME
:
3110 elif action
== patchcanvas
.ACTION_PORTS_CONNECT
:
3111 gOut
, pOut
, gIn
, pIn
= tuple(int(i
) for i
in valueStr
.split(":"))
3113 if not host
.patchbay_connect(gCarla
.gui
.fExternalPatchbay
, gOut
, pOut
, gIn
, pIn
):
3114 print("Connection failed:", host
.get_last_error())
3116 elif action
== patchcanvas
.ACTION_PORTS_DISCONNECT
:
3117 connectionId
= value1
3119 if not host
.patchbay_disconnect(gCarla
.gui
.fExternalPatchbay
, connectionId
):
3120 print("Disconnect failed:", host
.get_last_error())
3122 elif action
== patchcanvas
.ACTION_PLUGIN_CLONE
:
3125 if not host
.clone_plugin(pluginId
):
3126 CustomMessageBox(gCarla
.gui
, QMessageBox
.Warning, gCarla
.gui
.tr("Error"), gCarla
.gui
.tr("Operation failed"),
3127 host
.get_last_error(), QMessageBox
.Ok
, QMessageBox
.Ok
)
3129 elif action
== patchcanvas
.ACTION_PLUGIN_EDIT
:
3131 pwidget
= gCarla
.gui
.getPluginSlotWidget(pluginId
)
3133 if pwidget
is not None:
3134 pwidget
.showEditDialog()
3136 elif action
== patchcanvas
.ACTION_PLUGIN_RENAME
:
3138 pwidget
= gCarla
.gui
.getPluginSlotWidget(pluginId
)
3140 if pwidget
is not None:
3141 pwidget
.showRenameDialog()
3143 elif action
== patchcanvas
.ACTION_PLUGIN_REPLACE
:
3145 pwidget
= gCarla
.gui
.getPluginSlotWidget(pluginId
)
3147 if pwidget
is not None:
3148 pwidget
.showReplaceDialog()
3150 elif action
== patchcanvas
.ACTION_PLUGIN_REMOVE
:
3153 if not host
.remove_plugin(pluginId
):
3154 CustomMessageBox(gCarla
.gui
, QMessageBox
.Warning, gCarla
.gui
.tr("Error"), gCarla
.gui
.tr("Operation failed"),
3155 host
.get_last_error(), QMessageBox
.Ok
, QMessageBox
.Ok
)
3157 elif action
== patchcanvas
.ACTION_PLUGIN_SHOW_UI
:
3159 pwidget
= gCarla
.gui
.getPluginSlotWidget(pluginId
)
3161 if pwidget
is not None:
3162 pwidget
.showCustomUI()
3164 elif action
== patchcanvas
.ACTION_BG_RIGHT_CLICK
:
3165 gCarla
.gui
.slot_showPluginActionsMenu()
3167 elif action
== patchcanvas
.ACTION_INLINE_DISPLAY
:
3168 if gCarla
.gui
.fIsProjectLoading
:
3170 if not host
.is_engine_running():
3173 width
, height
= [int(v
) for v
in valueStr
.split(":")]
3174 return host
.render_inline_display(pluginId
, width
, height
)
3176 # ------------------------------------------------------------------------------------------------------------
3179 def engineCallback(host
, action
, pluginId
, value1
, value2
, value3
, valuef
, valueStr
):
3180 # kdevelop likes this :)
3181 if False: host
= CarlaHostNull()
3183 valueStr
= charPtrToString(valueStr
)
3185 if action
== ENGINE_CALLBACK_ENGINE_STARTED
:
3186 host
.processMode
= value1
3187 host
.transportMode
= value2
3188 elif action
== ENGINE_CALLBACK_PROCESS_MODE_CHANGED
:
3189 host
.processMode
= value1
3190 elif action
== ENGINE_CALLBACK_TRANSPORT_MODE_CHANGED
:
3191 host
.transportMode
= value1
3192 host
.transportExtra
= valueStr
3194 if action
== ENGINE_CALLBACK_DEBUG
:
3195 host
.DebugCallback
.emit(pluginId
, value1
, value2
, value3
, valuef
, valueStr
)
3196 elif action
== ENGINE_CALLBACK_PLUGIN_ADDED
:
3197 host
.PluginAddedCallback
.emit(pluginId
, value1
, valueStr
)
3198 elif action
== ENGINE_CALLBACK_PLUGIN_REMOVED
:
3199 host
.PluginRemovedCallback
.emit(pluginId
)
3200 elif action
== ENGINE_CALLBACK_PLUGIN_RENAMED
:
3201 host
.PluginRenamedCallback
.emit(pluginId
, valueStr
)
3202 elif action
== ENGINE_CALLBACK_PLUGIN_UNAVAILABLE
:
3203 host
.PluginUnavailableCallback
.emit(pluginId
, valueStr
)
3204 elif action
== ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED
:
3205 host
.ParameterValueChangedCallback
.emit(pluginId
, value1
, valuef
)
3206 elif action
== ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED
:
3207 host
.ParameterDefaultChangedCallback
.emit(pluginId
, value1
, valuef
)
3208 elif action
== ENGINE_CALLBACK_PARAMETER_MAPPED_CONTROL_INDEX_CHANGED
:
3209 host
.ParameterMappedControlIndexChangedCallback
.emit(pluginId
, value1
, value2
)
3210 elif action
== ENGINE_CALLBACK_PARAMETER_MAPPED_RANGE_CHANGED
:
3211 minimum
, maximum
= (float(v
) for v
in valueStr
.split(":", 2))
3212 host
.ParameterMappedRangeChangedCallback
.emit(pluginId
, value1
, minimum
, maximum
)
3213 elif action
== ENGINE_CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED
:
3214 host
.ParameterMidiChannelChangedCallback
.emit(pluginId
, value1
, value2
)
3215 elif action
== ENGINE_CALLBACK_PROGRAM_CHANGED
:
3216 host
.ProgramChangedCallback
.emit(pluginId
, value1
)
3217 elif action
== ENGINE_CALLBACK_MIDI_PROGRAM_CHANGED
:
3218 host
.MidiProgramChangedCallback
.emit(pluginId
, value1
)
3219 elif action
== ENGINE_CALLBACK_OPTION_CHANGED
:
3220 host
.OptionChangedCallback
.emit(pluginId
, value1
, bool(value2
))
3221 elif action
== ENGINE_CALLBACK_UI_STATE_CHANGED
:
3222 host
.UiStateChangedCallback
.emit(pluginId
, value1
)
3223 elif action
== ENGINE_CALLBACK_NOTE_ON
:
3224 host
.NoteOnCallback
.emit(pluginId
, value1
, value2
, value3
)
3225 elif action
== ENGINE_CALLBACK_NOTE_OFF
:
3226 host
.NoteOffCallback
.emit(pluginId
, value1
, value2
)
3227 elif action
== ENGINE_CALLBACK_UPDATE
:
3228 host
.UpdateCallback
.emit(pluginId
)
3229 elif action
== ENGINE_CALLBACK_RELOAD_INFO
:
3230 host
.ReloadInfoCallback
.emit(pluginId
)
3231 elif action
== ENGINE_CALLBACK_RELOAD_PARAMETERS
:
3232 host
.ReloadParametersCallback
.emit(pluginId
)
3233 elif action
== ENGINE_CALLBACK_RELOAD_PROGRAMS
:
3234 host
.ReloadProgramsCallback
.emit(pluginId
)
3235 elif action
== ENGINE_CALLBACK_RELOAD_ALL
:
3236 host
.ReloadAllCallback
.emit(pluginId
)
3237 elif action
== ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED
:
3238 host
.PatchbayClientAddedCallback
.emit(pluginId
, value1
, value2
, valueStr
)
3239 elif action
== ENGINE_CALLBACK_PATCHBAY_CLIENT_REMOVED
:
3240 host
.PatchbayClientRemovedCallback
.emit(pluginId
)
3241 elif action
== ENGINE_CALLBACK_PATCHBAY_CLIENT_RENAMED
:
3242 host
.PatchbayClientRenamedCallback
.emit(pluginId
, valueStr
)
3243 elif action
== ENGINE_CALLBACK_PATCHBAY_CLIENT_DATA_CHANGED
:
3244 host
.PatchbayClientDataChangedCallback
.emit(pluginId
, value1
, value2
)
3245 elif action
== ENGINE_CALLBACK_PATCHBAY_CLIENT_POSITION_CHANGED
:
3246 host
.PatchbayClientPositionChangedCallback
.emit(pluginId
, value1
, value2
, value3
, int(round(valuef
)))
3247 elif action
== ENGINE_CALLBACK_PATCHBAY_PORT_ADDED
:
3248 host
.PatchbayPortAddedCallback
.emit(pluginId
, value1
, value2
, value3
, valueStr
)
3249 elif action
== ENGINE_CALLBACK_PATCHBAY_PORT_REMOVED
:
3250 host
.PatchbayPortRemovedCallback
.emit(pluginId
, value1
)
3251 elif action
== ENGINE_CALLBACK_PATCHBAY_PORT_CHANGED
:
3252 host
.PatchbayPortChangedCallback
.emit(pluginId
, value1
, value2
, value3
, valueStr
)
3253 elif action
== ENGINE_CALLBACK_PATCHBAY_PORT_GROUP_ADDED
:
3254 host
.PatchbayPortGroupAddedCallback
.emit(pluginId
, value1
, value2
, valueStr
)
3255 elif action
== ENGINE_CALLBACK_PATCHBAY_PORT_GROUP_REMOVED
:
3256 host
.PatchbayPortGroupRemovedCallback
.emit(pluginId
, value1
)
3257 elif action
== ENGINE_CALLBACK_PATCHBAY_PORT_GROUP_CHANGED
:
3258 host
.PatchbayPortGroupChangedCallback
.emit(pluginId
, value1
, value2
, valueStr
)
3259 elif action
== ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED
:
3260 gOut
, pOut
, gIn
, pIn
= [int(i
) for i
in valueStr
.split(":")] # FIXME
3261 host
.PatchbayConnectionAddedCallback
.emit(pluginId
, gOut
, pOut
, gIn
, pIn
)
3262 elif action
== ENGINE_CALLBACK_PATCHBAY_CONNECTION_REMOVED
:
3263 host
.PatchbayConnectionRemovedCallback
.emit(pluginId
, value1
, value2
)
3264 elif action
== ENGINE_CALLBACK_ENGINE_STARTED
:
3265 host
.EngineStartedCallback
.emit(pluginId
, value1
, value2
, value3
, valuef
, valueStr
)
3266 elif action
== ENGINE_CALLBACK_ENGINE_STOPPED
:
3267 host
.EngineStoppedCallback
.emit()
3268 elif action
== ENGINE_CALLBACK_PROCESS_MODE_CHANGED
:
3269 host
.ProcessModeChangedCallback
.emit(value1
)
3270 elif action
== ENGINE_CALLBACK_TRANSPORT_MODE_CHANGED
:
3271 host
.TransportModeChangedCallback
.emit(value1
, valueStr
)
3272 elif action
== ENGINE_CALLBACK_BUFFER_SIZE_CHANGED
:
3273 host
.BufferSizeChangedCallback
.emit(value1
)
3274 elif action
== ENGINE_CALLBACK_SAMPLE_RATE_CHANGED
:
3275 host
.SampleRateChangedCallback
.emit(valuef
)
3276 elif action
== ENGINE_CALLBACK_CANCELABLE_ACTION
:
3277 host
.CancelableActionCallback
.emit(pluginId
, bool(value1
!= 0), valueStr
)
3278 elif action
== ENGINE_CALLBACK_PROJECT_LOAD_FINISHED
:
3279 host
.ProjectLoadFinishedCallback
.emit()
3280 elif action
== ENGINE_CALLBACK_NSM
:
3281 host
.NSMCallback
.emit(value1
, value2
, valueStr
)
3282 elif action
== ENGINE_CALLBACK_IDLE
:
3283 QApplication
.processEvents()
3284 elif action
== ENGINE_CALLBACK_INFO
:
3285 host
.InfoCallback
.emit(valueStr
)
3286 elif action
== ENGINE_CALLBACK_ERROR
:
3287 host
.ErrorCallback
.emit(valueStr
)
3288 elif action
== ENGINE_CALLBACK_QUIT
:
3289 host
.QuitCallback
.emit()
3290 elif action
== ENGINE_CALLBACK_INLINE_DISPLAY_REDRAW
:
3291 host
.InlineDisplayRedrawCallback
.emit(pluginId
)
3293 print("unhandled action", action
)
3295 # ------------------------------------------------------------------------------------------------------------
3298 def fileCallback(ptr
, action
, isDir
, title
, filter):
3299 title
= charPtrToString(title
)
3300 filter = charPtrToString(filter)
3302 if action
== FILE_CALLBACK_OPEN
:
3303 ret
, ok
= QFileDialog
.getOpenFileName(gCarla
.gui
, title
, "", filter) #, QFileDialog.ShowDirsOnly if isDir else 0x0)
3304 elif action
== FILE_CALLBACK_SAVE
:
3305 ret
, ok
= QFileDialog
.getSaveFileName(gCarla
.gui
, title
, "", filter, QFileDialog
.ShowDirsOnly
if isDir
else 0x0)
3309 # FIXME use ok value, test if it works as expected
3315 fileRet
= c_char_p(ret
.encode("utf-8"))
3316 retval
= cast(byref(fileRet
), POINTER(c_uintptr
))
3317 return retval
.contents
.value
3319 # ------------------------------------------------------------------------------------------------------------
3322 def initHost(initName
, libPrefix
, isControl
, isPlugin
, failError
, HostClass
= None):
3323 pathBinaries
, pathResources
= getPaths(libPrefix
)
3325 # --------------------------------------------------------------------------------------------------------
3326 # Fail if binary dir is not found
3328 if not os
.path
.exists(pathBinaries
):
3330 QMessageBox
.critical(None, "Error", "Failed to find the carla binaries, cannot continue")
3334 # --------------------------------------------------------------------------------------------------------
3335 # Check if we should open main lib as local or global
3337 settings
= QSafeSettings("falkTX", "Carla2")
3339 loadGlobal
= settings
.value(CARLA_KEY_EXPERIMENTAL_LOAD_LIB_GLOBAL
, CARLA_DEFAULT_EXPERIMENTAL_LOAD_LIB_GLOBAL
, bool)
3341 # --------------------------------------------------------------------------------------------------------
3342 # Set Carla library name
3344 libname
= "libcarla_%s2.%s" % ("control" if isControl
else "standalone", DLL_EXTENSION
)
3345 libname
= os
.path
.join(pathBinaries
, libname
)
3346 felibname
= os
.path
.join(pathBinaries
, "libcarla_frontend.%s" % (DLL_EXTENSION
))
3347 utilsname
= os
.path
.join(pathBinaries
, "libcarla_utils.%s" % (DLL_EXTENSION
))
3349 # --------------------------------------------------------------------------------------------------------
3352 if not (gCarla
.nogui
and isinstance(gCarla
.nogui
, int)):
3353 print("Carla %s started, status:" % VERSION
)
3354 print(" Python version: %s" % sys
.version
.split(" ",1)[0])
3355 print(" Qt version: %s" % QT_VERSION_STR
)
3356 print(" PyQt version: %s" % PYQT_VERSION_STR
)
3357 print(" Binary dir: %s" % pathBinaries
)
3358 print(" Resources dir: %s" % pathResources
)
3360 # --------------------------------------------------------------------------------------------------------
3365 host
= HostClass() if HostClass
is not None else CarlaHostQtDLL(libname
, loadGlobal
)
3368 host
= HostClass() if HostClass
is not None else CarlaHostQtDLL(libname
, loadGlobal
)
3370 host
= CarlaHostQtNull()
3372 host
.isControl
= isControl
3373 host
.isPlugin
= isPlugin
3375 host
.set_engine_callback(lambda h
,a
,p
,v1
,v2
,v3
,vf
,vs
: engineCallback(host
,a
,p
,v1
,v2
,v3
,vf
,vs
))
3376 host
.set_file_callback(fileCallback
)
3378 # If it's a plugin the paths are already set
3380 host
.pathBinaries
= pathBinaries
3381 host
.pathResources
= pathResources
3382 host
.set_engine_option(ENGINE_OPTION_PATH_BINARIES
, 0, pathBinaries
)
3383 host
.set_engine_option(ENGINE_OPTION_PATH_RESOURCES
, 0, pathResources
)
3386 host
.nsmOK
= host
.nsm_init(os
.getpid(), initName
)
3388 # --------------------------------------------------------------------------------------------------------
3391 if not gCarla
.nogui
:
3392 gCarla
.felib
= CarlaFrontendLib(felibname
)
3394 # --------------------------------------------------------------------------------------------------------
3397 gCarla
.utils
= CarlaUtils(utilsname
)
3398 gCarla
.utils
.set_process_name(os
.path
.basename(initName
))
3405 sys
.stdout
= CarlaPrint(False)
3406 sys
.stderr
= CarlaPrint(True)
3407 sys
.excepthook
= sys_excepthook
3409 # --------------------------------------------------------------------------------------------------------
3414 # ------------------------------------------------------------------------------------------------------------
3415 # Load host settings
3417 def loadHostSettings(host
):
3418 # kdevelop likes this :)
3419 if False: host
= CarlaHostNull()
3421 settings
= QSafeSettings("falkTX", "Carla2")
3423 host
.experimental
= settings
.value(CARLA_KEY_MAIN_EXPERIMENTAL
, CARLA_DEFAULT_MAIN_EXPERIMENTAL
, bool)
3424 host
.exportLV2
= settings
.value(CARLA_KEY_EXPERIMENTAL_EXPORT_LV2
, CARLA_DEFAULT_EXPERIMENTAL_LV2_EXPORT
, bool)
3425 host
.manageUIs
= settings
.value(CARLA_KEY_ENGINE_MANAGE_UIS
, CARLA_DEFAULT_MANAGE_UIS
, bool)
3426 host
.maxParameters
= settings
.value(CARLA_KEY_ENGINE_MAX_PARAMETERS
, CARLA_DEFAULT_MAX_PARAMETERS
, int)
3427 host
.resetXruns
= settings
.value(CARLA_KEY_ENGINE_RESET_XRUNS
, CARLA_DEFAULT_RESET_XRUNS
, bool)
3428 host
.forceStereo
= settings
.value(CARLA_KEY_ENGINE_FORCE_STEREO
, CARLA_DEFAULT_FORCE_STEREO
, bool)
3429 host
.preferPluginBridges
= settings
.value(CARLA_KEY_ENGINE_PREFER_PLUGIN_BRIDGES
, CARLA_DEFAULT_PREFER_PLUGIN_BRIDGES
, bool)
3430 host
.preferUIBridges
= settings
.value(CARLA_KEY_ENGINE_PREFER_UI_BRIDGES
, CARLA_DEFAULT_PREFER_UI_BRIDGES
, bool)
3431 host
.preventBadBehaviour
= settings
.value(CARLA_KEY_EXPERIMENTAL_PREVENT_BAD_BEHAVIOUR
, CARLA_DEFAULT_EXPERIMENTAL_PREVENT_BAD_BEHAVIOUR
, bool)
3432 host
.showLogs
= settings
.value(CARLA_KEY_MAIN_SHOW_LOGS
, CARLA_DEFAULT_MAIN_SHOW_LOGS
, bool) and not WINDOWS
3433 host
.showPluginBridges
= settings
.value(CARLA_KEY_EXPERIMENTAL_PLUGIN_BRIDGES
, CARLA_DEFAULT_EXPERIMENTAL_PLUGIN_BRIDGES
, bool)
3434 host
.showWineBridges
= settings
.value(CARLA_KEY_EXPERIMENTAL_WINE_BRIDGES
, CARLA_DEFAULT_EXPERIMENTAL_WINE_BRIDGES
, bool)
3435 host
.uiBridgesTimeout
= settings
.value(CARLA_KEY_ENGINE_UI_BRIDGES_TIMEOUT
, CARLA_DEFAULT_UI_BRIDGES_TIMEOUT
, int)
3436 host
.uisAlwaysOnTop
= settings
.value(CARLA_KEY_ENGINE_UIS_ALWAYS_ON_TOP
, CARLA_DEFAULT_UIS_ALWAYS_ON_TOP
, bool)
3441 host
.transportExtra
= settings
.value(CARLA_KEY_ENGINE_TRANSPORT_EXTRA
, "", str)
3444 if host
.audioDriverForced
is None:
3445 host
.transportMode
= settings
.value(CARLA_KEY_ENGINE_TRANSPORT_MODE
, CARLA_DEFAULT_TRANSPORT_MODE
, int)
3447 if not host
.processModeForced
:
3448 host
.processMode
= settings
.value(CARLA_KEY_ENGINE_PROCESS_MODE
, CARLA_DEFAULT_PROCESS_MODE
, int)
3450 host
.nextProcessMode
= host
.processMode
3452 # --------------------------------------------------------------------------------------------------------
3453 # fix things if needed
3455 if host
.processMode
== ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS
:
3457 print("LADISH detected but using multiple clients (not allowed), forcing single client now")
3458 host
.nextProcessMode
= host
.processMode
= ENGINE_PROCESS_MODE_SINGLE_CLIENT
3461 host
.transportMode
= ENGINE_TRANSPORT_MODE_JACK
3464 host
.showLogs
= False
3466 # --------------------------------------------------------------------------------------------------------
3467 # run headless host now if nogui option enabled
3470 runHostWithoutUI(host
)
3472 # ------------------------------------------------------------------------------------------------------------
3475 def setHostSettings(host
):
3476 # kdevelop likes this :)
3477 if False: host
= CarlaHostNull()
3479 host
.set_engine_option(ENGINE_OPTION_FORCE_STEREO
, host
.forceStereo
, "")
3480 host
.set_engine_option(ENGINE_OPTION_MAX_PARAMETERS
, host
.maxParameters
, "")
3481 host
.set_engine_option(ENGINE_OPTION_RESET_XRUNS
, host
.resetXruns
, "")
3482 host
.set_engine_option(ENGINE_OPTION_PREFER_PLUGIN_BRIDGES
, host
.preferPluginBridges
, "")
3483 host
.set_engine_option(ENGINE_OPTION_PREFER_UI_BRIDGES
, host
.preferUIBridges
, "")
3484 host
.set_engine_option(ENGINE_OPTION_PREVENT_BAD_BEHAVIOUR
, host
.preventBadBehaviour
, "")
3485 host
.set_engine_option(ENGINE_OPTION_UI_BRIDGES_TIMEOUT
, host
.uiBridgesTimeout
, "")
3486 host
.set_engine_option(ENGINE_OPTION_UIS_ALWAYS_ON_TOP
, host
.uisAlwaysOnTop
, "")
3488 if host
.isPlugin
or host
.isRemote
or host
.is_engine_running():
3491 host
.set_engine_option(ENGINE_OPTION_PROCESS_MODE
, host
.nextProcessMode
, "")
3492 host
.set_engine_option(ENGINE_OPTION_TRANSPORT_MODE
, host
.transportMode
, host
.transportExtra
)
3493 host
.set_engine_option(ENGINE_OPTION_DEBUG_CONSOLE_OUTPUT
, host
.showLogs
, "")
3495 if not (NSM_URL
and host
.nsmOK
):
3496 host
.set_engine_option(ENGINE_OPTION_CLIENT_NAME_PREFIX
, 0, gCarla
.cnprefix
)
3498 # ---------------------------------------------------------------------------------------------------------------------
3499 # Set Engine settings according to carla preferences. Returns selected audio driver.
3501 def setEngineSettings(host
, settings
, oscPort
= None):
3502 # kdevelop likes this :)
3503 if False: host
= CarlaHostNull()
3505 # -----------------------------------------------------------------------------------------------------------------
3506 # do nothing if control
3511 # -----------------------------------------------------------------------------------------------------------------
3512 # fetch settings as needed
3514 if settings
is None:
3515 qsettings
= QSafeSettings("falkTX", "Carla2")
3517 if host
.audioDriverForced
is not None:
3518 audioDriver
= host
.audioDriverForced
3520 audioDriver
= qsettings
.value(CARLA_KEY_ENGINE_AUDIO_DRIVER
, CARLA_DEFAULT_AUDIO_DRIVER
, str)
3522 audioDriverPrefix
= CARLA_KEY_ENGINE_DRIVER_PREFIX
+ audioDriver
3526 CARLA_KEY_ENGINE_AUDIO_DRIVER
: audioDriver
,
3527 CARLA_KEY_ENGINE_AUDIO_DEVICE
: qsettings
.value(audioDriverPrefix
+"/Device", "", str),
3528 CARLA_KEY_ENGINE_BUFFER_SIZE
: qsettings
.value(audioDriverPrefix
+"/BufferSize", CARLA_DEFAULT_AUDIO_BUFFER_SIZE
, int),
3529 CARLA_KEY_ENGINE_SAMPLE_RATE
: qsettings
.value(audioDriverPrefix
+"/SampleRate", CARLA_DEFAULT_AUDIO_SAMPLE_RATE
, int),
3530 CARLA_KEY_ENGINE_TRIPLE_BUFFER
: qsettings
.value(audioDriverPrefix
+"/TripleBuffer", CARLA_DEFAULT_AUDIO_TRIPLE_BUFFER
, bool),
3533 CARLA_KEY_PATHS_AUDIO
: splitter
.join(qsettings
.value(CARLA_KEY_PATHS_AUDIO
, CARLA_DEFAULT_FILE_PATH_AUDIO
, list)),
3534 CARLA_KEY_PATHS_MIDI
: splitter
.join(qsettings
.value(CARLA_KEY_PATHS_MIDI
, CARLA_DEFAULT_FILE_PATH_MIDI
, list)),
3537 CARLA_KEY_PATHS_LADSPA
: splitter
.join(qsettings
.value(CARLA_KEY_PATHS_LADSPA
, CARLA_DEFAULT_LADSPA_PATH
, list)),
3538 CARLA_KEY_PATHS_DSSI
: splitter
.join(qsettings
.value(CARLA_KEY_PATHS_DSSI
, CARLA_DEFAULT_DSSI_PATH
, list)),
3539 CARLA_KEY_PATHS_LV2
: splitter
.join(qsettings
.value(CARLA_KEY_PATHS_LV2
, CARLA_DEFAULT_LV2_PATH
, list)),
3540 CARLA_KEY_PATHS_VST2
: splitter
.join(qsettings
.value(CARLA_KEY_PATHS_VST2
, CARLA_DEFAULT_VST2_PATH
, list)),
3541 CARLA_KEY_PATHS_VST3
: splitter
.join(qsettings
.value(CARLA_KEY_PATHS_VST3
, CARLA_DEFAULT_VST3_PATH
, list)),
3542 CARLA_KEY_PATHS_SF2
: splitter
.join(qsettings
.value(CARLA_KEY_PATHS_SF2
, CARLA_DEFAULT_SF2_PATH
, list)),
3543 CARLA_KEY_PATHS_SFZ
: splitter
.join(qsettings
.value(CARLA_KEY_PATHS_SFZ
, CARLA_DEFAULT_SFZ_PATH
, list)),
3544 CARLA_KEY_PATHS_JSFX
: splitter
.join(qsettings
.value(CARLA_KEY_PATHS_JSFX
, CARLA_DEFAULT_JSFX_PATH
, list)),
3545 CARLA_KEY_PATHS_CLAP
: splitter
.join(qsettings
.value(CARLA_KEY_PATHS_CLAP
, CARLA_DEFAULT_CLAP_PATH
, list)),
3548 CARLA_KEY_OSC_ENABLED
: qsettings
.value(CARLA_KEY_OSC_ENABLED
, CARLA_DEFAULT_OSC_ENABLED
, bool),
3549 CARLA_KEY_OSC_TCP_PORT_ENABLED
: qsettings
.value(CARLA_KEY_OSC_TCP_PORT_ENABLED
, CARLA_DEFAULT_OSC_TCP_PORT_ENABLED
, bool),
3550 CARLA_KEY_OSC_TCP_PORT_RANDOM
: qsettings
.value(CARLA_KEY_OSC_TCP_PORT_RANDOM
, CARLA_DEFAULT_OSC_TCP_PORT_RANDOM
, bool),
3551 CARLA_KEY_OSC_TCP_PORT_NUMBER
: qsettings
.value(CARLA_KEY_OSC_TCP_PORT_NUMBER
, CARLA_DEFAULT_OSC_TCP_PORT_NUMBER
, int),
3552 CARLA_KEY_OSC_UDP_PORT_ENABLED
: qsettings
.value(CARLA_KEY_OSC_UDP_PORT_ENABLED
, CARLA_DEFAULT_OSC_UDP_PORT_ENABLED
, bool),
3553 CARLA_KEY_OSC_UDP_PORT_RANDOM
: qsettings
.value(CARLA_KEY_OSC_UDP_PORT_RANDOM
, CARLA_DEFAULT_OSC_UDP_PORT_RANDOM
, bool),
3554 CARLA_KEY_OSC_UDP_PORT_NUMBER
: qsettings
.value(CARLA_KEY_OSC_UDP_PORT_NUMBER
, CARLA_DEFAULT_OSC_UDP_PORT_NUMBER
, int),
3557 CARLA_KEY_WINE_EXECUTABLE
: qsettings
.value(CARLA_KEY_WINE_EXECUTABLE
, CARLA_DEFAULT_WINE_EXECUTABLE
, str),
3558 CARLA_KEY_WINE_AUTO_PREFIX
: qsettings
.value(CARLA_KEY_WINE_AUTO_PREFIX
, CARLA_DEFAULT_WINE_AUTO_PREFIX
, bool),
3559 CARLA_KEY_WINE_FALLBACK_PREFIX
: qsettings
.value(CARLA_KEY_WINE_FALLBACK_PREFIX
, CARLA_DEFAULT_WINE_FALLBACK_PREFIX
, str),
3560 CARLA_KEY_WINE_RT_PRIO_ENABLED
: qsettings
.value(CARLA_KEY_WINE_RT_PRIO_ENABLED
, CARLA_DEFAULT_WINE_RT_PRIO_ENABLED
, bool),
3561 CARLA_KEY_WINE_BASE_RT_PRIO
: qsettings
.value(CARLA_KEY_WINE_BASE_RT_PRIO
, CARLA_DEFAULT_WINE_BASE_RT_PRIO
, int),
3562 CARLA_KEY_WINE_SERVER_RT_PRIO
: qsettings
.value(CARLA_KEY_WINE_SERVER_RT_PRIO
, CARLA_DEFAULT_WINE_SERVER_RT_PRIO
, int),
3565 # -----------------------------------------------------------------------------------------------------------------
3568 setHostSettings(host
)
3570 # -----------------------------------------------------------------------------------------------------------------
3573 host
.set_engine_option(ENGINE_OPTION_FILE_PATH
, FILE_AUDIO
, settings
[CARLA_KEY_PATHS_AUDIO
])
3574 host
.set_engine_option(ENGINE_OPTION_FILE_PATH
, FILE_MIDI
, settings
[CARLA_KEY_PATHS_MIDI
])
3576 # -----------------------------------------------------------------------------------------------------------------
3579 host
.set_engine_option(ENGINE_OPTION_PLUGIN_PATH
, PLUGIN_LADSPA
, settings
[CARLA_KEY_PATHS_LADSPA
])
3580 host
.set_engine_option(ENGINE_OPTION_PLUGIN_PATH
, PLUGIN_DSSI
, settings
[CARLA_KEY_PATHS_DSSI
])
3581 host
.set_engine_option(ENGINE_OPTION_PLUGIN_PATH
, PLUGIN_LV2
, settings
[CARLA_KEY_PATHS_LV2
])
3582 host
.set_engine_option(ENGINE_OPTION_PLUGIN_PATH
, PLUGIN_VST2
, settings
[CARLA_KEY_PATHS_VST2
])
3583 host
.set_engine_option(ENGINE_OPTION_PLUGIN_PATH
, PLUGIN_VST3
, settings
[CARLA_KEY_PATHS_VST3
])
3584 host
.set_engine_option(ENGINE_OPTION_PLUGIN_PATH
, PLUGIN_SF2
, settings
[CARLA_KEY_PATHS_SF2
])
3585 host
.set_engine_option(ENGINE_OPTION_PLUGIN_PATH
, PLUGIN_SFZ
, settings
[CARLA_KEY_PATHS_SFZ
])
3586 host
.set_engine_option(ENGINE_OPTION_PLUGIN_PATH
, PLUGIN_JSFX
, settings
[CARLA_KEY_PATHS_JSFX
])
3587 host
.set_engine_option(ENGINE_OPTION_PLUGIN_PATH
, PLUGIN_CLAP
, settings
[CARLA_KEY_PATHS_CLAP
])
3589 # -----------------------------------------------------------------------------------------------------------------
3590 # don't continue if plugin
3595 # -----------------------------------------------------------------------------------------------------------------
3598 if oscPort
is not None and isinstance(oscPort
, int):
3600 portNumTCP
= portNumUDP
= oscPort
3603 oscEnabled
= settings
[CARLA_KEY_OSC_ENABLED
]
3605 if not settings
[CARLA_KEY_OSC_TCP_PORT_ENABLED
]:
3607 elif settings
[CARLA_KEY_OSC_TCP_PORT_RANDOM
]:
3610 portNumTCP
= settings
[CARLA_KEY_OSC_TCP_PORT_NUMBER
]
3612 if not settings
[CARLA_KEY_OSC_UDP_PORT_ENABLED
]:
3614 elif settings
[CARLA_KEY_OSC_UDP_PORT_RANDOM
]:
3617 portNumUDP
= settings
[CARLA_KEY_OSC_UDP_PORT_NUMBER
]
3619 host
.set_engine_option(ENGINE_OPTION_OSC_ENABLED
, 1 if oscEnabled
else 0, "")
3620 host
.set_engine_option(ENGINE_OPTION_OSC_PORT_TCP
, portNumTCP
, "")
3621 host
.set_engine_option(ENGINE_OPTION_OSC_PORT_UDP
, portNumUDP
, "")
3623 # -----------------------------------------------------------------------------------------------------------------
3626 host
.set_engine_option(ENGINE_OPTION_WINE_EXECUTABLE
, 0, settings
[CARLA_KEY_WINE_EXECUTABLE
])
3627 host
.set_engine_option(ENGINE_OPTION_WINE_AUTO_PREFIX
, 1 if settings
[CARLA_KEY_WINE_AUTO_PREFIX
] else 0, "")
3628 host
.set_engine_option(ENGINE_OPTION_WINE_FALLBACK_PREFIX
, 0, os
.path
.expanduser(settings
[CARLA_KEY_WINE_FALLBACK_PREFIX
]))
3629 host
.set_engine_option(ENGINE_OPTION_WINE_RT_PRIO_ENABLED
, 1 if settings
[CARLA_KEY_WINE_RT_PRIO_ENABLED
] else 0, "")
3630 host
.set_engine_option(ENGINE_OPTION_WINE_BASE_RT_PRIO
, settings
[CARLA_KEY_WINE_BASE_RT_PRIO
], "")
3631 host
.set_engine_option(ENGINE_OPTION_WINE_SERVER_RT_PRIO
, settings
[CARLA_KEY_WINE_SERVER_RT_PRIO
], "")
3633 # -----------------------------------------------------------------------------------------------------------------
3634 # driver and device settings
3637 audioDriver
= settings
[CARLA_KEY_ENGINE_AUDIO_DRIVER
]
3639 # Only setup audio things if engine is not running
3640 if not host
.is_engine_running():
3641 host
.set_engine_option(ENGINE_OPTION_AUDIO_DRIVER
, 0, audioDriver
)
3642 host
.set_engine_option(ENGINE_OPTION_AUDIO_DEVICE
, 0, settings
[CARLA_KEY_ENGINE_AUDIO_DEVICE
])
3644 if not audioDriver
.startswith("JACK"):
3645 host
.set_engine_option(ENGINE_OPTION_AUDIO_BUFFER_SIZE
, settings
[CARLA_KEY_ENGINE_BUFFER_SIZE
], "")
3646 host
.set_engine_option(ENGINE_OPTION_AUDIO_SAMPLE_RATE
, settings
[CARLA_KEY_ENGINE_SAMPLE_RATE
], "")
3647 host
.set_engine_option(ENGINE_OPTION_AUDIO_TRIPLE_BUFFER
, 1 if settings
[CARLA_KEY_ENGINE_TRIPLE_BUFFER
] else 0, "")
3649 # -----------------------------------------------------------------------------------------------------------------
3650 # fix things if needed
3652 if audioDriver
!= "JACK" and host
.transportMode
== ENGINE_TRANSPORT_MODE_JACK
:
3653 host
.transportMode
= ENGINE_TRANSPORT_MODE_INTERNAL
3654 host
.set_engine_option(ENGINE_OPTION_TRANSPORT_MODE
, ENGINE_TRANSPORT_MODE_INTERNAL
, host
.transportExtra
)
3656 # -----------------------------------------------------------------------------------------------------------------
3657 # return selected driver name
3661 # ---------------------------------------------------------------------------------------------------------------------
3662 # Run Carla without showing UI
3664 def runHostWithoutUI(host
):
3665 # kdevelop likes this :)
3666 if False: host
= CarlaHostNull()
3668 # --------------------------------------------------------------------------------------------------------
3669 # Some initial checks
3671 if not gCarla
.nogui
:
3674 projectFile
= getInitialProjectFile(True)
3676 if gCarla
.nogui
is True:
3680 print("Carla no-gui mode can only be used together with a project file.")
3684 oscPort
= gCarla
.nogui
3686 # --------------------------------------------------------------------------------------------------------
3687 # Additional imports
3689 from time
import sleep
3691 # --------------------------------------------------------------------------------------------------------
3694 audioDriver
= setEngineSettings(host
, None, oscPort
)
3695 if not host
.engine_init(audioDriver
, CARLA_CLIENT_NAME
or "Carla"):
3696 print("Engine failed to initialize, possible reasons:\n%s" % host
.get_last_error())
3699 if projectFile
and not host
.load_project(projectFile
):
3700 print("Failed to load selected project file, possible reasons:\n%s" % host
.get_last_error())
3704 # --------------------------------------------------------------------------------------------------------
3707 print("Carla ready!")
3709 while host
.is_engine_running() and not gCarla
.term
:
3711 sleep(0.0333) # 30 Hz
3713 # --------------------------------------------------------------------------------------------------------
3719 # ------------------------------------------------------------------------------------------------------------