2 # -*- coding: utf-8 -*-
5 # Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com>
7 # This program is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU General Public License as
9 # published by the Free Software Foundation; either version 2 of
10 # the License, or any later version.
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
17 # For a full copy of the GNU General Public License see the doc/GPL.txt file.
19 # ------------------------------------------------------------------------------------------------------------
24 # ------------------------------------------------------------------------------------------------------------
31 # ------------------------------------------------------------------------------------------------------------
34 # This fails in some configurations, assume >= 5.6.0 in that case
36 from PyQt5
.Qt
import PYQT_VERSION
38 PYQT_VERSION
= 0x50600
40 from PyQt5
.QtCore
import (
41 QT_VERSION
, qCritical
, QBuffer
, QEventLoop
, QFileInfo
, QIODevice
, QMimeData
, QModelIndex
, QPointF
, QTimer
, QEvent
43 from PyQt5
.QtGui
import (
44 QImage
, QImageWriter
, QPainter
, QPalette
, QBrush
46 from PyQt5
.QtWidgets
import (
47 QAction
, QApplication
, QInputDialog
, QFileSystemModel
, QListWidgetItem
, QGraphicsView
, QMainWindow
50 # ------------------------------------------------------------------------------------------------------------
55 from carla_app
import *
56 from carla_backend
import *
57 from carla_backend_qt
import CarlaHostQtDLL
, CarlaHostQtNull
58 from carla_frontend
import CarlaFrontendLib
59 from carla_shared
import *
60 from carla_settings
import *
61 from carla_utils
import *
62 from carla_widgets
import *
64 from patchcanvas
import patchcanvas
65 from widgets
.digitalpeakmeter
import DigitalPeakMeter
66 from widgets
.pixmapkeyboard
import PixmapKeyboardHArea
68 # ------------------------------------------------------------------------------------------------------------
72 from PyQt5
.QtOpenGL
import QGLWidget
77 # ------------------------------------------------------------------------------------------------------------
78 # Safe exception hook, needed for PyQt5
80 def sys_excepthook(typ
, value
, tback
):
81 return sys
.__excepthook
__(typ
, value
, tback
)
83 # ------------------------------------------------------------------------------------------------------------
84 # Session Management support
86 CARLA_CLIENT_NAME
= os
.getenv("CARLA_CLIENT_NAME")
87 LADISH_APP_NAME
= os
.getenv("LADISH_APP_NAME")
88 NSM_URL
= os
.getenv("NSM_URL")
90 # ------------------------------------------------------------------------------------------------------------
93 def processMode2Str(processMode
):
94 if processMode
== ENGINE_PROCESS_MODE_SINGLE_CLIENT
:
95 return "Single client"
96 if processMode
== ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS
:
98 if processMode
== ENGINE_PROCESS_MODE_CONTINUOUS_RACK
:
99 return "Continuous Rack"
100 if processMode
== ENGINE_PROCESS_MODE_PATCHBAY
:
102 if processMode
== ENGINE_PROCESS_MODE_BRIDGE
:
106 # ------------------------------------------------------------------------------------------------------------
110 def __init__(self
, err
):
114 gCarla
.utils
.fflush(self
.err
)
116 def write(self
, string
):
117 gCarla
.utils
.fputs(self
.err
, string
)
119 # ------------------------------------------------------------------------------------------------------------
122 class HostWindow(QMainWindow
):
123 #class HostWindow(QMainWindow, PluginEditParentMeta, metaclass=PyQtMetaClass):
125 SIGTERM
= pyqtSignal()
126 SIGUSR1
= pyqtSignal()
129 CUSTOM_ACTION_NONE
= 0
130 CUSTOM_ACTION_APP_CLOSE
= 1
131 CUSTOM_ACTION_PROJECT_LOAD
= 2
133 # --------------------------------------------------------------------------------------------------------
135 def __init__(self
, host
, withCanvas
, parent
=None):
136 QMainWindow
.__init
__(self
, parent
)
138 self
.ui
= ui_carla_host
.Ui_CarlaHostW()
139 self
.ui
.setupUi(self
)
143 # kdevelop likes this :)
144 host
= CarlaHostNull()
147 self
._true
= c_char_p("true".encode("utf-8"))
149 self
.fParentOrSelf
= parent
or self
151 # ----------------------------------------------------------------------------------------------------
154 self
.fIdleTimerNull
= self
.startTimer(1000) # keep application signals alive
155 self
.fIdleTimerFast
= 0
156 self
.fIdleTimerSlow
= 0
158 self
.fLadspaRdfNeedsUpdate
= True
159 self
.fLadspaRdfList
= []
161 self
.fPluginCount
= 0
162 self
.fPluginList
= []
164 self
.fPluginListDialog
= None
165 self
.fFavoritePlugins
= []
167 self
.fProjectFilename
= ""
168 self
.fIsProjectLoading
= False
169 self
.fCurrentlyRemovingAllPlugins
= False
170 self
.fHasLoadedLv2Plugins
= False
172 self
.fLastTransportBPM
= 0.0
173 self
.fLastTransportFrame
= 0
174 self
.fLastTransportState
= False
176 self
.fSampleRate
= 0.0
177 self
.fOscAddressTCP
= ""
178 self
.fOscAddressUDP
= ""
181 self
.fMacClosingHelper
= True
183 # CancelableActionCallback Box
184 self
.fCancelableActionBox
= None
186 # run a custom action after engine is properly closed
187 self
.fCustomStopAction
= self
.CUSTOM_ACTION_NONE
189 # first attempt of auto-start engine doesn't show an error
190 self
.fFirstEngineInit
= True
192 # to be filled with key-value pairs of current settings
193 self
.fSavedSettings
= {}
195 # true if NSM server handles our window management
196 self
.fWindowCloseHideGui
= False
199 self
.fClientName
= "Carla-Control"
200 self
.fSessionManagerName
= "Control"
202 self
.fClientName
= "Carla-Plugin"
203 self
.fSessionManagerName
= "Plugin"
204 elif LADISH_APP_NAME
:
205 self
.fClientName
= LADISH_APP_NAME
206 self
.fSessionManagerName
= ""
207 elif NSM_URL
and host
.nsmOK
:
208 self
.fClientName
= "Carla.tmp"
209 self
.fSessionManagerName
= "Non Session Manager TMP"
210 self
.fWindowCloseHideGui
= True
212 self
.fClientName
= CARLA_CLIENT_NAME
or "Carla"
213 self
.fSessionManagerName
= ""
215 # ----------------------------------------------------------------------------------------------------
216 # Internal stuff (patchbay)
218 self
.fPeaksCleared
= True
220 self
.fExternalPatchbay
= False
221 self
.fSelectedPlugins
= []
223 self
.fCanvasWidth
= 0
224 self
.fCanvasHeight
= 0
225 self
.fMiniCanvasUpdateTimeout
= 0
227 self
.fWithCanvas
= withCanvas
229 # ----------------------------------------------------------------------------------------------------
230 # Internal stuff (logs)
232 self
.autoscrollOnNewLog
= True
233 self
.lastLogSliderPos
= 0
235 # ----------------------------------------------------------------------------------------------------
236 # Set up GUI (engine stopped)
238 if self
.host
.isPlugin
or self
.host
.isControl
:
239 self
.ui
.act_file_save
.setVisible(False)
240 self
.ui
.act_engine_start
.setEnabled(False)
241 self
.ui
.act_engine_start
.setVisible(False)
242 self
.ui
.act_engine_stop
.setEnabled(False)
243 self
.ui
.act_engine_stop
.setVisible(False)
244 self
.ui
.menu_Engine
.setEnabled(False)
245 self
.ui
.menu_Engine
.setVisible(False)
246 self
.ui
.menu_Engine
.menuAction().setVisible(False)
247 self
.ui
.tabWidget
.removeTab(2)
249 if self
.host
.isControl
:
250 self
.ui
.act_file_new
.setVisible(False)
251 self
.ui
.act_file_open
.setVisible(False)
252 self
.ui
.act_file_save_as
.setVisible(False)
253 self
.ui
.tabUtils
.removeTab(0)
255 self
.ui
.act_file_save_as
.setText(self
.tr("Export as..."))
258 self
.ui
.tabWidget
.tabBar().hide()
261 self
.ui
.act_engine_start
.setEnabled(True)
264 self
.ui
.tabWidget
.removeTab(2)
266 if self
.host
.isControl
:
267 self
.ui
.act_file_refresh
.setEnabled(False)
269 self
.ui
.act_file_connect
.setEnabled(False)
270 self
.ui
.act_file_connect
.setVisible(False)
271 self
.ui
.act_file_refresh
.setEnabled(False)
272 self
.ui
.act_file_refresh
.setVisible(False)
274 if self
.fSessionManagerName
and not self
.host
.isPlugin
:
275 self
.ui
.act_file_new
.setEnabled(False)
277 self
.ui
.act_file_open
.setEnabled(False)
278 self
.ui
.act_file_save
.setEnabled(False)
279 self
.ui
.act_file_save_as
.setEnabled(False)
280 self
.ui
.act_engine_stop
.setEnabled(False)
281 self
.ui
.act_plugin_remove_all
.setEnabled(False)
283 self
.ui
.act_canvas_show_internal
.setChecked(False)
284 self
.ui
.act_canvas_show_internal
.setVisible(False)
285 self
.ui
.act_canvas_show_external
.setChecked(False)
286 self
.ui
.act_canvas_show_external
.setVisible(False)
288 self
.ui
.menu_PluginMacros
.setEnabled(False)
289 self
.ui
.menu_Canvas
.setEnabled(False)
291 self
.ui
.dockWidgetTitleBar
= QWidget(self
)
292 self
.ui
.dockWidget
.setTitleBarWidget(self
.ui
.dockWidgetTitleBar
)
295 self
.ui
.act_canvas_show_internal
.setVisible(False)
296 self
.ui
.act_canvas_show_external
.setVisible(False)
297 self
.ui
.act_canvas_arrange
.setVisible(False)
298 self
.ui
.act_canvas_refresh
.setVisible(False)
299 self
.ui
.act_canvas_save_image
.setVisible(False)
300 self
.ui
.act_canvas_zoom_100
.setVisible(False)
301 self
.ui
.act_canvas_zoom_fit
.setVisible(False)
302 self
.ui
.act_canvas_zoom_in
.setVisible(False)
303 self
.ui
.act_canvas_zoom_out
.setVisible(False)
304 self
.ui
.act_settings_show_meters
.setVisible(False)
305 self
.ui
.act_settings_show_keyboard
.setVisible(False)
306 self
.ui
.menu_Canvas_Zoom
.setEnabled(False)
307 self
.ui
.menu_Canvas_Zoom
.setVisible(False)
308 self
.ui
.menu_Canvas_Zoom
.menuAction().setVisible(False)
309 self
.ui
.menu_Canvas
.setEnabled(False)
310 self
.ui
.menu_Canvas
.setVisible(False)
311 self
.ui
.menu_Canvas
.menuAction().setVisible(False)
312 self
.ui
.tw_miniCanvas
.hide()
313 self
.ui
.tabWidget
.removeTab(1)
315 self
.ui
.tabWidget
.tabBar().hide()
317 # ----------------------------------------------------------------------------------------------------
320 exts
= gCarla
.utils
.get_supported_file_extensions()
322 self
.fDirModel
= QFileSystemModel(self
)
323 self
.fDirModel
.setRootPath(HOME
)
324 self
.fDirModel
.setNameFilters(tuple(("*." + i
) for i
in exts
))
326 self
.ui
.fileTreeView
.setModel(self
.fDirModel
)
327 self
.ui
.fileTreeView
.setRootIndex(self
.fDirModel
.index(HOME
))
328 self
.ui
.fileTreeView
.setColumnHidden(1, True)
329 self
.ui
.fileTreeView
.setColumnHidden(2, True)
330 self
.ui
.fileTreeView
.setColumnHidden(3, True)
331 self
.ui
.fileTreeView
.setHeaderHidden(True)
333 # ----------------------------------------------------------------------------------------------------
334 # Set up GUI (transport)
336 fontMetrics
= self
.ui
.l_transport_bbt
.fontMetrics()
337 minValueWidth
= fontMetricsHorizontalAdvance(fontMetrics
, "000|00|0000")
338 minLabelWidth
= fontMetricsHorizontalAdvance(fontMetrics
, self
.ui
.label_transport_frame
.text())
340 labelTimeWidth
= fontMetricsHorizontalAdvance(fontMetrics
, self
.ui
.label_transport_time
.text())
341 labelBBTWidth
= fontMetricsHorizontalAdvance(fontMetrics
, self
.ui
.label_transport_bbt
.text())
343 if minLabelWidth
< labelTimeWidth
:
344 minLabelWidth
= labelTimeWidth
345 if minLabelWidth
< labelBBTWidth
:
346 minLabelWidth
= labelBBTWidth
348 self
.ui
.label_transport_frame
.setMinimumWidth(minLabelWidth
+ 3)
349 self
.ui
.label_transport_time
.setMinimumWidth(minLabelWidth
+ 3)
350 self
.ui
.label_transport_bbt
.setMinimumWidth(minLabelWidth
+ 3)
352 self
.ui
.l_transport_bbt
.setMinimumWidth(minValueWidth
+ 3)
353 self
.ui
.l_transport_frame
.setMinimumWidth(minValueWidth
+ 3)
354 self
.ui
.l_transport_time
.setMinimumWidth(minValueWidth
+ 3)
357 self
.ui
.b_transport_play
.setEnabled(False)
358 self
.ui
.b_transport_stop
.setEnabled(False)
359 self
.ui
.b_transport_backwards
.setEnabled(False)
360 self
.ui
.b_transport_forwards
.setEnabled(False)
361 self
.ui
.group_transport_controls
.setEnabled(False)
362 self
.ui
.group_transport_controls
.setVisible(False)
363 self
.ui
.cb_transport_link
.setEnabled(False)
364 self
.ui
.cb_transport_link
.setVisible(False)
365 self
.ui
.cb_transport_jack
.setEnabled(False)
366 self
.ui
.cb_transport_jack
.setVisible(False)
367 self
.ui
.dsb_transport_bpm
.setEnabled(False)
368 self
.ui
.dsb_transport_bpm
.setReadOnly(True)
370 self
.ui
.w_transport
.setEnabled(False)
372 # ----------------------------------------------------------------------------------------------------
375 self
.ui
.listWidget
.setHostAndParent(self
.host
, self
)
377 sb
= self
.ui
.listWidget
.verticalScrollBar()
378 self
.ui
.rackScrollBar
.setMinimum(sb
.minimum())
379 self
.ui
.rackScrollBar
.setMaximum(sb
.maximum())
380 self
.ui
.rackScrollBar
.setValue(sb
.value())
382 sb
.rangeChanged
.connect(self
.ui
.rackScrollBar
.setRange
)
383 sb
.valueChanged
.connect(self
.ui
.rackScrollBar
.setValue
)
384 self
.ui
.rackScrollBar
.rangeChanged
.connect(sb
.setRange
)
385 self
.ui
.rackScrollBar
.valueChanged
.connect(sb
.setValue
)
389 self
.ui
.rack
.setStyleSheet("""
390 CarlaRackList#CarlaRackList {
391 background-color: black;
395 # ----------------------------------------------------------------------------------------------------
396 # Set up GUI (patchbay)
398 self
.ui
.peak_in
.setChannelCount(2)
399 self
.ui
.peak_in
.setMeterColor(DigitalPeakMeter
.COLOR_BLUE
)
400 self
.ui
.peak_in
.setMeterOrientation(DigitalPeakMeter
.VERTICAL
)
401 self
.ui
.peak_in
.setFixedWidth(25)
403 self
.ui
.peak_out
.setChannelCount(2)
404 self
.ui
.peak_out
.setMeterColor(DigitalPeakMeter
.COLOR_GREEN
)
405 self
.ui
.peak_out
.setMeterOrientation(DigitalPeakMeter
.VERTICAL
)
406 self
.ui
.peak_out
.setFixedWidth(25)
408 self
.ui
.scrollArea
= PixmapKeyboardHArea(self
.ui
.patchbay
)
409 self
.ui
.keyboard
= self
.ui
.scrollArea
.keyboard
410 self
.ui
.patchbay
.layout().addWidget(self
.ui
.scrollArea
, 1, 0, 1, 0)
412 self
.ui
.scrollArea
.setEnabled(False)
414 self
.ui
.miniCanvasPreview
.setRealParent(self
)
415 self
.ui
.tw_miniCanvas
.tabBar().hide()
417 # ----------------------------------------------------------------------------------------------------
420 self
.ui
.text_logs
.textChanged
.connect(self
.slot_logButtonsState
)
421 self
.ui
.logs_clear
.clicked
.connect(self
.slot_logClear
)
422 self
.ui
.logs_save
.clicked
.connect(self
.slot_logSave
)
423 self
.ui
.logs_autoscroll
.stateChanged
.connect(self
.slot_toggleLogAutoscroll
)
424 self
.ui
.text_logs
.verticalScrollBar().valueChanged
.connect(self
.slot_logSliderMoved
)
426 # ----------------------------------------------------------------------------------------------------
427 # Set up GUI (special stuff for Mac OS)
430 self
.ui
.act_file_quit
.setMenuRole(QAction
.QuitRole
)
431 self
.ui
.act_settings_configure
.setMenuRole(QAction
.PreferencesRole
)
432 self
.ui
.act_help_about
.setMenuRole(QAction
.AboutRole
)
433 self
.ui
.act_help_about_juce
.setMenuRole(QAction
.ApplicationSpecificRole
)
434 self
.ui
.act_help_about_qt
.setMenuRole(QAction
.AboutQtRole
)
435 self
.ui
.menu_Settings
.setTitle("Panels")
437 # ----------------------------------------------------------------------------------------------------
440 self
.loadSettings(True)
442 # ----------------------------------------------------------------------------------------------------
446 self
.scene
= patchcanvas
.PatchScene(self
, self
.ui
.graphicsView
)
447 self
.ui
.graphicsView
.setScene(self
.scene
)
449 if self
.fSavedSettings
[CARLA_KEY_CANVAS_USE_OPENGL
] and hasGL
:
450 self
.ui
.glView
= QGLWidget(self
)
451 self
.ui
.graphicsView
.setViewport(self
.ui
.glView
)
455 # ----------------------------------------------------------------------------------------------------
458 if self
.fSavedSettings
[CARLA_KEY_MAIN_SYSTEM_ICONS
]:
459 self
.ui
.act_file_connect
.setIcon(getIcon('network-connect', 16, 'svgz'))
460 self
.ui
.act_file_refresh
.setIcon(getIcon('view-refresh', 16, 'svgz'))
461 self
.ui
.act_file_new
.setIcon(getIcon('document-new', 16, 'svgz'))
462 self
.ui
.act_file_open
.setIcon(getIcon('document-open', 16, 'svgz'))
463 self
.ui
.act_file_save
.setIcon(getIcon('document-save', 16, 'svgz'))
464 self
.ui
.act_file_save_as
.setIcon(getIcon('document-save-as', 16, 'svgz'))
465 self
.ui
.act_file_quit
.setIcon(getIcon('application-exit', 16, 'svgz'))
466 self
.ui
.act_engine_start
.setIcon(getIcon('media-playback-start', 16, 'svgz'))
467 self
.ui
.act_engine_stop
.setIcon(getIcon('media-playback-stop', 16, 'svgz'))
468 self
.ui
.act_engine_panic
.setIcon(getIcon('dialog-warning', 16, 'svgz'))
469 self
.ui
.act_engine_config
.setIcon(getIcon('configure', 16, 'svgz'))
470 self
.ui
.act_plugin_add
.setIcon(getIcon('list-add', 16, 'svgz'))
471 self
.ui
.act_plugin_add_jack
.setIcon(getIcon('list-add', 16, 'svgz'))
472 self
.ui
.act_plugin_remove_all
.setIcon(getIcon('edit-delete', 16, 'svgz'))
473 self
.ui
.act_canvas_arrange
.setIcon(getIcon('view-sort-ascending', 16, 'svgz'))
474 self
.ui
.act_canvas_refresh
.setIcon(getIcon('view-refresh', 16, 'svgz'))
475 self
.ui
.act_canvas_zoom_fit
.setIcon(getIcon('zoom-fit-best', 16, 'svgz'))
476 self
.ui
.act_canvas_zoom_in
.setIcon(getIcon('zoom-in', 16, 'svgz'))
477 self
.ui
.act_canvas_zoom_out
.setIcon(getIcon('zoom-out', 16, 'svgz'))
478 self
.ui
.act_canvas_zoom_100
.setIcon(getIcon('zoom-original', 16, 'svgz'))
479 self
.ui
.act_settings_configure
.setIcon(getIcon('configure', 16, 'svgz'))
480 self
.ui
.b_disk_add
.setIcon(getIcon('list-add', 16, 'svgz'))
481 self
.ui
.b_disk_remove
.setIcon(getIcon('list-remove', 16, 'svgz'))
482 self
.ui
.b_transport_play
.setIcon(getIcon('media-playback-start', 16, 'svgz'))
483 self
.ui
.b_transport_stop
.setIcon(getIcon('media-playback-stop', 16, 'svgz'))
484 self
.ui
.b_transport_backwards
.setIcon(getIcon('media-seek-backward', 16, 'svgz'))
485 self
.ui
.b_transport_forwards
.setIcon(getIcon('media-seek-forward', 16, 'svgz'))
486 self
.ui
.logs_clear
.setIcon(getIcon('edit-clear', 16, 'svgz'))
487 self
.ui
.logs_save
.setIcon(getIcon('document-save', 16, 'svgz'))
489 # ----------------------------------------------------------------------------------------------------
490 # Connect actions to functions
492 self
.ui
.act_file_new
.triggered
.connect(self
.slot_fileNew
)
493 self
.ui
.act_file_open
.triggered
.connect(self
.slot_fileOpen
)
494 self
.ui
.act_file_save
.triggered
.connect(self
.slot_fileSave
)
495 self
.ui
.act_file_save_as
.triggered
.connect(self
.slot_fileSaveAs
)
497 self
.ui
.act_engine_start
.triggered
.connect(self
.slot_engineStart
)
498 self
.ui
.act_engine_stop
.triggered
.connect(self
.slot_engineStop
)
499 self
.ui
.act_engine_panic
.triggered
.connect(self
.slot_pluginsDisable
)
500 self
.ui
.act_engine_config
.triggered
.connect(self
.slot_engineConfig
)
502 self
.ui
.act_plugin_add
.triggered
.connect(self
.slot_pluginAdd
)
503 self
.ui
.act_plugin_add_jack
.triggered
.connect(self
.slot_jackAppAdd
)
504 self
.ui
.act_plugin_remove_all
.triggered
.connect(self
.slot_confirmRemoveAll
)
506 self
.ui
.act_plugins_enable
.triggered
.connect(self
.slot_pluginsEnable
)
507 self
.ui
.act_plugins_disable
.triggered
.connect(self
.slot_pluginsDisable
)
508 self
.ui
.act_plugins_volume100
.triggered
.connect(self
.slot_pluginsVolume100
)
509 self
.ui
.act_plugins_mute
.triggered
.connect(self
.slot_pluginsMute
)
510 self
.ui
.act_plugins_wet100
.triggered
.connect(self
.slot_pluginsWet100
)
511 self
.ui
.act_plugins_bypass
.triggered
.connect(self
.slot_pluginsBypass
)
512 self
.ui
.act_plugins_center
.triggered
.connect(self
.slot_pluginsCenter
)
513 self
.ui
.act_plugins_compact
.triggered
.connect(self
.slot_pluginsCompact
)
514 self
.ui
.act_plugins_expand
.triggered
.connect(self
.slot_pluginsExpand
)
516 self
.ui
.act_settings_show_toolbar
.toggled
.connect(self
.slot_showToolbar
)
517 self
.ui
.act_settings_show_meters
.toggled
.connect(self
.slot_showCanvasMeters
)
518 self
.ui
.act_settings_show_keyboard
.toggled
.connect(self
.slot_showCanvasKeyboard
)
519 self
.ui
.act_settings_show_side_panel
.toggled
.connect(self
.slot_showSidePanel
)
520 self
.ui
.act_settings_configure
.triggered
.connect(self
.slot_configureCarla
)
522 self
.ui
.act_help_about
.triggered
.connect(self
.slot_aboutCarla
)
523 self
.ui
.act_help_about_juce
.triggered
.connect(self
.slot_aboutJuce
)
524 self
.ui
.act_help_about_qt
.triggered
.connect(self
.slot_aboutQt
)
526 self
.ui
.cb_disk
.currentIndexChanged
.connect(self
.slot_diskFolderChanged
)
527 self
.ui
.b_disk_add
.clicked
.connect(self
.slot_diskFolderAdd
)
528 self
.ui
.b_disk_remove
.clicked
.connect(self
.slot_diskFolderRemove
)
529 self
.ui
.fileTreeView
.doubleClicked
.connect(self
.slot_fileTreeDoubleClicked
)
531 self
.ui
.b_transport_play
.clicked
.connect(self
.slot_transportPlayPause
)
532 self
.ui
.b_transport_stop
.clicked
.connect(self
.slot_transportStop
)
533 self
.ui
.b_transport_backwards
.clicked
.connect(self
.slot_transportBackwards
)
534 self
.ui
.b_transport_forwards
.clicked
.connect(self
.slot_transportForwards
)
535 self
.ui
.dsb_transport_bpm
.valueChanged
.connect(self
.slot_transportBpmChanged
)
536 self
.ui
.cb_transport_jack
.clicked
.connect(self
.slot_transportJackEnabled
)
537 self
.ui
.cb_transport_link
.clicked
.connect(self
.slot_transportLinkEnabled
)
539 self
.ui
.b_xruns
.clicked
.connect(self
.slot_xrunClear
)
541 self
.ui
.listWidget
.customContextMenuRequested
.connect(self
.slot_showPluginActionsMenu
)
543 self
.ui
.keyboard
.noteOn
.connect(self
.slot_noteOn
)
544 self
.ui
.keyboard
.noteOff
.connect(self
.slot_noteOff
)
546 self
.ui
.tabWidget
.currentChanged
.connect(self
.slot_tabChanged
)
547 self
.ui
.toolBar
.visibilityChanged
.connect(self
.slot_toolbarVisibilityChanged
)
550 self
.ui
.act_canvas_show_internal
.triggered
.connect(self
.slot_canvasShowInternal
)
551 self
.ui
.act_canvas_show_external
.triggered
.connect(self
.slot_canvasShowExternal
)
552 self
.ui
.act_canvas_arrange
.triggered
.connect(self
.slot_canvasArrange
)
553 self
.ui
.act_canvas_refresh
.triggered
.connect(self
.slot_canvasRefresh
)
554 self
.ui
.act_canvas_zoom_fit
.triggered
.connect(self
.slot_canvasZoomFit
)
555 self
.ui
.act_canvas_zoom_in
.triggered
.connect(self
.slot_canvasZoomIn
)
556 self
.ui
.act_canvas_zoom_out
.triggered
.connect(self
.slot_canvasZoomOut
)
557 self
.ui
.act_canvas_zoom_100
.triggered
.connect(self
.slot_canvasZoomReset
)
558 self
.ui
.act_canvas_save_image
.triggered
.connect(self
.slot_canvasSaveImage
)
559 self
.ui
.act_canvas_save_image_2x
.triggered
.connect(self
.slot_canvasSaveImage
)
560 self
.ui
.act_canvas_save_image_4x
.triggered
.connect(self
.slot_canvasSaveImage
)
561 self
.ui
.act_canvas_copy_clipboard
.triggered
.connect(self
.slot_canvasCopyToClipboard
)
562 self
.ui
.act_canvas_arrange
.setEnabled(False) # TODO, later
563 self
.ui
.graphicsView
.horizontalScrollBar().valueChanged
.connect(self
.slot_horizontalScrollBarChanged
)
564 self
.ui
.graphicsView
.verticalScrollBar().valueChanged
.connect(self
.slot_verticalScrollBarChanged
)
565 self
.ui
.miniCanvasPreview
.miniCanvasMoved
.connect(self
.slot_miniCanvasMoved
)
566 self
.scene
.scaleChanged
.connect(self
.slot_canvasScaleChanged
)
567 self
.scene
.pluginSelected
.connect(self
.slot_canvasPluginSelected
)
568 self
.scene
.selectionChanged
.connect(self
.slot_canvasSelectionChanged
)
570 self
.SIGUSR1
.connect(self
.slot_handleSIGUSR1
)
571 self
.SIGTERM
.connect(self
.slot_handleSIGTERM
)
573 host
.EngineStartedCallback
.connect(self
.slot_handleEngineStartedCallback
)
574 host
.EngineStoppedCallback
.connect(self
.slot_handleEngineStoppedCallback
)
575 host
.TransportModeChangedCallback
.connect(self
.slot_handleTransportModeChangedCallback
)
576 host
.BufferSizeChangedCallback
.connect(self
.slot_handleBufferSizeChangedCallback
)
577 host
.SampleRateChangedCallback
.connect(self
.slot_handleSampleRateChangedCallback
)
578 host
.CancelableActionCallback
.connect(self
.slot_handleCancelableActionCallback
)
579 host
.ProjectLoadFinishedCallback
.connect(self
.slot_handleProjectLoadFinishedCallback
)
581 host
.PluginAddedCallback
.connect(self
.slot_handlePluginAddedCallback
)
582 host
.PluginRemovedCallback
.connect(self
.slot_handlePluginRemovedCallback
)
583 host
.ReloadAllCallback
.connect(self
.slot_handleReloadAllCallback
)
585 host
.NoteOnCallback
.connect(self
.slot_handleNoteOnCallback
)
586 host
.NoteOffCallback
.connect(self
.slot_handleNoteOffCallback
)
588 host
.UpdateCallback
.connect(self
.slot_handleUpdateCallback
)
591 host
.PatchbayClientAddedCallback
.connect(self
.slot_handlePatchbayClientAddedCallback
)
592 host
.PatchbayClientRemovedCallback
.connect(self
.slot_handlePatchbayClientRemovedCallback
)
593 host
.PatchbayClientRenamedCallback
.connect(self
.slot_handlePatchbayClientRenamedCallback
)
594 host
.PatchbayClientDataChangedCallback
.connect(self
.slot_handlePatchbayClientDataChangedCallback
)
595 host
.PatchbayClientPositionChangedCallback
.connect(self
.slot_handlePatchbayClientPositionChangedCallback
)
596 host
.PatchbayPortAddedCallback
.connect(self
.slot_handlePatchbayPortAddedCallback
)
597 host
.PatchbayPortRemovedCallback
.connect(self
.slot_handlePatchbayPortRemovedCallback
)
598 host
.PatchbayPortChangedCallback
.connect(self
.slot_handlePatchbayPortChangedCallback
)
599 host
.PatchbayPortGroupAddedCallback
.connect(self
.slot_handlePatchbayPortGroupAddedCallback
)
600 host
.PatchbayPortGroupRemovedCallback
.connect(self
.slot_handlePatchbayPortGroupRemovedCallback
)
601 host
.PatchbayPortGroupChangedCallback
.connect(self
.slot_handlePatchbayPortGroupChangedCallback
)
602 host
.PatchbayConnectionAddedCallback
.connect(self
.slot_handlePatchbayConnectionAddedCallback
)
603 host
.PatchbayConnectionRemovedCallback
.connect(self
.slot_handlePatchbayConnectionRemovedCallback
)
605 host
.NSMCallback
.connect(self
.slot_handleNSMCallback
)
607 host
.DebugCallback
.connect(self
.slot_handleDebugCallback
)
608 host
.InfoCallback
.connect(self
.slot_handleInfoCallback
)
609 host
.ErrorCallback
.connect(self
.slot_handleErrorCallback
)
610 host
.QuitCallback
.connect(self
.slot_handleQuitCallback
)
611 host
.InlineDisplayRedrawCallback
.connect(self
.slot_handleInlineDisplayRedrawCallback
)
613 # ----------------------------------------------------------------------------------------------------
616 self
.ui
.text_logs
.clear()
617 self
.slot_logButtonsState(False)
618 self
.setProperWindowTitle()
620 # Disable non-supported features
621 features
= gCarla
.utils
.get_supported_features()
623 if "link" not in features
:
624 self
.ui
.cb_transport_link
.setEnabled(False)
625 self
.ui
.cb_transport_link
.setVisible(False)
627 if "juce" not in features
:
628 self
.ui
.act_help_about_juce
.setEnabled(False)
629 self
.ui
.act_help_about_juce
.setVisible(False)
631 # Plugin needs to have timers always running so it receives messages
632 if self
.host
.isPlugin
or self
.host
.isRemote
:
635 # Qt needs this so it properly creates & resizes the canvas
636 self
.ui
.tabWidget
.blockSignals(True)
637 self
.ui
.tabWidget
.setCurrentIndex(1)
638 self
.ui
.tabWidget
.setCurrentIndex(0)
639 self
.ui
.tabWidget
.blockSignals(False)
641 # Start in patchbay tab if using forced patchbay mode
642 if host
.processModeForced
and host
.processMode
== ENGINE_PROCESS_MODE_PATCHBAY
:
643 self
.ui
.tabWidget
.setCurrentIndex(1)
645 # Load initial project file if set
646 if not (self
.host
.isControl
or self
.host
.isPlugin
):
647 projectFile
= getInitialProjectFile(QApplication
.instance())
650 self
.loadProjectLater(projectFile
)
652 # For NSM we wait for the open message
653 if NSM_URL
and host
.nsmOK
:
654 host
.nsm_ready(NSM_CALLBACK_INIT
)
657 if not host
.isControl
:
658 QTimer
.singleShot(0, self
.slot_engineStart
)
660 # --------------------------------------------------------------------------------------------------------
661 # Manage visibility state, needed for NSM
663 def hideForNSM(self
):
664 for pitem
in reversed(self
.fPluginList
):
667 pitem
.getWidget().hideCustomUI()
670 def showIfNeeded(self
):
672 self
.ui
.act_file_quit
.setText(self
.tr("Hide"))
673 QApplication
.instance().setQuitOnLastWindowClosed(False)
677 # --------------------------------------------------------------------------------------------------------
680 def compactPlugin(self
, pluginId
):
681 if pluginId
> self
.fPluginCount
:
684 pitem
= self
.fPluginList
[pluginId
]
689 pitem
.recreateWidget(True)
691 def changePluginColor(self
, pluginId
, color
, colorStr
):
692 if pluginId
> self
.fPluginCount
:
695 pitem
= self
.fPluginList
[pluginId
]
700 self
.host
.set_custom_data(pluginId
, CUSTOM_DATA_TYPE_PROPERTY
, "CarlaColor", colorStr
)
701 pitem
.recreateWidget(newColor
= color
)
703 def changePluginSkin(self
, pluginId
, skin
):
704 if pluginId
> self
.fPluginCount
:
707 pitem
= self
.fPluginList
[pluginId
]
712 self
.host
.set_custom_data(pluginId
, CUSTOM_DATA_TYPE_PROPERTY
, "CarlaSkin", skin
)
713 if skin
not in ("default","rncbc","presets","mpresets"):
714 pitem
.recreateWidget(newSkin
= skin
, newColor
= (255,255,255))
716 pitem
.recreateWidget(newSkin
= skin
)
718 def findPluginInPatchbay(self
, pluginId
):
719 if pluginId
> self
.fPluginCount
:
722 if self
.fExternalPatchbay
:
723 self
.slot_canvasShowInternal()
725 if not patchcanvas
.focusGroupUsingPluginId(pluginId
):
726 name
= self
.host
.get_plugin_info(pluginId
)['name']
727 if not patchcanvas
.focusGroupUsingGroupName(name
):
730 self
.ui
.tabWidget
.setCurrentIndex(1)
732 def switchPlugins(self
, pluginIdA
, pluginIdB
):
733 if pluginIdA
== pluginIdB
:
735 if pluginIdA
< 0 or pluginIdB
< 0:
737 if pluginIdA
>= self
.fPluginCount
or pluginIdB
>= self
.fPluginCount
:
740 self
.host
.switch_plugins(pluginIdA
, pluginIdB
)
742 itemA
= self
.fPluginList
[pluginIdA
]
743 compactA
= itemA
.isCompacted()
744 guiShownA
= itemA
.isGuiShown()
746 itemB
= self
.fPluginList
[pluginIdB
]
747 compactB
= itemB
.isCompacted()
748 guiShownB
= itemB
.isGuiShown()
750 itemA
.setPluginId(pluginIdA
)
751 itemA
.recreateWidget2(compactB
, guiShownB
)
753 itemB
.setPluginId(pluginIdB
)
754 itemB
.recreateWidget2(compactA
, guiShownA
)
757 self
.slot_canvasRefresh()
759 def setLoadRDFsNeeded(self
):
760 self
.fLadspaRdfNeedsUpdate
= True
762 def setProperWindowTitle(self
):
763 title
= self
.fClientName
765 if self
.fProjectFilename
and not self
.host
.nsmOK
:
766 title
+= " - %s" % os
.path
.basename(self
.fProjectFilename
)
767 if self
.fSessionManagerName
:
768 title
+= " (%s)" % self
.fSessionManagerName
770 self
.setWindowTitle(title
)
772 def updateBufferSize(self
, newBufferSize
):
773 if self
.fBufferSize
== newBufferSize
:
775 self
.fBufferSize
= newBufferSize
776 self
.ui
.cb_buffer_size
.clear()
777 self
.ui
.cb_buffer_size
.addItem(str(newBufferSize
))
778 self
.ui
.cb_buffer_size
.setCurrentIndex(0)
780 def updateSampleRate(self
, newSampleRate
):
781 if self
.fSampleRate
== newSampleRate
:
783 self
.fSampleRate
= newSampleRate
784 self
.ui
.cb_sample_rate
.clear()
785 self
.ui
.cb_sample_rate
.addItem(str(newSampleRate
))
786 self
.ui
.cb_sample_rate
.setCurrentIndex(0)
787 self
.refreshTransport(True)
789 # --------------------------------------------------------------------------------------------------------
792 def loadProjectNow(self
):
793 if not self
.fProjectFilename
:
794 return qCritical("ERROR: loading project without filename set")
795 if self
.host
.nsmOK
and not os
.path
.exists(self
.fProjectFilename
):
798 self
.projectLoadingStarted()
799 self
.fIsProjectLoading
= True
801 if not self
.host
.load_project(self
.fProjectFilename
):
802 self
.fIsProjectLoading
= False
803 self
.projectLoadingFinished(True)
805 CustomMessageBox(self
, QMessageBox
.Critical
, self
.tr("Error"), self
.tr("Failed to load project"),
806 self
.host
.get_last_error(),
807 QMessageBox
.Ok
, QMessageBox
.Ok
)
809 def loadProjectLater(self
, filename
):
810 self
.fProjectFilename
= QFileInfo(filename
).absoluteFilePath()
811 self
.setProperWindowTitle()
812 QTimer
.singleShot(1, self
.slot_loadProjectNow
)
814 def saveProjectNow(self
):
815 if not self
.fProjectFilename
:
816 return qCritical("ERROR: saving project without filename set")
818 if not self
.host
.save_project(self
.fProjectFilename
):
819 CustomMessageBox(self
, QMessageBox
.Critical
, self
.tr("Error"), self
.tr("Failed to save project"),
820 self
.host
.get_last_error(),
821 QMessageBox
.Ok
, QMessageBox
.Ok
)
824 def projectLoadingStarted(self
):
825 self
.ui
.rack
.setEnabled(False)
826 self
.ui
.graphicsView
.setEnabled(False)
828 def projectLoadingFinished(self
, refreshCanvas
):
829 self
.ui
.rack
.setEnabled(True)
830 self
.ui
.graphicsView
.setEnabled(True)
832 if self
.fCustomStopAction
== self
.CUSTOM_ACTION_APP_CLOSE
or not self
.fWithCanvas
:
835 if refreshCanvas
and not self
.loadExternalCanvasGroupPositionsIfNeeded(self
.fProjectFilename
):
836 QTimer
.singleShot(1, self
.slot_canvasRefresh
)
838 def loadExternalCanvasGroupPositionsIfNeeded(self
, filename
):
839 extrafile
= filename
.rsplit(".",1)[0]+".json"
840 if not os
.path
.exists(extrafile
):
843 with
open(filename
, "r") as fh
:
844 if "".join(fh
.readlines(90)).find("<CARLA-PROJECT VERSION='2.0'>") < 0:
847 with
open(extrafile
, "r") as fh
:
849 canvasdata
= json
.load(fh
)['canvas']
853 print("NOTICE: loading old-style canvas group positions via legacy json file")
854 patchcanvas
.restoreGroupPositions(canvasdata
)
855 QTimer
.singleShot(1, self
.slot_canvasRefresh
)
858 # --------------------------------------------------------------------------------------------------------
859 # Files (menu actions)
862 def slot_fileNew(self
):
863 if self
.fPluginCount
> 0 and QMessageBox
.question(self
, self
.tr("New File"),
864 self
.tr("Plugins that are currently loaded will be removed. Are you sure?"),
865 QMessageBox
.Yes|QMessageBox
.No
) == QMessageBox
.No
:
868 self
.pluginRemoveAll()
869 self
.fProjectFilename
= ""
870 self
.setProperWindowTitle()
871 self
.host
.clear_project_filename()
874 def slot_fileOpen(self
):
875 fileFilter
= self
.tr("Carla Project File (*.carxp);;Carla Preset File (*.carxs)")
876 filename
, ok
= QFileDialog
.getOpenFileName(self
, self
.tr("Open Carla Project File"), self
.fSavedSettings
[CARLA_KEY_MAIN_PROJECT_FOLDER
], filter=fileFilter
)
878 # FIXME use ok value, test if it works as expected
884 if self
.fPluginCount
> 0:
885 ask
= QMessageBox
.question(self
, self
.tr("Question"), self
.tr("There are some plugins loaded, do you want to remove them now?"),
886 QMessageBox
.Yes | QMessageBox
.No
, QMessageBox
.No
)
887 newFile
= (ask
== QMessageBox
.Yes
)
890 self
.pluginRemoveAll()
891 self
.fProjectFilename
= filename
892 self
.setProperWindowTitle()
893 self
.loadProjectNow()
895 filenameOld
= self
.fProjectFilename
896 self
.fProjectFilename
= filename
897 self
.loadProjectNow()
898 self
.fProjectFilename
= filenameOld
901 def slot_fileSave(self
, saveAs
=False):
902 if self
.fProjectFilename
and not saveAs
:
903 return self
.saveProjectNow()
905 fileFilter
= self
.tr("Carla Project File (*.carxp)")
906 filename
, ok
= QFileDialog
.getSaveFileName(self
, self
.tr("Save Carla Project File"), self
.fSavedSettings
[CARLA_KEY_MAIN_PROJECT_FOLDER
], filter=fileFilter
)
908 # FIXME use ok value, test if it works as expected
912 if not filename
.lower().endswith(".carxp"):
915 if self
.fProjectFilename
!= filename
:
916 self
.fProjectFilename
= filename
917 self
.setProperWindowTitle()
919 self
.saveProjectNow()
922 def slot_fileSaveAs(self
):
923 self
.slot_fileSave(True)
926 def slot_loadProjectNow(self
):
927 self
.loadProjectNow()
929 # --------------------------------------------------------------------------------------------------------
930 # Engine (menu actions)
933 def slot_engineStart(self
):
934 audioDriver
= setEngineSettings(self
.host
, self
.fSavedSettings
)
936 firstInit
= self
.fFirstEngineInit
937 self
.fFirstEngineInit
= False
939 self
.ui
.text_logs
.appendPlainText("======= Starting engine =======")
941 if self
.host
.engine_init(audioDriver
, self
.fClientName
):
942 if firstInit
and not (self
.host
.isControl
or self
.host
.isPlugin
):
943 settings
= QSafeSettings()
944 lastBpm
= settings
.value("LastBPM", 120.0, float)
947 self
.host
.transport_bpm(lastBpm
)
951 self
.ui
.text_logs
.appendPlainText("Failed to start engine on first try, ignored")
954 audioError
= self
.host
.get_last_error()
957 QMessageBox
.critical(self
, self
.tr("Error"),
958 self
.tr("Could not connect to Audio backend '%s', possible reasons:\n%s" % (audioDriver
, audioError
)))
960 QMessageBox
.critical(self
, self
.tr("Error"),
961 self
.tr("Could not connect to Audio backend '%s'" % audioDriver
))
964 def slot_engineStop(self
, forced
= False):
965 self
.ui
.text_logs
.appendPlainText("======= Stopping engine =======")
967 if self
.fPluginCount
== 0 or not self
.host
.is_engine_running():
968 self
.engineStopFinal()
972 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"
973 "Do you want to do this now?"),
974 QMessageBox
.Yes | QMessageBox
.No
, QMessageBox
.No
)
975 if ask
!= QMessageBox
.Yes
:
978 return self
.slot_engineStopTryAgain()
981 def slot_engineConfig(self
):
982 engineRunning
= self
.host
.is_engine_running()
985 dialog
= RuntimeDriverSettingsW(self
.fParentOrSelf
, self
.host
)
988 if self
.host
.isPlugin
:
989 driverName
= "Plugin"
991 elif self
.host
.audioDriverForced
:
992 driverName
= self
.host
.audioDriverForced
995 settings
= QSafeSettings()
996 driverName
= settings
.value(CARLA_KEY_ENGINE_AUDIO_DRIVER
, CARLA_DEFAULT_AUDIO_DRIVER
, str)
997 for i
in range(self
.host
.get_engine_driver_count()):
998 if self
.host
.get_engine_driver_name(i
) == driverName
:
1004 dialog
= DriverSettingsW(self
.fParentOrSelf
, self
.host
, driverIndex
, driverName
)
1005 dialog
.ui
.ico_restart
.hide()
1006 dialog
.ui
.label_restart
.hide()
1009 if not dialog
.exec_():
1012 audioDevice
, bufferSize
, sampleRate
= dialog
.getValues()
1015 self
.host
.set_engine_buffer_size_and_sample_rate(bufferSize
, sampleRate
)
1017 self
.host
.set_engine_option(ENGINE_OPTION_AUDIO_DEVICE
, 0, audioDevice
)
1018 self
.host
.set_engine_option(ENGINE_OPTION_AUDIO_BUFFER_SIZE
, bufferSize
, "")
1019 self
.host
.set_engine_option(ENGINE_OPTION_AUDIO_SAMPLE_RATE
, sampleRate
, "")
1022 def slot_engineStopTryAgain(self
):
1023 if self
.host
.is_engine_running() and not self
.host
.set_engine_about_to_close():
1024 QTimer
.singleShot(0, self
.slot_engineStopTryAgain
)
1027 self
.engineStopFinal()
1030 def engineStopFinal(self
):
1031 patchcanvas
.handleAllPluginsRemoved()
1034 if self
.fCustomStopAction
== self
.CUSTOM_ACTION_PROJECT_LOAD
:
1035 self
.removeAllPlugins()
1037 self
.fProjectFilename
= ""
1038 self
.setProperWindowTitle()
1039 if self
.fPluginCount
!= 0:
1040 self
.fCurrentlyRemovingAllPlugins
= True
1041 self
.projectLoadingStarted()
1043 if self
.host
.is_engine_running() and not self
.host
.remove_all_plugins():
1044 self
.ui
.text_logs
.appendPlainText("Failed to remove all plugins, error was:")
1045 self
.ui
.text_logs
.appendPlainText(self
.host
.get_last_error())
1047 if not self
.host
.engine_close():
1048 self
.ui
.text_logs
.appendPlainText("Failed to stop engine, error was:")
1049 self
.ui
.text_logs
.appendPlainText(self
.host
.get_last_error())
1051 if self
.fCustomStopAction
== self
.CUSTOM_ACTION_APP_CLOSE
:
1053 elif self
.fCustomStopAction
== self
.CUSTOM_ACTION_PROJECT_LOAD
:
1054 self
.slot_engineStart()
1055 self
.loadProjectNow()
1056 self
.host
.nsm_ready(NSM_CALLBACK_OPEN
)
1058 self
.fCustomStopAction
= self
.CUSTOM_ACTION_NONE
1060 # --------------------------------------------------------------------------------------------------------
1061 # Engine (host callbacks)
1063 @pyqtSlot(int, int, int, int, float, str)
1064 def slot_handleEngineStartedCallback(self
, pluginCount
, processMode
, transportMode
, bufferSize
, sampleRate
, driverName
):
1065 self
.ui
.menu_PluginMacros
.setEnabled(True)
1066 self
.ui
.menu_Canvas
.setEnabled(True)
1067 self
.ui
.w_transport
.setEnabled(True)
1069 self
.ui
.act_canvas_show_internal
.blockSignals(True)
1070 self
.ui
.act_canvas_show_external
.blockSignals(True)
1072 if processMode
== ENGINE_PROCESS_MODE_PATCHBAY
and not self
.host
.isPlugin
:
1073 self
.ui
.act_canvas_show_internal
.setChecked(True)
1074 self
.ui
.act_canvas_show_internal
.setVisible(True)
1075 self
.ui
.act_canvas_show_external
.setChecked(False)
1076 self
.ui
.act_canvas_show_external
.setVisible(True)
1077 self
.fExternalPatchbay
= False
1079 self
.ui
.act_canvas_show_internal
.setChecked(False)
1080 self
.ui
.act_canvas_show_internal
.setVisible(False)
1081 self
.ui
.act_canvas_show_external
.setChecked(True)
1082 self
.ui
.act_canvas_show_external
.setVisible(False)
1083 self
.fExternalPatchbay
= not self
.host
.isPlugin
1085 self
.ui
.act_canvas_show_internal
.blockSignals(False)
1086 self
.ui
.act_canvas_show_external
.blockSignals(False)
1088 if not (self
.host
.isControl
or self
.host
.isPlugin
):
1089 canSave
= (self
.fProjectFilename
and os
.path
.exists(self
.fProjectFilename
)) or not self
.fSessionManagerName
1090 self
.ui
.act_file_save
.setEnabled(canSave
)
1091 self
.ui
.act_engine_start
.setEnabled(False)
1092 self
.ui
.act_engine_stop
.setEnabled(True)
1094 if not self
.host
.isPlugin
:
1095 self
.enableTransport(transportMode
!= ENGINE_TRANSPORT_MODE_DISABLED
)
1097 if self
.host
.isPlugin
or not self
.fSessionManagerName
:
1098 self
.ui
.act_file_open
.setEnabled(True)
1099 self
.ui
.act_file_save_as
.setEnabled(True)
1101 self
.ui
.cb_transport_jack
.setChecked(transportMode
== ENGINE_TRANSPORT_MODE_JACK
)
1102 self
.ui
.cb_transport_jack
.setEnabled(driverName
== "JACK" and processMode
!= ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS
)
1104 if self
.ui
.cb_transport_link
.isEnabled():
1105 self
.ui
.cb_transport_link
.setChecked(":link:" in self
.host
.transportExtra
)
1107 self
.updateBufferSize(bufferSize
)
1108 self
.updateSampleRate(int(sampleRate
))
1109 self
.refreshRuntimeInfo(0.0, 0)
1112 self
.ui
.text_logs
.appendPlainText("======= Engine started ========")
1113 self
.ui
.text_logs
.appendPlainText("Carla engine started, details:")
1114 self
.ui
.text_logs
.appendPlainText(" Driver name: %s" % driverName
)
1115 self
.ui
.text_logs
.appendPlainText(" Sample rate: %i" % int(sampleRate
))
1116 self
.ui
.text_logs
.appendPlainText(" Process mode: %s" % processMode2Str(processMode
))
1119 def slot_handleEngineStoppedCallback(self
):
1120 self
.ui
.text_logs
.appendPlainText("======= Engine stopped ========")
1122 if self
.fWithCanvas
:
1128 self
.removeAllPlugins()
1129 self
.refreshRuntimeInfo(0.0, 0)
1131 self
.ui
.menu_PluginMacros
.setEnabled(False)
1132 self
.ui
.menu_Canvas
.setEnabled(False)
1133 self
.ui
.w_transport
.setEnabled(False)
1135 if not (self
.host
.isControl
or self
.host
.isPlugin
):
1136 self
.ui
.act_file_save
.setEnabled(False)
1137 self
.ui
.act_engine_start
.setEnabled(True)
1138 self
.ui
.act_engine_stop
.setEnabled(False)
1140 if self
.host
.isPlugin
or not self
.fSessionManagerName
:
1141 self
.ui
.act_file_open
.setEnabled(False)
1142 self
.ui
.act_file_save_as
.setEnabled(False)
1145 def slot_handleTransportModeChangedCallback(self
, transportMode
, transportExtra
):
1146 self
.enableTransport(transportMode
!= ENGINE_TRANSPORT_MODE_DISABLED
)
1148 self
.ui
.cb_transport_jack
.setChecked(transportMode
== ENGINE_TRANSPORT_MODE_JACK
)
1149 self
.ui
.cb_transport_link
.setChecked(":link:" in transportExtra
)
1152 def slot_handleBufferSizeChangedCallback(self
, newBufferSize
):
1153 self
.updateBufferSize(newBufferSize
)
1156 def slot_handleSampleRateChangedCallback(self
, newSampleRate
):
1157 self
.updateSampleRate(int(newSampleRate
))
1159 @pyqtSlot(int, bool, str)
1160 def slot_handleCancelableActionCallback(self
, pluginId
, started
, action
):
1161 if self
.fCancelableActionBox
is not None:
1162 self
.fCancelableActionBox
.close()
1165 self
.fCancelableActionBox
= QMessageBox(self
)
1166 self
.fCancelableActionBox
.setIcon(QMessageBox
.Information
)
1167 self
.fCancelableActionBox
.setWindowTitle(self
.tr("Action in progress"))
1168 self
.fCancelableActionBox
.setText(action
)
1169 self
.fCancelableActionBox
.setInformativeText(self
.tr("An action is in progress, please wait..."))
1170 self
.fCancelableActionBox
.setStandardButtons(QMessageBox
.Cancel
)
1171 self
.fCancelableActionBox
.setDefaultButton(QMessageBox
.Cancel
)
1172 self
.fCancelableActionBox
.buttonClicked
.connect(self
.slot_canlableActionBoxClicked
)
1173 self
.fCancelableActionBox
.show()
1176 self
.fCancelableActionBox
= None
1179 def slot_canlableActionBoxClicked(self
):
1180 self
.host
.cancel_engine_action()
1183 def slot_handleProjectLoadFinishedCallback(self
):
1184 self
.fIsProjectLoading
= False
1185 self
.projectLoadingFinished(False)
1187 # --------------------------------------------------------------------------------------------------------
1190 def removeAllPlugins(self
):
1191 self
.ui
.act_plugin_remove_all
.setEnabled(False)
1192 patchcanvas
.handleAllPluginsRemoved()
1194 while self
.ui
.listWidget
.takeItem(0):
1197 self
.clearSideStuff()
1199 for pitem
in self
.fPluginList
:
1206 self
.fPluginCount
= 0
1207 self
.fPluginList
= []
1209 # --------------------------------------------------------------------------------------------------------
1210 # Plugins (menu actions)
1212 def showAddPluginDialog(self
):
1213 # TODO self.fHasLoadedLv2Plugins
1214 if self
.fPluginListDialog
is None:
1216 'showPluginBridges': self
.fSavedSettings
[CARLA_KEY_EXPERIMENTAL_PLUGIN_BRIDGES
],
1217 'showWineBridges': self
.fSavedSettings
[CARLA_KEY_EXPERIMENTAL_WINE_BRIDGES
],
1218 'useSystemIcons': self
.fSavedSettings
[CARLA_KEY_MAIN_SYSTEM_ICONS
],
1219 'wineAutoPrefix': self
.fSavedSettings
[CARLA_KEY_WINE_AUTO_PREFIX
],
1220 'wineExecutable': self
.fSavedSettings
[CARLA_KEY_WINE_EXECUTABLE
],
1221 'wineFallbackPrefix': self
.fSavedSettings
[CARLA_KEY_WINE_FALLBACK_PREFIX
],
1223 self
.fPluginListDialog
= d
= gCarla
.felib
.createPluginListDialog(self
.fParentOrSelf
, hostSettings
)
1225 gCarla
.felib
.setPluginListDialogPath(d
, PLUGIN_LADSPA
, self
.fSavedSettings
[CARLA_KEY_PATHS_LADSPA
])
1226 gCarla
.felib
.setPluginListDialogPath(d
, PLUGIN_DSSI
, self
.fSavedSettings
[CARLA_KEY_PATHS_DSSI
])
1227 gCarla
.felib
.setPluginListDialogPath(d
, PLUGIN_LV2
, self
.fSavedSettings
[CARLA_KEY_PATHS_LV2
])
1228 gCarla
.felib
.setPluginListDialogPath(d
, PLUGIN_VST2
, self
.fSavedSettings
[CARLA_KEY_PATHS_VST2
])
1229 gCarla
.felib
.setPluginListDialogPath(d
, PLUGIN_VST3
, self
.fSavedSettings
[CARLA_KEY_PATHS_VST3
])
1230 gCarla
.felib
.setPluginListDialogPath(d
, PLUGIN_SF2
, self
.fSavedSettings
[CARLA_KEY_PATHS_SF2
])
1231 gCarla
.felib
.setPluginListDialogPath(d
, PLUGIN_SFZ
, self
.fSavedSettings
[CARLA_KEY_PATHS_SFZ
])
1232 gCarla
.felib
.setPluginListDialogPath(d
, PLUGIN_JSFX
, self
.fSavedSettings
[CARLA_KEY_PATHS_JSFX
])
1233 gCarla
.felib
.setPluginListDialogPath(d
, PLUGIN_CLAP
, self
.fSavedSettings
[CARLA_KEY_PATHS_CLAP
])
1235 ret
= gCarla
.felib
.execPluginListDialog(self
.fPluginListDialog
)
1238 #if dialog.fFavoritePluginsChanged:
1239 #self.fFavoritePlugins = dialog.fFavoritePlugins
1244 if not self
.host
.is_engine_running():
1245 QMessageBox
.warning(self
, self
.tr("Warning"), self
.tr("Cannot add new plugins while engine is stopped"))
1248 btype
= ret
['build']
1250 filename
= ret
['filename']
1251 label
= ret
['label']
1252 uniqueId
= ret
['uniqueId']
1255 return (btype
, ptype
, filename
, label
, uniqueId
, extraPtr
)
1257 def showAddJackAppDialog(self
):
1258 ret
= gCarla
.felib
.createAndExecJackAppDialog(self
.fParentOrSelf
, self
.fProjectFilename
)
1263 if not self
.host
.is_engine_running():
1264 QMessageBox
.warning(self
, self
.tr("Warning"), self
.tr("Cannot add new plugins while engine is stopped"))
1270 def slot_favoritePluginAdd(self
):
1271 plugin
= self
.sender().data()
1276 if not self
.host
.add_plugin(plugin
['build'], plugin
['type'], plugin
['filename'], None,
1277 plugin
['label'], plugin
['uniqueId'], None, PLUGIN_OPTIONS_NULL
):
1278 # remove plugin from favorites
1280 self
.fFavoritePlugins
.remove(plugin
)
1284 settingsDBf
= QSafeSettings("falkTX", "CarlaDatabase2")
1285 settingsDBf
.setValue("PluginDatabase/Favorites", self
.fFavoritePlugins
)
1289 CustomMessageBox(self
,
1290 QMessageBox
.Critical
,
1292 self
.tr("Failed to load plugin"),
1293 self
.host
.get_last_error(), QMessageBox
.Ok
, QMessageBox
.Ok
)
1296 def slot_showPluginActionsMenu(self
):
1299 menu
.addSection("Plugins")
1300 menu
.addAction(self
.ui
.act_plugin_add
)
1302 if len(self
.fFavoritePlugins
) != 0:
1303 fmenu
= QMenu("Add from favorites", self
)
1304 for p
in self
.fFavoritePlugins
:
1305 act
= fmenu
.addAction(p
['name'])
1307 act
.triggered
.connect(self
.slot_favoritePluginAdd
)
1310 menu
.addAction(self
.ui
.act_plugin_remove_all
)
1312 menu
.addSection("All plugins (macros)")
1313 menu
.addAction(self
.ui
.act_plugins_enable
)
1314 menu
.addAction(self
.ui
.act_plugins_disable
)
1316 menu
.addAction(self
.ui
.act_plugins_volume100
)
1317 menu
.addAction(self
.ui
.act_plugins_mute
)
1319 menu
.addAction(self
.ui
.act_plugins_wet100
)
1320 menu
.addAction(self
.ui
.act_plugins_bypass
)
1322 menu
.addAction(self
.ui
.act_plugins_center
)
1324 menu
.addAction(self
.ui
.act_plugins_compact
)
1325 menu
.addAction(self
.ui
.act_plugins_expand
)
1327 menu
.exec_(QCursor
.pos())
1330 def slot_pluginAdd(self
):
1331 data
= self
.showAddPluginDialog()
1336 btype
, ptype
, filename
, label
, uniqueId
, extraPtr
= data
1338 if not self
.host
.add_plugin(btype
, ptype
, filename
, None, label
, uniqueId
, extraPtr
, PLUGIN_OPTIONS_NULL
):
1339 CustomMessageBox(self
, QMessageBox
.Critical
, self
.tr("Error"), self
.tr("Failed to load plugin"),
1340 self
.host
.get_last_error(), QMessageBox
.Ok
, QMessageBox
.Ok
)
1343 def slot_confirmRemoveAll(self
):
1344 if self
.fPluginCount
== 0:
1347 if QMessageBox
.question(self
, self
.tr("Remove All"),
1348 self
.tr("Are you sure you want to remove all plugins?"),
1349 QMessageBox
.Yes|QMessageBox
.No
) == QMessageBox
.No
:
1352 self
.pluginRemoveAll()
1354 def pluginRemoveAll(self
):
1355 if self
.fPluginCount
== 0:
1358 self
.fCurrentlyRemovingAllPlugins
= True
1359 self
.projectLoadingStarted()
1361 if not self
.host
.remove_all_plugins():
1362 self
.projectLoadingFinished(True)
1363 self
.fCurrentlyRemovingAllPlugins
= False
1364 CustomMessageBox(self
, QMessageBox
.Warning, self
.tr("Error"), self
.tr("Operation failed"),
1365 self
.host
.get_last_error(), QMessageBox
.Ok
, QMessageBox
.Ok
)
1368 def slot_jackAppAdd(self
):
1369 data
= self
.showAddJackAppDialog()
1374 if not data
['command']:
1375 CustomMessageBox(self
, QMessageBox
.Critical
, self
.tr("Error"), self
.tr("Cannot add jack application"),
1376 self
.tr("command is empty"), QMessageBox
.Ok
, QMessageBox
.Ok
)
1379 if not self
.host
.add_plugin(BINARY_NATIVE
, PLUGIN_JACK
,
1380 data
['command'], data
['name'], data
['labelSetup'],
1381 0, None, PLUGIN_OPTIONS_NULL
):
1382 CustomMessageBox(self
, QMessageBox
.Critical
, self
.tr("Error"), self
.tr("Failed to load plugin"),
1383 self
.host
.get_last_error(), QMessageBox
.Ok
, QMessageBox
.Ok
)
1385 # --------------------------------------------------------------------------------------------------------
1389 def slot_pluginsEnable(self
):
1390 if not self
.host
.is_engine_running():
1393 for pitem
in self
.fPluginList
:
1397 pitem
.getWidget().setActive(True, True, True)
1400 def slot_pluginsDisable(self
):
1401 if not self
.host
.is_engine_running():
1404 for pitem
in self
.fPluginList
:
1408 pitem
.getWidget().setActive(False, True, True)
1411 def slot_pluginsVolume100(self
):
1412 if not self
.host
.is_engine_running():
1415 for pitem
in self
.fPluginList
:
1419 pitem
.getWidget().setInternalParameter(PLUGIN_CAN_VOLUME
, 1.0)
1422 def slot_pluginsMute(self
):
1423 if not self
.host
.is_engine_running():
1426 for pitem
in self
.fPluginList
:
1430 pitem
.getWidget().setInternalParameter(PLUGIN_CAN_VOLUME
, 0.0)
1433 def slot_pluginsWet100(self
):
1434 if not self
.host
.is_engine_running():
1437 for pitem
in self
.fPluginList
:
1441 pitem
.getWidget().setInternalParameter(PLUGIN_CAN_DRYWET
, 1.0)
1444 def slot_pluginsBypass(self
):
1445 if not self
.host
.is_engine_running():
1448 for pitem
in self
.fPluginList
:
1452 pitem
.getWidget().setInternalParameter(PLUGIN_CAN_DRYWET
, 0.0)
1455 def slot_pluginsCenter(self
):
1456 if not self
.host
.is_engine_running():
1459 for pitem
in self
.fPluginList
:
1463 pitem
.getWidget().setInternalParameter(PARAMETER_BALANCE_LEFT
, -1.0)
1464 pitem
.getWidget().setInternalParameter(PARAMETER_BALANCE_RIGHT
, 1.0)
1465 pitem
.getWidget().setInternalParameter(PARAMETER_PANNING
, 0.0)
1468 def slot_pluginsCompact(self
):
1469 for pitem
in self
.fPluginList
:
1475 def slot_pluginsExpand(self
):
1476 for pitem
in self
.fPluginList
:
1481 # --------------------------------------------------------------------------------------------------------
1482 # Plugins (host callbacks)
1484 @pyqtSlot(int, int, str)
1485 def slot_handlePluginAddedCallback(self
, pluginId
, pluginType
, pluginName
):
1486 if pluginId
!= self
.fPluginCount
:
1487 print("ERROR: pluginAdded mismatch Id:", pluginId
, self
.fPluginCount
)
1488 pitem
= self
.getPluginItem(pluginId
)
1489 pitem
.recreateWidget()
1492 pitem
= self
.ui
.listWidget
.createItem(pluginId
, self
.fSavedSettings
[CARLA_KEY_MAIN_CLASSIC_SKIN
])
1493 self
.fPluginList
.append(pitem
)
1494 self
.fPluginCount
+= 1
1496 self
.ui
.act_plugin_remove_all
.setEnabled(self
.fPluginCount
> 0)
1498 if pluginType
== PLUGIN_LV2
:
1499 self
.fHasLoadedLv2Plugins
= True
1502 def slot_handlePluginRemovedCallback(self
, pluginId
):
1503 if self
.fWithCanvas
:
1504 patchcanvas
.handlePluginRemoved(pluginId
)
1506 if pluginId
in self
.fSelectedPlugins
:
1507 self
.clearSideStuff()
1509 if self
.fPluginCount
== 0:
1512 pitem
= self
.getPluginItem(pluginId
)
1514 self
.fPluginCount
-= 1
1515 self
.fPluginList
.pop(pluginId
)
1516 self
.ui
.listWidget
.takeItem(pluginId
)
1518 if pitem
is not None:
1522 if self
.fPluginCount
== 0:
1523 self
.ui
.act_plugin_remove_all
.setEnabled(False)
1524 if self
.fCurrentlyRemovingAllPlugins
:
1525 self
.fCurrentlyRemovingAllPlugins
= False
1526 self
.projectLoadingFinished(False)
1529 # push all plugins 1 slot back
1530 for i
in range(pluginId
, self
.fPluginCount
):
1531 pitem
= self
.fPluginList
[i
]
1532 pitem
.setPluginId(i
)
1534 self
.ui
.act_plugin_remove_all
.setEnabled(True)
1536 # --------------------------------------------------------------------------------------------------------
1539 def clearSideStuff(self
):
1540 if self
.fWithCanvas
:
1541 self
.scene
.clearSelection()
1543 self
.fSelectedPlugins
= []
1545 self
.ui
.keyboard
.allNotesOff(False)
1546 self
.ui
.scrollArea
.setEnabled(False)
1548 self
.fPeaksCleared
= True
1549 self
.ui
.peak_in
.displayMeter(1, 0.0, True)
1550 self
.ui
.peak_in
.displayMeter(2, 0.0, True)
1551 self
.ui
.peak_out
.displayMeter(1, 0.0, True)
1552 self
.ui
.peak_out
.displayMeter(2, 0.0, True)
1554 def setupCanvas(self
):
1555 pOptions
= patchcanvas
.options_t()
1556 pOptions
.theme_name
= self
.fSavedSettings
[CARLA_KEY_CANVAS_THEME
]
1557 pOptions
.auto_hide_groups
= self
.fSavedSettings
[CARLA_KEY_CANVAS_AUTO_HIDE_GROUPS
]
1558 pOptions
.auto_select_items
= self
.fSavedSettings
[CARLA_KEY_CANVAS_AUTO_SELECT_ITEMS
]
1559 pOptions
.use_bezier_lines
= self
.fSavedSettings
[CARLA_KEY_CANVAS_USE_BEZIER_LINES
]
1560 pOptions
.antialiasing
= self
.fSavedSettings
[CARLA_KEY_CANVAS_ANTIALIASING
]
1561 pOptions
.inline_displays
= self
.fSavedSettings
[CARLA_KEY_CANVAS_INLINE_DISPLAYS
]
1563 if self
.fSavedSettings
[CARLA_KEY_CANVAS_FANCY_EYE_CANDY
]:
1564 pOptions
.eyecandy
= patchcanvas
.EYECANDY_FULL
1565 elif self
.fSavedSettings
[CARLA_KEY_CANVAS_EYE_CANDY
]:
1566 pOptions
.eyecandy
= patchcanvas
.EYECANDY_SMALL
1568 pOptions
.eyecandy
= patchcanvas
.EYECANDY_NONE
1570 pFeatures
= patchcanvas
.features_t()
1571 pFeatures
.group_info
= False
1572 pFeatures
.group_rename
= False
1573 pFeatures
.port_info
= False
1574 pFeatures
.port_rename
= False
1575 pFeatures
.handle_group_pos
= False
1577 patchcanvas
.setOptions(pOptions
)
1578 patchcanvas
.setFeatures(pFeatures
)
1579 patchcanvas
.init("Carla2", self
.scene
, canvasCallback
, False)
1581 tryCanvasSize
= self
.fSavedSettings
[CARLA_KEY_CANVAS_SIZE
].split("x")
1583 if len(tryCanvasSize
) == 2 and tryCanvasSize
[0].isdigit() and tryCanvasSize
[1].isdigit():
1584 self
.fCanvasWidth
= int(tryCanvasSize
[0])
1585 self
.fCanvasHeight
= int(tryCanvasSize
[1])
1587 self
.fCanvasWidth
= CARLA_DEFAULT_CANVAS_SIZE_WIDTH
1588 self
.fCanvasHeight
= CARLA_DEFAULT_CANVAS_SIZE_HEIGHT
1590 patchcanvas
.setCanvasSize(0, 0, self
.fCanvasWidth
, self
.fCanvasHeight
)
1591 patchcanvas
.setInitialPos(self
.fCanvasWidth
/ 2, self
.fCanvasHeight
/ 2)
1592 self
.ui
.graphicsView
.setSceneRect(0, 0, self
.fCanvasWidth
, self
.fCanvasHeight
)
1594 self
.ui
.miniCanvasPreview
.setViewTheme(patchcanvas
.canvas
.theme
.canvas_bg
, patchcanvas
.canvas
.theme
.rubberband_brush
, patchcanvas
.canvas
.theme
.rubberband_pen
.color())
1595 self
.ui
.miniCanvasPreview
.init(self
.scene
, self
.fCanvasWidth
, self
.fCanvasHeight
, self
.fSavedSettings
[CARLA_KEY_CUSTOM_PAINTING
])
1597 if self
.fSavedSettings
[CARLA_KEY_CANVAS_ANTIALIASING
] != patchcanvas
.ANTIALIASING_NONE
:
1598 self
.ui
.graphicsView
.setRenderHint(QPainter
.Antialiasing
, True)
1600 fullAA
= self
.fSavedSettings
[CARLA_KEY_CANVAS_ANTIALIASING
] == patchcanvas
.ANTIALIASING_FULL
1601 self
.ui
.graphicsView
.setRenderHint(QPainter
.SmoothPixmapTransform
, fullAA
)
1602 self
.ui
.graphicsView
.setRenderHint(QPainter
.TextAntialiasing
, fullAA
)
1604 if self
.fSavedSettings
[CARLA_KEY_CANVAS_USE_OPENGL
] and hasGL
:
1605 self
.ui
.graphicsView
.setRenderHint(QPainter
.HighQualityAntialiasing
, self
.fSavedSettings
[CARLA_KEY_CANVAS_HQ_ANTIALIASING
])
1608 self
.ui
.graphicsView
.setRenderHint(QPainter
.Antialiasing
, False)
1610 if self
.fSavedSettings
[CARLA_KEY_CANVAS_FULL_REPAINTS
]:
1611 self
.ui
.graphicsView
.setViewportUpdateMode(QGraphicsView
.FullViewportUpdate
)
1613 self
.ui
.graphicsView
.setViewportUpdateMode(QGraphicsView
.MinimalViewportUpdate
)
1615 def updateCanvasInitialPos(self
):
1616 x
= self
.ui
.graphicsView
.horizontalScrollBar().value() + self
.width()/4
1617 y
= self
.ui
.graphicsView
.verticalScrollBar().value() + self
.height()/4
1618 patchcanvas
.setInitialPos(x
, y
)
1620 def updateMiniCanvasLater(self
):
1621 QTimer
.singleShot(self
.fMiniCanvasUpdateTimeout
, self
.ui
.miniCanvasPreview
.update
)
1623 # --------------------------------------------------------------------------------------------------------
1624 # Canvas (menu actions)
1627 def slot_canvasShowInternal(self
):
1628 self
.fExternalPatchbay
= False
1629 self
.ui
.act_canvas_show_internal
.blockSignals(True)
1630 self
.ui
.act_canvas_show_external
.blockSignals(True)
1631 self
.ui
.act_canvas_show_internal
.setChecked(True)
1632 self
.ui
.act_canvas_show_external
.setChecked(False)
1633 self
.ui
.act_canvas_show_internal
.blockSignals(False)
1634 self
.ui
.act_canvas_show_external
.blockSignals(False)
1635 self
.slot_canvasRefresh()
1638 def slot_canvasShowExternal(self
):
1639 self
.fExternalPatchbay
= True
1640 self
.ui
.act_canvas_show_internal
.blockSignals(True)
1641 self
.ui
.act_canvas_show_external
.blockSignals(True)
1642 self
.ui
.act_canvas_show_internal
.setChecked(False)
1643 self
.ui
.act_canvas_show_external
.setChecked(True)
1644 self
.ui
.act_canvas_show_internal
.blockSignals(False)
1645 self
.ui
.act_canvas_show_external
.blockSignals(False)
1646 self
.slot_canvasRefresh()
1649 def slot_canvasArrange(self
):
1650 patchcanvas
.arrange()
1653 def slot_canvasRefresh(self
):
1656 if self
.host
.processMode
== ENGINE_PROCESS_MODE_CONTINUOUS_RACK
and self
.host
.isPlugin
:
1659 if self
.host
.is_engine_running():
1660 self
.host
.patchbay_refresh(self
.fExternalPatchbay
)
1662 self
.updateMiniCanvasLater()
1665 def slot_canvasZoomFit(self
):
1666 self
.scene
.zoom_fit()
1669 def slot_canvasZoomIn(self
):
1670 self
.scene
.zoom_in()
1673 def slot_canvasZoomOut(self
):
1674 self
.scene
.zoom_out()
1677 def slot_canvasZoomReset(self
):
1678 self
.scene
.zoom_reset()
1680 def _canvasImageRender(self
, zoom
= 1.0):
1681 image
= QImage(self
.scene
.width()*zoom
, self
.scene
.height()*zoom
, QImage
.Format_RGB32
)
1682 painter
= QPainter(image
)
1684 painter
.setRenderHints(painter
.renderHints() | QPainter
.Antialiasing | QPainter
.TextAntialiasing
)
1685 self
.scene
.clearSelection()
1686 self
.scene
.render(painter
)
1691 def _canvasImageWrite(self
, iw
: QImageWriter
, imgFormat
: bytes
, image
: QImage
):
1692 iw
.setFormat(imgFormat
)
1693 iw
.setCompression(-1)
1694 if QT_VERSION
>= 0x50500:
1695 iw
.setOptimizedWrite(True)
1699 def slot_canvasSaveImage(self
):
1700 if self
.fProjectFilename
:
1701 dir = QFileInfo(self
.fProjectFilename
).absoluteDir().absolutePath()
1703 dir = self
.fSavedSettings
[CARLA_KEY_MAIN_PROJECT_FOLDER
]
1705 fileDialog
= QFileDialog(self
)
1706 fileDialog
.setAcceptMode(QFileDialog
.AcceptSave
)
1707 fileDialog
.setDirectory(dir)
1708 fileDialog
.setFileMode(QFileDialog
.AnyFile
)
1709 fileDialog
.setMimeTypeFilters(("image/png", "image/jpeg"))
1710 fileDialog
.setNameFilter(self
.tr("Images (*.png *.jpg)"))
1711 fileDialog
.setOptions(QFileDialog
.DontUseCustomDirectoryIcons
)
1712 fileDialog
.setWindowTitle(self
.tr("Save Image"))
1714 ok
= fileDialog
.exec_()
1719 newPath
= fileDialog
.selectedFiles()
1721 if len(newPath
) != 1:
1724 newPath
= newPath
[0]
1726 if QT_VERSION
>= 0x50900:
1727 if fileDialog
.selectedMimeTypeFilter() == "image/jpeg":
1732 if newPath
.lower().endswith((".jpg", ".jpeg")):
1737 sender
= self
.sender()
1738 if sender
== self
.ui
.act_canvas_save_image_2x
:
1740 elif sender
== self
.ui
.act_canvas_save_image_4x
:
1745 image
= self
._canvasImageRender
(zoom
)
1746 iw
= QImageWriter(newPath
)
1747 self
._canvasImageWrite
(iw
, imgFormat
, image
)
1750 def slot_canvasCopyToClipboard(self
):
1752 buffer.open(QIODevice
.WriteOnly
)
1754 image
= self
._canvasImageRender
()
1755 iw
= QImageWriter(buffer, b
"PNG")
1756 self
._canvasImageWrite
(iw
, b
"PNG", image
)
1760 mimeData
= QMimeData()
1761 mimeData
.setData("image/png", buffer.buffer());
1763 QApplication
.clipboard().setMimeData(mimeData
)
1765 # --------------------------------------------------------------------------------------------------------
1766 # Canvas (canvas callbacks)
1769 def slot_canvasSelectionChanged(self
):
1770 self
.updateMiniCanvasLater()
1773 def slot_canvasScaleChanged(self
, scale
):
1774 self
.ui
.miniCanvasPreview
.setViewScale(scale
)
1777 def slot_canvasPluginSelected(self
, pluginList
):
1778 self
.ui
.keyboard
.allNotesOff(False)
1779 self
.ui
.scrollArea
.setEnabled(len(pluginList
) != 0) # and self.fPluginCount > 0
1780 self
.fSelectedPlugins
= pluginList
1782 # --------------------------------------------------------------------------------------------------------
1783 # Canvas (host callbacks)
1785 @pyqtSlot(int, int, int, str)
1786 def slot_handlePatchbayClientAddedCallback(self
, clientId
, clientIcon
, pluginId
, clientName
):
1787 pcSplit
= patchcanvas
.SPLIT_UNDEF
1788 pcIcon
= patchcanvas
.ICON_APPLICATION
1790 if clientIcon
== PATCHBAY_ICON_PLUGIN
:
1791 pcIcon
= patchcanvas
.ICON_PLUGIN
1792 if clientIcon
== PATCHBAY_ICON_HARDWARE
:
1793 pcIcon
= patchcanvas
.ICON_HARDWARE
1794 elif clientIcon
== PATCHBAY_ICON_CARLA
:
1796 elif clientIcon
== PATCHBAY_ICON_DISTRHO
:
1797 pcIcon
= patchcanvas
.ICON_DISTRHO
1798 elif clientIcon
== PATCHBAY_ICON_FILE
:
1799 pcIcon
= patchcanvas
.ICON_FILE
1801 patchcanvas
.addGroup(clientId
, clientName
, pcSplit
, pcIcon
)
1803 self
.updateMiniCanvasLater()
1807 if pluginId
>= self
.fPluginCount
and pluginId
!= MAIN_CARLA_PLUGIN_ID
:
1808 print("Error mapping plugin to canvas client:", clientName
)
1811 if pluginId
== MAIN_CARLA_PLUGIN_ID
:
1813 hasInlineDisplay
= False
1815 hints
= self
.host
.get_plugin_info(pluginId
)['hints']
1816 hasCustomUI
= bool(hints
& PLUGIN_HAS_CUSTOM_UI
)
1817 hasInlineDisplay
= bool(hints
& PLUGIN_HAS_INLINE_DISPLAY
)
1819 patchcanvas
.setGroupAsPlugin(clientId
, pluginId
, hasCustomUI
, hasInlineDisplay
)
1822 def slot_handlePatchbayClientRemovedCallback(self
, clientId
):
1823 patchcanvas
.removeGroup(clientId
)
1824 self
.updateMiniCanvasLater()
1827 def slot_handlePatchbayClientRenamedCallback(self
, clientId
, newClientName
):
1828 patchcanvas
.renameGroup(clientId
, newClientName
)
1829 self
.updateMiniCanvasLater()
1831 @pyqtSlot(int, int, int)
1832 def slot_handlePatchbayClientDataChangedCallback(self
, clientId
, clientIcon
, pluginId
):
1833 pcIcon
= patchcanvas
.ICON_APPLICATION
1835 if clientIcon
== PATCHBAY_ICON_PLUGIN
:
1836 pcIcon
= patchcanvas
.ICON_PLUGIN
1837 if clientIcon
== PATCHBAY_ICON_HARDWARE
:
1838 pcIcon
= patchcanvas
.ICON_HARDWARE
1839 elif clientIcon
== PATCHBAY_ICON_CARLA
:
1841 elif clientIcon
== PATCHBAY_ICON_DISTRHO
:
1842 pcIcon
= patchcanvas
.ICON_DISTRHO
1843 elif clientIcon
== PATCHBAY_ICON_FILE
:
1844 pcIcon
= patchcanvas
.ICON_FILE
1846 patchcanvas
.setGroupIcon(clientId
, pcIcon
)
1847 self
.updateMiniCanvasLater()
1851 if pluginId
>= self
.fPluginCount
and pluginId
!= MAIN_CARLA_PLUGIN_ID
:
1852 print("sorry, can't map this plugin to canvas client", pluginId
, self
.fPluginCount
)
1855 if pluginId
== MAIN_CARLA_PLUGIN_ID
:
1857 hasInlineDisplay
= False
1859 hints
= self
.host
.get_plugin_info(pluginId
)['hints']
1860 hasCustomUI
= bool(hints
& PLUGIN_HAS_CUSTOM_UI
)
1861 hasInlineDisplay
= bool(hints
& PLUGIN_HAS_INLINE_DISPLAY
)
1863 patchcanvas
.setGroupAsPlugin(clientId
, pluginId
, hasCustomUI
, hasInlineDisplay
)
1865 @pyqtSlot(int, int, int, int, int)
1866 def slot_handlePatchbayClientPositionChangedCallback(self
, clientId
, x1
, y1
, x2
, y2
):
1867 if (x1
!= 0 and x2
!= 0) or (y1
!= 0 and y2
!= 0):
1868 patchcanvas
.splitGroup(clientId
)
1870 patchcanvas
.joinGroup(clientId
)
1871 patchcanvas
.setGroupPosFull(clientId
, x1
, y1
, x2
, y2
)
1872 self
.updateMiniCanvasLater()
1874 @pyqtSlot(int, int, int, int, str)
1875 def slot_handlePatchbayPortAddedCallback(self
, clientId
, portId
, portFlags
, portGroupId
, portName
):
1876 if portFlags
& PATCHBAY_PORT_IS_INPUT
:
1877 portMode
= patchcanvas
.PORT_MODE_INPUT
1879 portMode
= patchcanvas
.PORT_MODE_OUTPUT
1881 if portFlags
& PATCHBAY_PORT_TYPE_AUDIO
:
1882 portType
= patchcanvas
.PORT_TYPE_AUDIO_JACK
1884 elif portFlags
& PATCHBAY_PORT_TYPE_CV
:
1885 portType
= patchcanvas
.PORT_TYPE_PARAMETER
1887 elif portFlags
& PATCHBAY_PORT_TYPE_MIDI
:
1888 portType
= patchcanvas
.PORT_TYPE_MIDI_JACK
1891 portType
= patchcanvas
.PORT_TYPE_NULL
1894 patchcanvas
.addPort(clientId
, portId
, portName
, portMode
, portType
, isAlternate
)
1895 self
.updateMiniCanvasLater()
1898 def slot_handlePatchbayPortRemovedCallback(self
, groupId
, portId
):
1899 patchcanvas
.removePort(groupId
, portId
)
1900 self
.updateMiniCanvasLater()
1902 @pyqtSlot(int, int, int, int, str)
1903 def slot_handlePatchbayPortChangedCallback(self
, groupId
, portId
, portFlags
, portGroupId
, newPortName
):
1904 patchcanvas
.renamePort(groupId
, portId
, newPortName
)
1905 self
.updateMiniCanvasLater()
1907 @pyqtSlot(int, int, int, str)
1908 def slot_handlePatchbayPortGroupAddedCallback(self
, groupId
, portId
, portGroupId
, newPortName
):
1913 def slot_handlePatchbayPortGroupRemovedCallback(self
, groupId
, portId
):
1917 @pyqtSlot(int, int, int, str)
1918 def slot_handlePatchbayPortGroupChangedCallback(self
, groupId
, portId
, portGroupId
, newPortName
):
1922 @pyqtSlot(int, int, int, int, int)
1923 def slot_handlePatchbayConnectionAddedCallback(self
, connectionId
, groupOutId
, portOutId
, groupInId
, portInId
):
1924 patchcanvas
.connectPorts(connectionId
, groupOutId
, portOutId
, groupInId
, portInId
)
1925 self
.updateMiniCanvasLater()
1927 @pyqtSlot(int, int, int)
1928 def slot_handlePatchbayConnectionRemovedCallback(self
, connectionId
, portOutId
, portInId
):
1929 patchcanvas
.disconnectPorts(connectionId
)
1930 self
.updateMiniCanvasLater()
1932 # --------------------------------------------------------------------------------------------------------
1935 def saveSettings(self
):
1936 settings
= QSafeSettings()
1938 settings
.setValue("Geometry", self
.saveGeometry())
1939 settings
.setValue("ShowToolbar", self
.ui
.toolBar
.isEnabled())
1940 settings
.setValue("ShowSidePanel", self
.ui
.dockWidget
.isEnabled())
1944 for i
in range(self
.ui
.cb_disk
.count()):
1945 diskFolders
.append(self
.ui
.cb_disk
.itemData(i
))
1947 settings
.setValue("DiskFolders", diskFolders
)
1948 settings
.setValue("LastBPM", self
.fLastTransportBPM
)
1950 settings
.setValue("ShowMeters", self
.ui
.act_settings_show_meters
.isChecked())
1951 settings
.setValue("ShowKeyboard", self
.ui
.act_settings_show_keyboard
.isChecked())
1952 settings
.setValue("HorizontalScrollBarValue", self
.ui
.graphicsView
.horizontalScrollBar().value())
1953 settings
.setValue("VerticalScrollBarValue", self
.ui
.graphicsView
.verticalScrollBar().value())
1955 settings
.setValue(CARLA_KEY_ENGINE_TRANSPORT_MODE
, self
.host
.transportMode
)
1956 settings
.setValue(CARLA_KEY_ENGINE_TRANSPORT_EXTRA
, self
.host
.transportExtra
)
1960 def loadSettings(self
, firstTime
):
1961 settings
= QSafeSettings()
1963 if self
.fPluginListDialog
is not None:
1964 gCarla
.felib
.destroyPluginListDialog(self
.fPluginListDialog
)
1965 self
.fPluginListDialog
= None
1968 geometry
= settings
.value("Geometry", QByteArray(), QByteArray
)
1969 if not geometry
.isNull():
1970 self
.restoreGeometry(geometry
)
1972 showToolbar
= settings
.value("ShowToolbar", True, bool)
1973 self
.ui
.act_settings_show_toolbar
.setChecked(showToolbar
)
1974 self
.ui
.toolBar
.blockSignals(True)
1975 self
.ui
.toolBar
.setEnabled(showToolbar
)
1976 self
.ui
.toolBar
.setVisible(showToolbar
)
1977 self
.ui
.toolBar
.blockSignals(False)
1979 #if settings.contains("SplitterState"):
1980 #self.ui.splitter.restoreState(settings.value("SplitterState", b""))
1982 #self.ui.splitter.setSizes([210, 99999])
1984 showSidePanel
= settings
.value("ShowSidePanel", True, bool)
1985 self
.ui
.act_settings_show_side_panel
.setChecked(showSidePanel
)
1986 self
.slot_showSidePanel(showSidePanel
)
1988 diskFolders
= settings
.value("DiskFolders", [HOME
], list)
1990 self
.ui
.cb_disk
.setItemData(0, HOME
)
1992 for i
in range(len(diskFolders
)):
1994 folder
= diskFolders
[i
]
1995 self
.ui
.cb_disk
.addItem(os
.path
.basename(folder
), folder
)
1997 #if MACOS and not settings.value(CARLA_KEY_MAIN_USE_PRO_THEME, True, bool):
1998 # self.setUnifiedTitleAndToolBarOnMac(True)
2000 showMeters
= settings
.value("ShowMeters", True, bool)
2001 self
.ui
.act_settings_show_meters
.setChecked(showMeters
)
2002 self
.ui
.peak_in
.setVisible(showMeters
)
2003 self
.ui
.peak_out
.setVisible(showMeters
)
2005 showKeyboard
= settings
.value("ShowKeyboard", True, bool)
2006 self
.ui
.act_settings_show_keyboard
.setChecked(showKeyboard
)
2007 self
.ui
.scrollArea
.setVisible(showKeyboard
)
2009 settingsDBf
= QSafeSettings("falkTX", "CarlaDatabase2")
2010 self
.fFavoritePlugins
= settingsDBf
.value("PluginDatabase/Favorites", [], list)
2012 QTimer
.singleShot(100, self
.slot_restoreCanvasScrollbarValues
)
2014 # TODO - complete this
2015 oldSettings
= self
.fSavedSettings
2017 if self
.host
.audioDriverForced
is not None:
2018 audioDriver
= self
.host
.audioDriverForced
2020 audioDriver
= settings
.value(CARLA_KEY_ENGINE_AUDIO_DRIVER
, CARLA_DEFAULT_AUDIO_DRIVER
, str)
2022 audioDriverPrefix
= CARLA_KEY_ENGINE_DRIVER_PREFIX
+ audioDriver
2024 self
.fSavedSettings
= {
2025 CARLA_KEY_MAIN_PROJECT_FOLDER
: settings
.value(CARLA_KEY_MAIN_PROJECT_FOLDER
, CARLA_DEFAULT_MAIN_PROJECT_FOLDER
, str),
2026 CARLA_KEY_MAIN_CONFIRM_EXIT
: settings
.value(CARLA_KEY_MAIN_CONFIRM_EXIT
, CARLA_DEFAULT_MAIN_CONFIRM_EXIT
, bool),
2027 CARLA_KEY_MAIN_CLASSIC_SKIN
: settings
.value(CARLA_KEY_MAIN_CLASSIC_SKIN
, CARLA_DEFAULT_MAIN_CLASSIC_SKIN
, bool),
2028 CARLA_KEY_MAIN_REFRESH_INTERVAL
: settings
.value(CARLA_KEY_MAIN_REFRESH_INTERVAL
, CARLA_DEFAULT_MAIN_REFRESH_INTERVAL
, int),
2029 CARLA_KEY_MAIN_SYSTEM_ICONS
: settings
.value(CARLA_KEY_MAIN_SYSTEM_ICONS
, CARLA_DEFAULT_MAIN_SYSTEM_ICONS
, bool),
2030 CARLA_KEY_MAIN_EXPERIMENTAL
: settings
.value(CARLA_KEY_MAIN_EXPERIMENTAL
, CARLA_DEFAULT_MAIN_EXPERIMENTAL
, bool),
2031 CARLA_KEY_CANVAS_THEME
: settings
.value(CARLA_KEY_CANVAS_THEME
, CARLA_DEFAULT_CANVAS_THEME
, str),
2032 CARLA_KEY_CANVAS_SIZE
: settings
.value(CARLA_KEY_CANVAS_SIZE
, CARLA_DEFAULT_CANVAS_SIZE
, str),
2033 CARLA_KEY_CANVAS_AUTO_HIDE_GROUPS
: settings
.value(CARLA_KEY_CANVAS_AUTO_HIDE_GROUPS
, CARLA_DEFAULT_CANVAS_AUTO_HIDE_GROUPS
, bool),
2034 CARLA_KEY_CANVAS_AUTO_SELECT_ITEMS
: settings
.value(CARLA_KEY_CANVAS_AUTO_SELECT_ITEMS
, CARLA_DEFAULT_CANVAS_AUTO_SELECT_ITEMS
, bool),
2035 CARLA_KEY_CANVAS_USE_BEZIER_LINES
: settings
.value(CARLA_KEY_CANVAS_USE_BEZIER_LINES
, CARLA_DEFAULT_CANVAS_USE_BEZIER_LINES
, bool),
2036 CARLA_KEY_CANVAS_EYE_CANDY
: settings
.value(CARLA_KEY_CANVAS_EYE_CANDY
, CARLA_DEFAULT_CANVAS_EYE_CANDY
, bool),
2037 CARLA_KEY_CANVAS_FANCY_EYE_CANDY
: settings
.value(CARLA_KEY_CANVAS_FANCY_EYE_CANDY
, CARLA_DEFAULT_CANVAS_FANCY_EYE_CANDY
, bool),
2038 CARLA_KEY_CANVAS_USE_OPENGL
: settings
.value(CARLA_KEY_CANVAS_USE_OPENGL
, CARLA_DEFAULT_CANVAS_USE_OPENGL
, bool),
2039 CARLA_KEY_CANVAS_ANTIALIASING
: settings
.value(CARLA_KEY_CANVAS_ANTIALIASING
, CARLA_DEFAULT_CANVAS_ANTIALIASING
, int),
2040 CARLA_KEY_CANVAS_HQ_ANTIALIASING
: settings
.value(CARLA_KEY_CANVAS_HQ_ANTIALIASING
, CARLA_DEFAULT_CANVAS_HQ_ANTIALIASING
, bool),
2041 CARLA_KEY_CANVAS_FULL_REPAINTS
: settings
.value(CARLA_KEY_CANVAS_FULL_REPAINTS
, CARLA_DEFAULT_CANVAS_FULL_REPAINTS
, bool),
2042 CARLA_KEY_CUSTOM_PAINTING
: (settings
.value(CARLA_KEY_MAIN_USE_PRO_THEME
, True, bool) and
2043 settings
.value(CARLA_KEY_MAIN_PRO_THEME_COLOR
, "Black", str).lower() == "black"),
2046 CARLA_KEY_ENGINE_AUDIO_DRIVER
: audioDriver
,
2047 CARLA_KEY_ENGINE_AUDIO_DEVICE
: settings
.value(audioDriverPrefix
+"/Device", "", str),
2048 CARLA_KEY_ENGINE_BUFFER_SIZE
: settings
.value(audioDriverPrefix
+"/BufferSize", CARLA_DEFAULT_AUDIO_BUFFER_SIZE
, int),
2049 CARLA_KEY_ENGINE_SAMPLE_RATE
: settings
.value(audioDriverPrefix
+"/SampleRate", CARLA_DEFAULT_AUDIO_SAMPLE_RATE
, int),
2050 CARLA_KEY_ENGINE_TRIPLE_BUFFER
: settings
.value(audioDriverPrefix
+"/TripleBuffer", CARLA_DEFAULT_AUDIO_TRIPLE_BUFFER
, bool),
2053 CARLA_KEY_PATHS_AUDIO
: splitter
.join(settings
.value(CARLA_KEY_PATHS_AUDIO
, CARLA_DEFAULT_FILE_PATH_AUDIO
, list)),
2054 CARLA_KEY_PATHS_MIDI
: splitter
.join(settings
.value(CARLA_KEY_PATHS_MIDI
, CARLA_DEFAULT_FILE_PATH_MIDI
, list)),
2057 CARLA_KEY_PATHS_LADSPA
: splitter
.join(settings
.value(CARLA_KEY_PATHS_LADSPA
, CARLA_DEFAULT_LADSPA_PATH
, list)),
2058 CARLA_KEY_PATHS_DSSI
: splitter
.join(settings
.value(CARLA_KEY_PATHS_DSSI
, CARLA_DEFAULT_DSSI_PATH
, list)),
2059 CARLA_KEY_PATHS_LV2
: splitter
.join(settings
.value(CARLA_KEY_PATHS_LV2
, CARLA_DEFAULT_LV2_PATH
, list)),
2060 CARLA_KEY_PATHS_VST2
: splitter
.join(settings
.value(CARLA_KEY_PATHS_VST2
, CARLA_DEFAULT_VST2_PATH
, list)),
2061 CARLA_KEY_PATHS_VST3
: splitter
.join(settings
.value(CARLA_KEY_PATHS_VST3
, CARLA_DEFAULT_VST3_PATH
, list)),
2062 CARLA_KEY_PATHS_SF2
: splitter
.join(settings
.value(CARLA_KEY_PATHS_SF2
, CARLA_DEFAULT_SF2_PATH
, list)),
2063 CARLA_KEY_PATHS_SFZ
: splitter
.join(settings
.value(CARLA_KEY_PATHS_SFZ
, CARLA_DEFAULT_SFZ_PATH
, list)),
2064 CARLA_KEY_PATHS_JSFX
: splitter
.join(settings
.value(CARLA_KEY_PATHS_JSFX
, CARLA_DEFAULT_JSFX_PATH
, list)),
2065 CARLA_KEY_PATHS_CLAP
: splitter
.join(settings
.value(CARLA_KEY_PATHS_CLAP
, CARLA_DEFAULT_CLAP_PATH
, list)),
2068 CARLA_KEY_OSC_ENABLED
: settings
.value(CARLA_KEY_OSC_ENABLED
, CARLA_DEFAULT_OSC_ENABLED
, bool),
2069 CARLA_KEY_OSC_TCP_PORT_ENABLED
: settings
.value(CARLA_KEY_OSC_TCP_PORT_ENABLED
, CARLA_DEFAULT_OSC_TCP_PORT_ENABLED
, bool),
2070 CARLA_KEY_OSC_TCP_PORT_RANDOM
: settings
.value(CARLA_KEY_OSC_TCP_PORT_RANDOM
, CARLA_DEFAULT_OSC_TCP_PORT_RANDOM
, bool),
2071 CARLA_KEY_OSC_TCP_PORT_NUMBER
: settings
.value(CARLA_KEY_OSC_TCP_PORT_NUMBER
, CARLA_DEFAULT_OSC_TCP_PORT_NUMBER
, int),
2072 CARLA_KEY_OSC_UDP_PORT_ENABLED
: settings
.value(CARLA_KEY_OSC_UDP_PORT_ENABLED
, CARLA_DEFAULT_OSC_UDP_PORT_ENABLED
, bool),
2073 CARLA_KEY_OSC_UDP_PORT_RANDOM
: settings
.value(CARLA_KEY_OSC_UDP_PORT_RANDOM
, CARLA_DEFAULT_OSC_UDP_PORT_RANDOM
, bool),
2074 CARLA_KEY_OSC_UDP_PORT_NUMBER
: settings
.value(CARLA_KEY_OSC_UDP_PORT_NUMBER
, CARLA_DEFAULT_OSC_UDP_PORT_NUMBER
, int),
2077 CARLA_KEY_WINE_EXECUTABLE
: settings
.value(CARLA_KEY_WINE_EXECUTABLE
, CARLA_DEFAULT_WINE_EXECUTABLE
, str),
2078 CARLA_KEY_WINE_AUTO_PREFIX
: settings
.value(CARLA_KEY_WINE_AUTO_PREFIX
, CARLA_DEFAULT_WINE_AUTO_PREFIX
, bool),
2079 CARLA_KEY_WINE_FALLBACK_PREFIX
: settings
.value(CARLA_KEY_WINE_FALLBACK_PREFIX
, CARLA_DEFAULT_WINE_FALLBACK_PREFIX
, str),
2080 CARLA_KEY_WINE_RT_PRIO_ENABLED
: settings
.value(CARLA_KEY_WINE_RT_PRIO_ENABLED
, CARLA_DEFAULT_WINE_RT_PRIO_ENABLED
, bool),
2081 CARLA_KEY_WINE_BASE_RT_PRIO
: settings
.value(CARLA_KEY_WINE_BASE_RT_PRIO
, CARLA_DEFAULT_WINE_BASE_RT_PRIO
, int),
2082 CARLA_KEY_WINE_SERVER_RT_PRIO
: settings
.value(CARLA_KEY_WINE_SERVER_RT_PRIO
, CARLA_DEFAULT_WINE_SERVER_RT_PRIO
, int),
2084 # experimental switches
2085 CARLA_KEY_EXPERIMENTAL_PLUGIN_BRIDGES
:
2086 settings
.value(CARLA_KEY_EXPERIMENTAL_PLUGIN_BRIDGES
, CARLA_DEFAULT_EXPERIMENTAL_PLUGIN_BRIDGES
, bool),
2087 CARLA_KEY_EXPERIMENTAL_WINE_BRIDGES
:
2088 settings
.value(CARLA_KEY_EXPERIMENTAL_WINE_BRIDGES
, CARLA_DEFAULT_EXPERIMENTAL_WINE_BRIDGES
, bool),
2091 if not self
.host
.isControl
:
2092 self
.fSavedSettings
[CARLA_KEY_CANVAS_INLINE_DISPLAYS
] = settings
.value(CARLA_KEY_CANVAS_INLINE_DISPLAYS
, CARLA_DEFAULT_CANVAS_INLINE_DISPLAYS
, bool)
2094 self
.fSavedSettings
[CARLA_KEY_CANVAS_INLINE_DISPLAYS
] = False
2096 settings2
= QSafeSettings("falkTX", "Carla2")
2098 if self
.host
.experimental
:
2099 visible
= settings2
.value(CARLA_KEY_EXPERIMENTAL_JACK_APPS
, CARLA_DEFAULT_EXPERIMENTAL_JACK_APPS
, bool)
2100 self
.ui
.act_plugin_add_jack
.setVisible(visible
)
2102 self
.ui
.act_plugin_add_jack
.setVisible(False)
2104 self
.fMiniCanvasUpdateTimeout
= 1000 if self
.fSavedSettings
[CARLA_KEY_CANVAS_FANCY_EYE_CANDY
] else 0
2106 setEngineSettings(self
.host
, self
.fSavedSettings
)
2107 self
.restartTimersIfNeeded()
2109 if oldSettings
.get(CARLA_KEY_MAIN_CLASSIC_SKIN
, None) not in (self
.fSavedSettings
[CARLA_KEY_MAIN_CLASSIC_SKIN
], None):
2110 newSkin
= "classic" if self
.fSavedSettings
[CARLA_KEY_MAIN_CLASSIC_SKIN
] else None
2112 for pitem
in self
.fPluginList
:
2115 pitem
.recreateWidget(newSkin
= newSkin
)
2119 # --------------------------------------------------------------------------------------------------------
2120 # Settings (helpers)
2122 def enableTransport(self
, enabled
):
2123 self
.ui
.group_transport_controls
.setEnabled(enabled
)
2124 self
.ui
.group_transport_settings
.setEnabled(enabled
)
2127 def slot_restoreCanvasScrollbarValues(self
):
2128 settings
= QSafeSettings()
2129 horiz
= settings
.value("HorizontalScrollBarValue", int(self
.ui
.graphicsView
.horizontalScrollBar().maximum()/2), int)
2130 vertc
= settings
.value("VerticalScrollBarValue", int(self
.ui
.graphicsView
.verticalScrollBar().maximum()/2), int)
2131 self
.ui
.graphicsView
.horizontalScrollBar().setValue(horiz
)
2132 self
.ui
.graphicsView
.verticalScrollBar().setValue(vertc
)
2134 # --------------------------------------------------------------------------------------------------------
2135 # Settings (menu actions)
2138 def slot_showSidePanel(self
, yesNo
):
2139 self
.ui
.dockWidget
.setEnabled(yesNo
)
2140 self
.ui
.dockWidget
.setVisible(yesNo
)
2143 def slot_showToolbar(self
, yesNo
):
2144 self
.ui
.toolBar
.blockSignals(True)
2145 self
.ui
.toolBar
.setEnabled(yesNo
)
2146 self
.ui
.toolBar
.setVisible(yesNo
)
2147 self
.ui
.toolBar
.blockSignals(False)
2150 def slot_showCanvasMeters(self
, yesNo
):
2151 self
.ui
.peak_in
.setVisible(yesNo
)
2152 self
.ui
.peak_out
.setVisible(yesNo
)
2153 QTimer
.singleShot(0, self
.slot_miniCanvasCheckAll
)
2156 def slot_showCanvasKeyboard(self
, yesNo
):
2157 self
.ui
.scrollArea
.setVisible(yesNo
)
2158 QTimer
.singleShot(0, self
.slot_miniCanvasCheckAll
)
2161 def slot_configureCarla(self
):
2162 dialog
= CarlaSettingsW(self
.fParentOrSelf
, self
.host
, True, hasGL
)
2163 if not dialog
.exec_():
2166 self
.loadSettings(False)
2168 if self
.fWithCanvas
:
2171 self
.slot_miniCanvasCheckAll()
2173 if self
.host
.processMode
== ENGINE_PROCESS_MODE_CONTINUOUS_RACK
and self
.host
.isPlugin
:
2175 elif self
.host
.is_engine_running():
2176 self
.host
.patchbay_refresh(self
.fExternalPatchbay
)
2178 # --------------------------------------------------------------------------------------------------------
2179 # About (menu actions)
2182 def slot_aboutCarla(self
):
2183 CarlaAboutW(self
.fParentOrSelf
, self
.host
).exec_()
2186 def slot_aboutJuce(self
):
2187 gCarla
.felib
.createAndExecAboutJuceDialog(self
.fParentOrSelf
)
2190 def slot_aboutQt(self
):
2191 QApplication
.instance().aboutQt()
2193 # --------------------------------------------------------------------------------------------------------
2194 # Disk (menu actions)
2197 def slot_diskFolderChanged(self
, index
):
2202 self
.ui
.b_disk_remove
.setEnabled(False)
2204 filename
= self
.ui
.cb_disk
.itemData(index
)
2205 self
.ui
.b_disk_remove
.setEnabled(True)
2207 self
.fDirModel
.setRootPath(filename
)
2208 self
.ui
.fileTreeView
.setRootIndex(self
.fDirModel
.index(filename
))
2211 def slot_diskFolderAdd(self
):
2212 newPath
= QFileDialog
.getExistingDirectory(self
, self
.tr("New Folder"), "", QFileDialog
.ShowDirsOnly
)
2215 if newPath
[-1] == os
.sep
:
2216 newPath
= newPath
[:-1]
2217 self
.ui
.cb_disk
.addItem(os
.path
.basename(newPath
), newPath
)
2218 self
.ui
.cb_disk
.setCurrentIndex(self
.ui
.cb_disk
.count()-1)
2219 self
.ui
.b_disk_remove
.setEnabled(True)
2222 def slot_diskFolderRemove(self
):
2223 index
= self
.ui
.cb_disk
.currentIndex()
2228 self
.ui
.cb_disk
.removeItem(index
)
2230 if self
.ui
.cb_disk
.currentIndex() == 0:
2231 self
.ui
.b_disk_remove
.setEnabled(False)
2233 @pyqtSlot(QModelIndex
)
2234 def slot_fileTreeDoubleClicked(self
, modelIndex
):
2235 filename
= self
.fDirModel
.filePath(modelIndex
)
2237 if not self
.ui
.listWidget
.isDragUrlValid(filename
):
2240 if not self
.host
.load_file(filename
):
2241 CustomMessageBox(self
, QMessageBox
.Critical
, self
.tr("Error"),
2242 self
.tr("Failed to load file"),
2243 self
.host
.get_last_error(), QMessageBox
.Ok
, QMessageBox
.Ok
)
2246 if filename
.endswith(".carxp"):
2247 self
.loadExternalCanvasGroupPositionsIfNeeded(filename
)
2249 # --------------------------------------------------------------------------------------------------------
2252 def refreshTransport(self
, forced
= False):
2253 if not self
.ui
.l_transport_time
.isVisible():
2255 if self
.fSampleRate
== 0.0 or not self
.host
.is_engine_running():
2258 timeInfo
= self
.host
.get_transport_info()
2259 playing
= timeInfo
['playing']
2260 frame
= timeInfo
['frame']
2261 bpm
= timeInfo
['bpm']
2263 if playing
!= self
.fLastTransportState
or forced
:
2265 if self
.fSavedSettings
[CARLA_KEY_MAIN_SYSTEM_ICONS
]:
2266 icon
= getIcon('media-playback-pause', 16, 'svgz')
2268 icon
= QIcon(":/16x16/media-playback-pause.svgz")
2269 self
.ui
.b_transport_play
.setChecked(True)
2270 self
.ui
.b_transport_play
.setIcon(icon
)
2271 #self.ui.b_transport_play.setText(self.tr("&Pause"))
2273 if self
.fSavedSettings
[CARLA_KEY_MAIN_SYSTEM_ICONS
]:
2274 icon
= getIcon('media-playback-start', 16, 'svgz')
2276 icon
= QIcon(":/16x16/media-playback-start.svgz")
2277 self
.ui
.b_transport_play
.setChecked(False)
2278 self
.ui
.b_transport_play
.setIcon(icon
)
2279 #self.ui.b_play.setText(self.tr("&Play"))
2281 self
.fLastTransportState
= playing
2283 if frame
!= self
.fLastTransportFrame
or forced
:
2284 self
.fLastTransportFrame
= frame
2286 time
= frame
/ self
.fSampleRate
2288 mins
= (time
/ 60) % 60
2289 hrs
= (time
/ 3600) % 60
2290 self
.ui
.l_transport_time
.setText("%02i:%02i:%02i" % (hrs
, mins
, secs
))
2292 frame1
= frame
% 1000
2293 frame2
= (frame
/ 1000) % 1000
2294 frame3
= (frame
/ 1000000) % 1000
2295 self
.ui
.l_transport_frame
.setText("%03i'%03i'%03i" % (frame3
, frame2
, frame1
))
2297 bar
= timeInfo
['bar']
2298 beat
= timeInfo
['beat']
2299 tick
= timeInfo
['tick']
2300 self
.ui
.l_transport_bbt
.setText("%03i|%02i|%04i" % (bar
, beat
, tick
))
2302 if bpm
!= self
.fLastTransportBPM
or forced
:
2303 self
.fLastTransportBPM
= bpm
2306 self
.ui
.dsb_transport_bpm
.blockSignals(True)
2307 self
.ui
.dsb_transport_bpm
.setValue(bpm
)
2308 self
.ui
.dsb_transport_bpm
.blockSignals(False)
2309 self
.ui
.dsb_transport_bpm
.setStyleSheet("")
2311 self
.ui
.dsb_transport_bpm
.setStyleSheet("QDoubleSpinBox { color: palette(mid); }")
2313 # --------------------------------------------------------------------------------------------------------
2314 # Transport (menu actions)
2317 def slot_transportPlayPause(self
, toggled
):
2318 if self
.host
.isPlugin
or not self
.host
.is_engine_running():
2322 self
.host
.transport_play()
2324 self
.host
.transport_pause()
2326 self
.refreshTransport()
2329 def slot_transportStop(self
):
2330 if self
.host
.isPlugin
or not self
.host
.is_engine_running():
2333 self
.host
.transport_pause()
2334 self
.host
.transport_relocate(0)
2336 self
.refreshTransport()
2339 def slot_transportBackwards(self
):
2340 if self
.host
.isPlugin
or not self
.host
.is_engine_running():
2343 newFrame
= self
.host
.get_current_transport_frame() - 100000
2348 self
.host
.transport_relocate(newFrame
)
2351 def slot_transportBpmChanged(self
, newValue
):
2352 self
.host
.transport_bpm(newValue
)
2355 def slot_transportForwards(self
):
2356 if self
.fSampleRate
== 0.0 or self
.host
.isPlugin
or not self
.host
.is_engine_running():
2359 newFrame
= self
.host
.get_current_transport_frame() + int(self
.fSampleRate
*2.5)
2360 self
.host
.transport_relocate(newFrame
)
2363 def slot_transportJackEnabled(self
, clicked
):
2364 if not self
.host
.is_engine_running():
2366 self
.host
.transportMode
= ENGINE_TRANSPORT_MODE_JACK
if clicked
else ENGINE_TRANSPORT_MODE_INTERNAL
2367 self
.host
.set_engine_option(ENGINE_OPTION_TRANSPORT_MODE
,
2368 self
.host
.transportMode
,
2369 self
.host
.transportExtra
)
2372 def slot_transportLinkEnabled(self
, clicked
):
2373 if not self
.host
.is_engine_running():
2375 extra
= ":link:" if clicked
else ""
2376 self
.host
.transportExtra
= extra
2377 self
.host
.set_engine_option(ENGINE_OPTION_TRANSPORT_MODE
,
2378 self
.host
.transportMode
,
2379 self
.host
.transportExtra
)
2381 # --------------------------------------------------------------------------------------------------------
2385 def slot_xrunClear(self
):
2386 self
.host
.clear_engine_xruns()
2388 # --------------------------------------------------------------------------------------------------------
2392 def slot_horizontalScrollBarChanged(self
, value
):
2393 maximum
= self
.ui
.graphicsView
.horizontalScrollBar().maximum()
2397 xp
= float(value
) / maximum
2398 self
.ui
.miniCanvasPreview
.setViewPosX(xp
)
2399 self
.updateCanvasInitialPos()
2402 def slot_verticalScrollBarChanged(self
, value
):
2403 maximum
= self
.ui
.graphicsView
.verticalScrollBar().maximum()
2407 yp
= float(value
) / maximum
2408 self
.ui
.miniCanvasPreview
.setViewPosY(yp
)
2409 self
.updateCanvasInitialPos()
2411 # --------------------------------------------------------------------------------------------------------
2415 def slot_noteOn(self
, note
):
2416 if self
.fPluginCount
== 0:
2419 for pluginId
in self
.fSelectedPlugins
:
2420 self
.host
.send_midi_note(pluginId
, 0, note
, 100)
2422 pedit
= self
.getPluginEditDialog(pluginId
)
2423 pedit
.noteOn(0, note
, 100)
2426 def slot_noteOff(self
, note
):
2427 if self
.fPluginCount
== 0:
2430 for pluginId
in self
.fSelectedPlugins
:
2431 self
.host
.send_midi_note(pluginId
, 0, note
, 0)
2433 pedit
= self
.getPluginEditDialog(pluginId
)
2434 pedit
.noteOff(0, note
)
2436 # --------------------------------------------------------------------------------------------------------
2437 # Canvas keyboard (host callbacks)
2439 @pyqtSlot(int, int, int, int)
2440 def slot_handleNoteOnCallback(self
, pluginId
, channel
, note
, velocity
):
2441 if pluginId
in self
.fSelectedPlugins
:
2442 self
.ui
.keyboard
.sendNoteOn(note
, False)
2444 @pyqtSlot(int, int, int)
2445 def slot_handleNoteOffCallback(self
, pluginId
, channel
, note
):
2446 if pluginId
in self
.fSelectedPlugins
:
2447 self
.ui
.keyboard
.sendNoteOff(note
, False)
2449 # --------------------------------------------------------------------------------------------------------
2452 def slot_handleUpdateCallback(self
, pluginId
):
2453 pitem
= self
.getPluginItem(pluginId
)
2458 wasCompacted
= pitem
.isCompacted()
2459 isCompacted
= wasCompacted
2461 check
= self
.host
.get_custom_data_value(pluginId
, CUSTOM_DATA_TYPE_PROPERTY
, "CarlaSkinIsCompacted")
2464 isCompacted
= bool(check
== "true")
2466 if wasCompacted
== isCompacted
:
2469 pitem
.recreateWidget(True)
2471 # --------------------------------------------------------------------------------------------------------
2475 def slot_miniCanvasCheckAll(self
):
2476 self
.slot_miniCanvasCheckSize()
2477 self
.slot_horizontalScrollBarChanged(self
.ui
.graphicsView
.horizontalScrollBar().value())
2478 self
.slot_verticalScrollBarChanged(self
.ui
.graphicsView
.verticalScrollBar().value())
2481 def slot_miniCanvasCheckSize(self
):
2482 if self
.fCanvasWidth
== 0 or self
.fCanvasHeight
== 0:
2485 currentIndex
= self
.ui
.tabWidget
.currentIndex()
2487 if currentIndex
== 1:
2488 width
= self
.ui
.graphicsView
.width()
2489 height
= self
.ui
.graphicsView
.height()
2491 self
.ui
.tabWidget
.blockSignals(True)
2492 self
.ui
.tabWidget
.setCurrentIndex(1)
2493 width
= self
.ui
.graphicsView
.width()
2494 height
= self
.ui
.graphicsView
.height()
2495 self
.ui
.tabWidget
.setCurrentIndex(currentIndex
)
2496 self
.ui
.tabWidget
.blockSignals(False)
2498 self
.scene
.updateLimits()
2500 self
.ui
.miniCanvasPreview
.setViewSize(float(width
)/self
.fCanvasWidth
, float(height
)/self
.fCanvasHeight
)
2502 @pyqtSlot(float, float)
2503 def slot_miniCanvasMoved(self
, xp
, yp
):
2504 hsb
= self
.ui
.graphicsView
.horizontalScrollBar()
2505 vsb
= self
.ui
.graphicsView
.verticalScrollBar()
2506 hsb
.setValue(xp
* hsb
.maximum())
2507 vsb
.setValue(yp
* vsb
.maximum())
2508 self
.updateCanvasInitialPos()
2510 # --------------------------------------------------------------------------------------------------------
2511 # Logs autoscroll, save and clear
2514 def slot_toggleLogAutoscroll(self
, checkState
):
2515 self
.autoscrollOnNewLog
= checkState
== Qt
.Checked
2516 if self
.autoscrollOnNewLog
:
2517 self
.ui
.text_logs
.verticalScrollBar().setValue(self
.ui
.text_logs
.verticalScrollBar().maximum())
2520 def slot_logSliderMoved(self
, slider_pos
):
2521 if self
.ui
.text_logs
.verticalScrollBar().hasTracking() or self
.autoscrollOnNewLog
:
2522 self
.lastLogSliderPos
= slider_pos
2524 self
.ui
.text_logs
.verticalScrollBar().setValue(self
.lastLogSliderPos
)
2527 def slot_logButtonsState(self
, enabled
=True):
2528 self
.ui
.logs_clear
.setEnabled(enabled
)
2529 self
.ui
.logs_save
.setEnabled(enabled
)
2532 def slot_logSave(self
):
2533 filename
= os
.path
.join(self
.fSavedSettings
[CARLA_KEY_MAIN_PROJECT_FOLDER
], 'carla_log.txt')
2534 filename
, _
= QFileDialog
.getSaveFileName(self
, self
.tr("Save Logs"), filename
)
2540 with
open(filename
, "w") as logfile
:
2541 logfile
.write(self
.ui
.text_logs
.toPlainText())
2547 def slot_logClear(self
):
2548 self
.ui
.text_logs
.clear()
2549 self
.ui
.text_logs
.appendPlainText("======= Logs cleared ========")
2550 self
.slot_logButtonsState(False)
2552 # --------------------------------------------------------------------------------------------------------
2555 def startTimers(self
):
2556 if self
.fIdleTimerFast
== 0:
2557 self
.fIdleTimerFast
= self
.startTimer(self
.fSavedSettings
[CARLA_KEY_MAIN_REFRESH_INTERVAL
])
2559 if self
.fIdleTimerSlow
== 0:
2560 self
.fIdleTimerSlow
= self
.startTimer(self
.fSavedSettings
[CARLA_KEY_MAIN_REFRESH_INTERVAL
]*4)
2562 def restartTimersIfNeeded(self
):
2563 if self
.fIdleTimerFast
!= 0:
2564 self
.killTimer(self
.fIdleTimerFast
)
2565 self
.fIdleTimerFast
= self
.startTimer(self
.fSavedSettings
[CARLA_KEY_MAIN_REFRESH_INTERVAL
])
2567 if self
.fIdleTimerSlow
!= 0:
2568 self
.killTimer(self
.fIdleTimerSlow
)
2569 self
.fIdleTimerSlow
= self
.startTimer(self
.fSavedSettings
[CARLA_KEY_MAIN_REFRESH_INTERVAL
]*4)
2571 def killTimers(self
):
2572 if self
.fIdleTimerFast
!= 0:
2573 self
.killTimer(self
.fIdleTimerFast
)
2574 self
.fIdleTimerFast
= 0
2576 if self
.fIdleTimerSlow
!= 0:
2577 self
.killTimer(self
.fIdleTimerSlow
)
2578 self
.fIdleTimerSlow
= 0
2580 # --------------------------------------------------------------------------------------------------------
2584 def slot_toolbarVisibilityChanged(self
, visible
):
2585 self
.ui
.toolBar
.blockSignals(True)
2586 self
.ui
.toolBar
.setEnabled(visible
)
2587 self
.ui
.toolBar
.blockSignals(False)
2588 self
.ui
.act_settings_show_toolbar
.setChecked(visible
)
2591 def slot_tabChanged(self
, index
):
2595 self
.ui
.graphicsView
.setFocus()
2598 def slot_handleReloadAllCallback(self
, pluginId
):
2599 if pluginId
>= self
.fPluginCount
:
2602 pitem
= self
.fPluginList
[pluginId
]
2606 pitem
.recreateWidget()
2608 # --------------------------------------------------------------------------------------------------------
2610 @pyqtSlot(int, int, str)
2611 def slot_handleNSMCallback(self
, opcode
, valueInt
, valueStr
):
2612 if opcode
== NSM_CALLBACK_INIT
:
2616 elif opcode
== NSM_CALLBACK_ERROR
:
2620 elif opcode
== NSM_CALLBACK_ANNOUNCE
:
2621 self
.fFirstEngineInit
= False
2622 self
.fSessionManagerName
= valueStr
2623 self
.setProperWindowTitle()
2625 # If NSM server does not support optional-gui, revert our initial assumptions that it does
2626 if (valueInt
& (1 << 1)) == 0x0:
2627 self
.fWindowCloseHideGui
= False
2628 self
.ui
.act_file_quit
.setText(self
.tr("&Quit"))
2629 QApplication
.instance().setQuitOnLastWindowClosed(True)
2633 elif opcode
== NSM_CALLBACK_OPEN
:
2634 self
.fProjectFilename
= QFileInfo(valueStr
+".carxp").absoluteFilePath()
2635 self
.setProperWindowTitle()
2637 self
.fCustomStopAction
= self
.CUSTOM_ACTION_PROJECT_LOAD
2638 self
.slot_engineStop(True)
2642 elif opcode
== NSM_CALLBACK_SAVE
:
2643 self
.saveProjectNow()
2646 elif opcode
== NSM_CALLBACK_SESSION_IS_LOADED
:
2650 elif opcode
== NSM_CALLBACK_SHOW_OPTIONAL_GUI
:
2654 elif opcode
== NSM_CALLBACK_HIDE_OPTIONAL_GUI
:
2658 elif opcode
== NSM_CALLBACK_SET_CLIENT_NAME_ID
:
2659 self
.fClientName
= valueStr
2662 self
.host
.nsm_ready(opcode
)
2664 # --------------------------------------------------------------------------------------------------------
2666 def fixLogText(self
, text
):
2667 return text
.replace("\x1b[30;1m", "").replace("\x1b[31m", "").replace("\x1b[0m", "")
2669 @pyqtSlot(int, int, int, int, float, str)
2670 def slot_handleDebugCallback(self
, pluginId
, value1
, value2
, value3
, valuef
, valueStr
):
2671 self
.ui
.text_logs
.appendPlainText(self
.fixLogText(valueStr
))
2674 def slot_handleInfoCallback(self
, info
):
2675 QMessageBox
.information(self
, "Information", info
)
2678 def slot_handleErrorCallback(self
, error
):
2679 QMessageBox
.critical(self
, "Error", error
)
2682 def slot_handleQuitCallback(self
):
2683 self
.fIsProjectLoading
= False
2685 self
.removeAllPlugins()
2686 self
.projectLoadingFinished(False)
2689 def slot_handleInlineDisplayRedrawCallback(self
, pluginId
):
2691 if self
.fIdleTimerSlow
!= 0 and self
.fIdleTimerFast
!= 0 and pluginId
< self
.fPluginCount
and not self
.fIsProjectLoading
:
2692 patchcanvas
.redrawPluginGroup(pluginId
)
2694 # --------------------------------------------------------------------------------------------------------
2697 def slot_handleSIGUSR1(self
):
2698 print("Got SIGUSR1 -> Saving project now")
2699 self
.slot_fileSave()
2702 def slot_handleSIGTERM(self
):
2703 print("Got SIGTERM -> Closing now")
2704 self
.fCustomStopAction
= self
.CUSTOM_ACTION_APP_CLOSE
2707 # --------------------------------------------------------------------------------------------------------
2710 def getExtraPtr(self
, plugin
):
2711 ptype
= plugin
['type']
2713 if ptype
== PLUGIN_LADSPA
:
2714 uniqueId
= plugin
['uniqueId']
2716 self
.maybeLoadRDFs()
2718 for rdfItem
in self
.fLadspaRdfList
:
2719 if rdfItem
.UniqueID
== uniqueId
:
2720 return pointer(rdfItem
)
2722 elif ptype
== PLUGIN_SF2
:
2723 if plugin
['name'].lower().endswith(" (16 outputs)"):
2728 def maybeLoadRDFs(self
):
2729 if not self
.fLadspaRdfNeedsUpdate
:
2732 self
.fLadspaRdfNeedsUpdate
= False
2733 self
.fLadspaRdfList
= []
2738 settingsDir
= os
.path
.join(HOME
, ".config", "falkTX")
2739 frLadspaFile
= os
.path
.join(settingsDir
, "ladspa_rdf.db")
2741 if os
.path
.exists(frLadspaFile
):
2742 frLadspa
= open(frLadspaFile
, 'r')
2745 self
.fLadspaRdfList
= ladspa_rdf
.get_c_ladspa_rdfs(json
.load(frLadspa
))
2751 # --------------------------------------------------------------------------------------------------------
2753 def getPluginCount(self
):
2754 return self
.fPluginCount
2756 def getPluginItem(self
, pluginId
):
2757 if pluginId
>= self
.fPluginCount
:
2760 pitem
= self
.fPluginList
[pluginId
]
2764 #return CarlaRackItem(self, 0, False)
2768 def getPluginEditDialog(self
, pluginId
):
2769 if pluginId
>= self
.fPluginCount
:
2772 pitem
= self
.fPluginList
[pluginId
]
2776 return PluginEdit(self
, self
.host
, 0)
2778 return pitem
.getEditDialog()
2780 def getPluginSlotWidget(self
, pluginId
):
2781 if pluginId
>= self
.fPluginCount
:
2784 pitem
= self
.fPluginList
[pluginId
]
2788 #return AbstractPluginSlot()
2790 return pitem
.getWidget()
2792 # --------------------------------------------------------------------------------------------------------
2794 def waitForPendingEvents(self
):
2797 # --------------------------------------------------------------------------------------------------------
2800 def showEvent(self
, event
):
2801 self
.getAndRefreshRuntimeInfo()
2802 self
.refreshTransport(True)
2803 QMainWindow
.showEvent(self
, event
)
2805 if QT_VERSION
>= 0x50600:
2806 self
.host
.set_engine_option(ENGINE_OPTION_FRONTEND_UI_SCALE
, int(self
.devicePixelRatioF() * 1000), "")
2807 print("Frontend pixel ratio is", self
.devicePixelRatioF())
2809 # set our gui as parent for all plugins UIs
2810 if self
.host
.manageUIs
and not self
.host
.isControl
:
2812 nsViewPtr
= int(self
.winId())
2813 winIdStr
= "%x" % gCarla
.utils
.cocoa_get_window(nsViewPtr
)
2815 winIdStr
= "%x" % int(self
.winId())
2816 self
.host
.set_engine_option(ENGINE_OPTION_FRONTEND_WIN_ID
, 0, winIdStr
)
2818 def hideEvent(self
, event
):
2820 if not self
.host
.isControl
:
2821 self
.host
.set_engine_option(ENGINE_OPTION_FRONTEND_WIN_ID
, 0, "0")
2823 QMainWindow
.hideEvent(self
, event
)
2825 # --------------------------------------------------------------------------------------------------------
2828 def resizeEvent(self
, event
):
2829 QMainWindow
.resizeEvent(self
, event
)
2831 if self
.fWithCanvas
:
2832 self
.slot_miniCanvasCheckSize()
2834 # --------------------------------------------------------------------------------------------------------
2837 def refreshRuntimeInfo(self
, load
, xruns
):
2838 txt1
= str(xruns
) if (xruns
>= 0) else "--"
2839 txt2
= "" if (xruns
== 1) else "s"
2840 self
.ui
.b_xruns
.setText("%s Xrun%s" % (txt1
, txt2
))
2841 self
.ui
.pb_dsp_load
.setValue(int(load
))
2843 def getAndRefreshRuntimeInfo(self
):
2844 if not self
.ui
.pb_dsp_load
.isVisible():
2846 if not self
.host
.is_engine_running():
2848 info
= self
.host
.get_runtime_engine_info()
2849 self
.refreshRuntimeInfo(info
['load'], info
['xruns'])
2852 self
.host
.engine_idle()
2853 self
.refreshTransport()
2855 if self
.fPluginCount
== 0 or self
.fCurrentlyRemovingAllPlugins
:
2858 for pitem
in self
.fPluginList
:
2862 pitem
.getWidget().idleFast()
2864 for pluginId
in self
.fSelectedPlugins
:
2865 self
.fPeaksCleared
= False
2866 if self
.ui
.peak_in
.isVisible():
2867 self
.ui
.peak_in
.displayMeter(1, self
.host
.get_input_peak_value(pluginId
, True))
2868 self
.ui
.peak_in
.displayMeter(2, self
.host
.get_input_peak_value(pluginId
, False))
2869 if self
.ui
.peak_out
.isVisible():
2870 self
.ui
.peak_out
.displayMeter(1, self
.host
.get_output_peak_value(pluginId
, True))
2871 self
.ui
.peak_out
.displayMeter(2, self
.host
.get_output_peak_value(pluginId
, False))
2874 if self
.fPeaksCleared
:
2877 self
.fPeaksCleared
= True
2878 self
.ui
.peak_in
.displayMeter(1, 0.0, True)
2879 self
.ui
.peak_in
.displayMeter(2, 0.0, True)
2880 self
.ui
.peak_out
.displayMeter(1, 0.0, True)
2881 self
.ui
.peak_out
.displayMeter(2, 0.0, True)
2884 self
.getAndRefreshRuntimeInfo()
2886 if self
.fPluginCount
== 0 or self
.fCurrentlyRemovingAllPlugins
:
2889 for pitem
in self
.fPluginList
:
2893 pitem
.getWidget().idleSlow()
2895 def timerEvent(self
, event
):
2896 if event
.timerId() == self
.fIdleTimerFast
:
2899 elif event
.timerId() == self
.fIdleTimerSlow
:
2902 QMainWindow
.timerEvent(self
, event
)
2904 # --------------------------------------------------------------------------------------------------------
2905 # color/style change event
2907 def changeEvent(self
, event
):
2908 if event
.type() in (QEvent
.PaletteChange
, QEvent
.StyleChange
):
2910 QMainWindow
.changeEvent(self
, event
)
2912 def updateStyle(self
):
2913 # Rack padding images setup
2914 rack_imgL
= QImage(":/bitmaps/rack_padding_left.png")
2915 rack_imgR
= QImage(":/bitmaps/rack_padding_right.png")
2919 if PYQT_VERSION
>= 0x50600:
2920 value_fix
= 1.0/(1.0-rack_imgL
.scaled(1, 1, Qt
.IgnoreAspectRatio
, Qt
.SmoothTransformation
).pixelColor(0,0).blackF())
2924 rack_pal
= self
.ui
.rack
.palette()
2925 bg_color
= rack_pal
.window().color()
2926 fg_color
= rack_pal
.text().color()
2927 bg_value
= 1.0 - bg_color
.blackF()
2928 if bg_value
!= 0.0 and bg_value
< min_value
:
2929 pad_color
= bg_color
.lighter(int(100*min_value
/bg_value
*value_fix
))
2931 pad_color
= QColor
.fromHsvF(0.0, 0.0, min_value
*value_fix
)
2933 painter
= QPainter()
2934 fillRect
= rack_imgL
.rect().adjusted(-1,-1,1,1)
2936 painter
.begin(rack_imgL
)
2937 painter
.setCompositionMode(QPainter
.CompositionMode_Multiply
)
2938 painter
.setBrush(pad_color
)
2939 painter
.drawRect(fillRect
)
2941 rack_pixmapL
= QPixmap(rack_imgL
)
2942 self
.imgL_palette
= QPalette()
2943 self
.imgL_palette
.setBrush(QPalette
.Window
, QBrush(rack_pixmapL
))
2944 self
.ui
.pad_left
.setPalette(self
.imgL_palette
)
2945 self
.ui
.pad_left
.setAutoFillBackground(True)
2947 painter
.begin(rack_imgR
)
2948 painter
.setCompositionMode(QPainter
.CompositionMode_Multiply
)
2949 painter
.setBrush(pad_color
)
2950 painter
.drawRect(fillRect
)
2952 rack_pixmapR
= QPixmap(rack_imgR
)
2953 self
.imgR_palette
= QPalette()
2954 self
.imgR_palette
.setBrush(QPalette
.Window
, QBrush(rack_pixmapR
))
2955 self
.ui
.pad_right
.setPalette(self
.imgR_palette
)
2956 self
.ui
.pad_right
.setAutoFillBackground(True)
2958 # qt's rgba is actually argb, so convert that
2959 bg_color_value
= bg_color
.rgba()
2960 bg_color_value
= ((bg_color_value
& 0xffffff) << 8) |
(bg_color_value
>> 24)
2962 fg_color_value
= fg_color
.rgba()
2963 fg_color_value
= ((fg_color_value
& 0xffffff) << 8) |
(fg_color_value
>> 24)
2965 self
.host
.set_engine_option(ENGINE_OPTION_FRONTEND_BACKGROUND_COLOR
, bg_color_value
, "")
2966 self
.host
.set_engine_option(ENGINE_OPTION_FRONTEND_FOREGROUND_COLOR
, fg_color_value
, "")
2968 # --------------------------------------------------------------------------------------------------------
2971 #def paintEvent(self, event):
2972 #QMainWindow.paintEvent(self, event)
2974 #if MACOS or not self.fSavedSettings[CARLA_KEY_CUSTOM_PAINTING]:
2977 #painter = QPainter(self)
2978 #painter.setBrush(QColor(36, 36, 36))
2979 #painter.setPen(QColor(62, 62, 62))
2980 #painter.drawRect(1, self.height()/2, self.width()-3, self.height()-self.height()/2-1)
2982 # --------------------------------------------------------------------------------------------------------
2985 def shouldIgnoreClose(self
):
2986 if self
.host
.isControl
or self
.host
.isPlugin
:
2988 if self
.fCustomStopAction
== self
.CUSTOM_ACTION_APP_CLOSE
:
2990 if self
.fWindowCloseHideGui
:
2992 if self
.fSavedSettings
[CARLA_KEY_MAIN_CONFIRM_EXIT
]:
2993 return QMessageBox
.question(self
, self
.tr("Quit"),
2994 self
.tr("Are you sure you want to quit Carla?"),
2995 QMessageBox
.Yes|QMessageBox
.No
) == QMessageBox
.No
2998 def closeEvent(self
, event
):
2999 if self
.shouldIgnoreClose():
3003 if self
.fWindowCloseHideGui
and self
.fCustomStopAction
!= self
.CUSTOM_ACTION_APP_CLOSE
:
3005 self
.host
.nsm_ready(NSM_CALLBACK_HIDE_OPTIONAL_GUI
)
3008 patchcanvas
.handleAllPluginsRemoved()
3010 if MACOS
and self
.fMacClosingHelper
and not (self
.host
.isControl
or self
.host
.isPlugin
):
3011 self
.fCustomStopAction
= self
.CUSTOM_ACTION_APP_CLOSE
3012 self
.fMacClosingHelper
= False
3015 for i
in reversed(range(self
.fPluginCount
)):
3016 self
.host
.show_custom_ui(i
, False)
3018 QTimer
.singleShot(100, self
.close
)
3024 if self
.host
.is_engine_running() and not (self
.host
.isControl
or self
.host
.isPlugin
):
3025 if not self
.slot_engineStop(True):
3026 self
.fCustomStopAction
= self
.CUSTOM_ACTION_APP_CLOSE
3030 QMainWindow
.closeEvent(self
, event
)
3032 # if we reach this point, fully close ourselves
3034 QApplication
.instance().quit()
3036 # ------------------------------------------------------------------------------------------------
3039 def canvasCallback(action
, value1
, value2
, valueStr
):
3040 host
= gCarla
.gui
.host
3042 if gCarla
.gui
.fCustomStopAction
== HostWindow
.CUSTOM_ACTION_APP_CLOSE
:
3045 if action
== patchcanvas
.ACTION_GROUP_INFO
:
3048 elif action
== patchcanvas
.ACTION_GROUP_RENAME
:
3051 elif action
== patchcanvas
.ACTION_GROUP_SPLIT
:
3053 patchcanvas
.splitGroup(groupId
)
3054 gCarla
.gui
.updateMiniCanvasLater()
3056 elif action
== patchcanvas
.ACTION_GROUP_JOIN
:
3058 patchcanvas
.joinGroup(groupId
)
3059 gCarla
.gui
.updateMiniCanvasLater()
3061 elif action
== patchcanvas
.ACTION_GROUP_POSITION
:
3062 if gCarla
.gui
.fIsProjectLoading
:
3064 if not host
.is_engine_running():
3067 x1
, y1
, x2
, y2
= tuple(int(i
) for i
in valueStr
.split(":"))
3068 host
.patchbay_set_group_pos(gCarla
.gui
.fExternalPatchbay
, groupId
, x1
, y1
, x2
, y2
)
3069 gCarla
.gui
.updateMiniCanvasLater()
3071 elif action
== patchcanvas
.ACTION_PORT_INFO
:
3074 elif action
== patchcanvas
.ACTION_PORT_RENAME
:
3077 elif action
== patchcanvas
.ACTION_PORTS_CONNECT
:
3078 gOut
, pOut
, gIn
, pIn
= tuple(int(i
) for i
in valueStr
.split(":"))
3080 if not host
.patchbay_connect(gCarla
.gui
.fExternalPatchbay
, gOut
, pOut
, gIn
, pIn
):
3081 print("Connection failed:", host
.get_last_error())
3083 elif action
== patchcanvas
.ACTION_PORTS_DISCONNECT
:
3084 connectionId
= value1
3086 if not host
.patchbay_disconnect(gCarla
.gui
.fExternalPatchbay
, connectionId
):
3087 print("Disconnect failed:", host
.get_last_error())
3089 elif action
== patchcanvas
.ACTION_PLUGIN_CLONE
:
3092 if not host
.clone_plugin(pluginId
):
3093 CustomMessageBox(gCarla
.gui
, QMessageBox
.Warning, gCarla
.gui
.tr("Error"), gCarla
.gui
.tr("Operation failed"),
3094 host
.get_last_error(), QMessageBox
.Ok
, QMessageBox
.Ok
)
3096 elif action
== patchcanvas
.ACTION_PLUGIN_EDIT
:
3098 pwidget
= gCarla
.gui
.getPluginSlotWidget(pluginId
)
3100 if pwidget
is not None:
3101 pwidget
.showEditDialog()
3103 elif action
== patchcanvas
.ACTION_PLUGIN_RENAME
:
3105 pwidget
= gCarla
.gui
.getPluginSlotWidget(pluginId
)
3107 if pwidget
is not None:
3108 pwidget
.showRenameDialog()
3110 elif action
== patchcanvas
.ACTION_PLUGIN_REPLACE
:
3112 pwidget
= gCarla
.gui
.getPluginSlotWidget(pluginId
)
3114 if pwidget
is not None:
3115 pwidget
.showReplaceDialog()
3117 elif action
== patchcanvas
.ACTION_PLUGIN_REMOVE
:
3120 if not host
.remove_plugin(pluginId
):
3121 CustomMessageBox(gCarla
.gui
, QMessageBox
.Warning, gCarla
.gui
.tr("Error"), gCarla
.gui
.tr("Operation failed"),
3122 host
.get_last_error(), QMessageBox
.Ok
, QMessageBox
.Ok
)
3124 elif action
== patchcanvas
.ACTION_PLUGIN_SHOW_UI
:
3126 pwidget
= gCarla
.gui
.getPluginSlotWidget(pluginId
)
3128 if pwidget
is not None:
3129 pwidget
.showCustomUI()
3131 elif action
== patchcanvas
.ACTION_BG_RIGHT_CLICK
:
3132 gCarla
.gui
.slot_showPluginActionsMenu()
3134 elif action
== patchcanvas
.ACTION_INLINE_DISPLAY
:
3135 if gCarla
.gui
.fIsProjectLoading
:
3137 if not host
.is_engine_running():
3140 width
, height
= [int(v
) for v
in valueStr
.split(":")]
3141 return host
.render_inline_display(pluginId
, width
, height
)
3143 # ------------------------------------------------------------------------------------------------------------
3146 def engineCallback(host
, action
, pluginId
, value1
, value2
, value3
, valuef
, valueStr
):
3147 # kdevelop likes this :)
3148 if False: host
= CarlaHostNull()
3150 valueStr
= charPtrToString(valueStr
)
3152 if action
== ENGINE_CALLBACK_ENGINE_STARTED
:
3153 host
.processMode
= value1
3154 host
.transportMode
= value2
3155 elif action
== ENGINE_CALLBACK_PROCESS_MODE_CHANGED
:
3156 host
.processMode
= value1
3157 elif action
== ENGINE_CALLBACK_TRANSPORT_MODE_CHANGED
:
3158 host
.transportMode
= value1
3159 host
.transportExtra
= valueStr
3161 if action
== ENGINE_CALLBACK_DEBUG
:
3162 host
.DebugCallback
.emit(pluginId
, value1
, value2
, value3
, valuef
, valueStr
)
3163 elif action
== ENGINE_CALLBACK_PLUGIN_ADDED
:
3164 host
.PluginAddedCallback
.emit(pluginId
, value1
, valueStr
)
3165 elif action
== ENGINE_CALLBACK_PLUGIN_REMOVED
:
3166 host
.PluginRemovedCallback
.emit(pluginId
)
3167 elif action
== ENGINE_CALLBACK_PLUGIN_RENAMED
:
3168 host
.PluginRenamedCallback
.emit(pluginId
, valueStr
)
3169 elif action
== ENGINE_CALLBACK_PLUGIN_UNAVAILABLE
:
3170 host
.PluginUnavailableCallback
.emit(pluginId
, valueStr
)
3171 elif action
== ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED
:
3172 host
.ParameterValueChangedCallback
.emit(pluginId
, value1
, valuef
)
3173 elif action
== ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED
:
3174 host
.ParameterDefaultChangedCallback
.emit(pluginId
, value1
, valuef
)
3175 elif action
== ENGINE_CALLBACK_PARAMETER_MAPPED_CONTROL_INDEX_CHANGED
:
3176 host
.ParameterMappedControlIndexChangedCallback
.emit(pluginId
, value1
, value2
)
3177 elif action
== ENGINE_CALLBACK_PARAMETER_MAPPED_RANGE_CHANGED
:
3178 minimum
, maximum
= (float(v
) for v
in valueStr
.split(":", 2))
3179 host
.ParameterMappedRangeChangedCallback
.emit(pluginId
, value1
, minimum
, maximum
)
3180 elif action
== ENGINE_CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED
:
3181 host
.ParameterMidiChannelChangedCallback
.emit(pluginId
, value1
, value2
)
3182 elif action
== ENGINE_CALLBACK_PROGRAM_CHANGED
:
3183 host
.ProgramChangedCallback
.emit(pluginId
, value1
)
3184 elif action
== ENGINE_CALLBACK_MIDI_PROGRAM_CHANGED
:
3185 host
.MidiProgramChangedCallback
.emit(pluginId
, value1
)
3186 elif action
== ENGINE_CALLBACK_OPTION_CHANGED
:
3187 host
.OptionChangedCallback
.emit(pluginId
, value1
, bool(value2
))
3188 elif action
== ENGINE_CALLBACK_UI_STATE_CHANGED
:
3189 host
.UiStateChangedCallback
.emit(pluginId
, value1
)
3190 elif action
== ENGINE_CALLBACK_NOTE_ON
:
3191 host
.NoteOnCallback
.emit(pluginId
, value1
, value2
, value3
)
3192 elif action
== ENGINE_CALLBACK_NOTE_OFF
:
3193 host
.NoteOffCallback
.emit(pluginId
, value1
, value2
)
3194 elif action
== ENGINE_CALLBACK_UPDATE
:
3195 host
.UpdateCallback
.emit(pluginId
)
3196 elif action
== ENGINE_CALLBACK_RELOAD_INFO
:
3197 host
.ReloadInfoCallback
.emit(pluginId
)
3198 elif action
== ENGINE_CALLBACK_RELOAD_PARAMETERS
:
3199 host
.ReloadParametersCallback
.emit(pluginId
)
3200 elif action
== ENGINE_CALLBACK_RELOAD_PROGRAMS
:
3201 host
.ReloadProgramsCallback
.emit(pluginId
)
3202 elif action
== ENGINE_CALLBACK_RELOAD_ALL
:
3203 host
.ReloadAllCallback
.emit(pluginId
)
3204 elif action
== ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED
:
3205 host
.PatchbayClientAddedCallback
.emit(pluginId
, value1
, value2
, valueStr
)
3206 elif action
== ENGINE_CALLBACK_PATCHBAY_CLIENT_REMOVED
:
3207 host
.PatchbayClientRemovedCallback
.emit(pluginId
)
3208 elif action
== ENGINE_CALLBACK_PATCHBAY_CLIENT_RENAMED
:
3209 host
.PatchbayClientRenamedCallback
.emit(pluginId
, valueStr
)
3210 elif action
== ENGINE_CALLBACK_PATCHBAY_CLIENT_DATA_CHANGED
:
3211 host
.PatchbayClientDataChangedCallback
.emit(pluginId
, value1
, value2
)
3212 elif action
== ENGINE_CALLBACK_PATCHBAY_CLIENT_POSITION_CHANGED
:
3213 host
.PatchbayClientPositionChangedCallback
.emit(pluginId
, value1
, value2
, value3
, int(round(valuef
)))
3214 elif action
== ENGINE_CALLBACK_PATCHBAY_PORT_ADDED
:
3215 host
.PatchbayPortAddedCallback
.emit(pluginId
, value1
, value2
, value3
, valueStr
)
3216 elif action
== ENGINE_CALLBACK_PATCHBAY_PORT_REMOVED
:
3217 host
.PatchbayPortRemovedCallback
.emit(pluginId
, value1
)
3218 elif action
== ENGINE_CALLBACK_PATCHBAY_PORT_CHANGED
:
3219 host
.PatchbayPortChangedCallback
.emit(pluginId
, value1
, value2
, value3
, valueStr
)
3220 elif action
== ENGINE_CALLBACK_PATCHBAY_PORT_GROUP_ADDED
:
3221 host
.PatchbayPortGroupAddedCallback
.emit(pluginId
, value1
, value2
, valueStr
)
3222 elif action
== ENGINE_CALLBACK_PATCHBAY_PORT_GROUP_REMOVED
:
3223 host
.PatchbayPortGroupRemovedCallback
.emit(pluginId
, value1
)
3224 elif action
== ENGINE_CALLBACK_PATCHBAY_PORT_GROUP_CHANGED
:
3225 host
.PatchbayPortGroupChangedCallback
.emit(pluginId
, value1
, value2
, valueStr
)
3226 elif action
== ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED
:
3227 gOut
, pOut
, gIn
, pIn
= [int(i
) for i
in valueStr
.split(":")] # FIXME
3228 host
.PatchbayConnectionAddedCallback
.emit(pluginId
, gOut
, pOut
, gIn
, pIn
)
3229 elif action
== ENGINE_CALLBACK_PATCHBAY_CONNECTION_REMOVED
:
3230 host
.PatchbayConnectionRemovedCallback
.emit(pluginId
, value1
, value2
)
3231 elif action
== ENGINE_CALLBACK_ENGINE_STARTED
:
3232 host
.EngineStartedCallback
.emit(pluginId
, value1
, value2
, value3
, valuef
, valueStr
)
3233 elif action
== ENGINE_CALLBACK_ENGINE_STOPPED
:
3234 host
.EngineStoppedCallback
.emit()
3235 elif action
== ENGINE_CALLBACK_PROCESS_MODE_CHANGED
:
3236 host
.ProcessModeChangedCallback
.emit(value1
)
3237 elif action
== ENGINE_CALLBACK_TRANSPORT_MODE_CHANGED
:
3238 host
.TransportModeChangedCallback
.emit(value1
, valueStr
)
3239 elif action
== ENGINE_CALLBACK_BUFFER_SIZE_CHANGED
:
3240 host
.BufferSizeChangedCallback
.emit(value1
)
3241 elif action
== ENGINE_CALLBACK_SAMPLE_RATE_CHANGED
:
3242 host
.SampleRateChangedCallback
.emit(valuef
)
3243 elif action
== ENGINE_CALLBACK_CANCELABLE_ACTION
:
3244 host
.CancelableActionCallback
.emit(pluginId
, bool(value1
!= 0), valueStr
)
3245 elif action
== ENGINE_CALLBACK_PROJECT_LOAD_FINISHED
:
3246 host
.ProjectLoadFinishedCallback
.emit()
3247 elif action
== ENGINE_CALLBACK_NSM
:
3248 host
.NSMCallback
.emit(value1
, value2
, valueStr
)
3249 elif action
== ENGINE_CALLBACK_IDLE
:
3250 QApplication
.processEvents()
3251 elif action
== ENGINE_CALLBACK_INFO
:
3252 host
.InfoCallback
.emit(valueStr
)
3253 elif action
== ENGINE_CALLBACK_ERROR
:
3254 host
.ErrorCallback
.emit(valueStr
)
3255 elif action
== ENGINE_CALLBACK_QUIT
:
3256 host
.QuitCallback
.emit()
3257 elif action
== ENGINE_CALLBACK_INLINE_DISPLAY_REDRAW
:
3258 host
.InlineDisplayRedrawCallback
.emit(pluginId
)
3260 print("unhandled action", action
)
3262 # ------------------------------------------------------------------------------------------------------------
3265 def fileCallback(ptr
, action
, isDir
, title
, filter):
3266 title
= charPtrToString(title
)
3267 filter = charPtrToString(filter)
3269 if action
== FILE_CALLBACK_OPEN
:
3270 ret
, ok
= QFileDialog
.getOpenFileName(gCarla
.gui
, title
, "", filter) #, QFileDialog.ShowDirsOnly if isDir else 0x0)
3271 elif action
== FILE_CALLBACK_SAVE
:
3272 ret
, ok
= QFileDialog
.getSaveFileName(gCarla
.gui
, title
, "", filter, QFileDialog
.ShowDirsOnly
if isDir
else 0x0)
3276 # FIXME use ok value, test if it works as expected
3282 fileRet
= c_char_p(ret
.encode("utf-8"))
3283 retval
= cast(byref(fileRet
), POINTER(c_uintptr
))
3284 return retval
.contents
.value
3286 # ------------------------------------------------------------------------------------------------------------
3289 def initHost(initName
, libPrefix
, isControl
, isPlugin
, failError
, HostClass
= None):
3290 pathBinaries
, pathResources
= getPaths(libPrefix
)
3292 # --------------------------------------------------------------------------------------------------------
3293 # Fail if binary dir is not found
3295 if not os
.path
.exists(pathBinaries
):
3297 QMessageBox
.critical(None, "Error", "Failed to find the carla binaries, cannot continue")
3301 # --------------------------------------------------------------------------------------------------------
3302 # Check if we should open main lib as local or global
3304 settings
= QSafeSettings("falkTX", "Carla2")
3306 loadGlobal
= settings
.value(CARLA_KEY_EXPERIMENTAL_LOAD_LIB_GLOBAL
, CARLA_DEFAULT_EXPERIMENTAL_LOAD_LIB_GLOBAL
, bool)
3308 # --------------------------------------------------------------------------------------------------------
3309 # Set Carla library name
3311 libname
= "libcarla_%s2.%s" % ("control" if isControl
else "standalone", DLL_EXTENSION
)
3312 libname
= os
.path
.join(pathBinaries
, libname
)
3313 felibname
= os
.path
.join(pathBinaries
, "libcarla_frontend.%s" % (DLL_EXTENSION
))
3314 utilsname
= os
.path
.join(pathBinaries
, "libcarla_utils.%s" % (DLL_EXTENSION
))
3316 # --------------------------------------------------------------------------------------------------------
3319 if not (gCarla
.nogui
and isinstance(gCarla
.nogui
, int)):
3320 print("Carla %s started, status:" % VERSION
)
3321 print(" Python version: %s" % sys
.version
.split(" ",1)[0])
3322 print(" Qt version: %s" % QT_VERSION_STR
)
3323 print(" PyQt version: %s" % PYQT_VERSION_STR
)
3324 print(" Binary dir: %s" % pathBinaries
)
3325 print(" Resources dir: %s" % pathResources
)
3327 # --------------------------------------------------------------------------------------------------------
3332 host
= HostClass() if HostClass
is not None else CarlaHostQtDLL(libname
, loadGlobal
)
3335 host
= HostClass() if HostClass
is not None else CarlaHostQtDLL(libname
, loadGlobal
)
3337 host
= CarlaHostQtNull()
3339 host
.isControl
= isControl
3340 host
.isPlugin
= isPlugin
3342 host
.set_engine_callback(lambda h
,a
,p
,v1
,v2
,v3
,vf
,vs
: engineCallback(host
,a
,p
,v1
,v2
,v3
,vf
,vs
))
3343 host
.set_file_callback(fileCallback
)
3345 # If it's a plugin the paths are already set
3347 host
.pathBinaries
= pathBinaries
3348 host
.pathResources
= pathResources
3349 host
.set_engine_option(ENGINE_OPTION_PATH_BINARIES
, 0, pathBinaries
)
3350 host
.set_engine_option(ENGINE_OPTION_PATH_RESOURCES
, 0, pathResources
)
3353 host
.nsmOK
= host
.nsm_init(os
.getpid(), initName
)
3355 # --------------------------------------------------------------------------------------------------------
3358 if not gCarla
.nogui
:
3359 gCarla
.felib
= CarlaFrontendLib(felibname
)
3361 # --------------------------------------------------------------------------------------------------------
3364 gCarla
.utils
= CarlaUtils(utilsname
)
3365 gCarla
.utils
.set_process_name(os
.path
.basename(initName
))
3372 sys
.stdout
= CarlaPrint(False)
3373 sys
.stderr
= CarlaPrint(True)
3374 sys
.excepthook
= sys_excepthook
3376 # --------------------------------------------------------------------------------------------------------
3381 # ------------------------------------------------------------------------------------------------------------
3382 # Load host settings
3384 def loadHostSettings(host
):
3385 # kdevelop likes this :)
3386 if False: host
= CarlaHostNull()
3388 settings
= QSafeSettings("falkTX", "Carla2")
3390 host
.experimental
= settings
.value(CARLA_KEY_MAIN_EXPERIMENTAL
, CARLA_DEFAULT_MAIN_EXPERIMENTAL
, bool)
3391 host
.exportLV2
= settings
.value(CARLA_KEY_EXPERIMENTAL_EXPORT_LV2
, CARLA_DEFAULT_EXPERIMENTAL_LV2_EXPORT
, bool)
3392 host
.manageUIs
= settings
.value(CARLA_KEY_ENGINE_MANAGE_UIS
, CARLA_DEFAULT_MANAGE_UIS
, bool)
3393 host
.maxParameters
= settings
.value(CARLA_KEY_ENGINE_MAX_PARAMETERS
, CARLA_DEFAULT_MAX_PARAMETERS
, int)
3394 host
.resetXruns
= settings
.value(CARLA_KEY_ENGINE_RESET_XRUNS
, CARLA_DEFAULT_RESET_XRUNS
, bool)
3395 host
.forceStereo
= settings
.value(CARLA_KEY_ENGINE_FORCE_STEREO
, CARLA_DEFAULT_FORCE_STEREO
, bool)
3396 host
.preferPluginBridges
= settings
.value(CARLA_KEY_ENGINE_PREFER_PLUGIN_BRIDGES
, CARLA_DEFAULT_PREFER_PLUGIN_BRIDGES
, bool)
3397 host
.preferUIBridges
= settings
.value(CARLA_KEY_ENGINE_PREFER_UI_BRIDGES
, CARLA_DEFAULT_PREFER_UI_BRIDGES
, bool)
3398 host
.preventBadBehaviour
= settings
.value(CARLA_KEY_EXPERIMENTAL_PREVENT_BAD_BEHAVIOUR
, CARLA_DEFAULT_EXPERIMENTAL_PREVENT_BAD_BEHAVIOUR
, bool)
3399 host
.showLogs
= settings
.value(CARLA_KEY_MAIN_SHOW_LOGS
, CARLA_DEFAULT_MAIN_SHOW_LOGS
, bool) and not WINDOWS
3400 host
.showPluginBridges
= settings
.value(CARLA_KEY_EXPERIMENTAL_PLUGIN_BRIDGES
, CARLA_DEFAULT_EXPERIMENTAL_PLUGIN_BRIDGES
, bool)
3401 host
.showWineBridges
= settings
.value(CARLA_KEY_EXPERIMENTAL_WINE_BRIDGES
, CARLA_DEFAULT_EXPERIMENTAL_WINE_BRIDGES
, bool)
3402 host
.uiBridgesTimeout
= settings
.value(CARLA_KEY_ENGINE_UI_BRIDGES_TIMEOUT
, CARLA_DEFAULT_UI_BRIDGES_TIMEOUT
, int)
3403 host
.uisAlwaysOnTop
= settings
.value(CARLA_KEY_ENGINE_UIS_ALWAYS_ON_TOP
, CARLA_DEFAULT_UIS_ALWAYS_ON_TOP
, bool)
3408 host
.transportExtra
= settings
.value(CARLA_KEY_ENGINE_TRANSPORT_EXTRA
, "", str)
3411 if host
.audioDriverForced
is None:
3412 host
.transportMode
= settings
.value(CARLA_KEY_ENGINE_TRANSPORT_MODE
, CARLA_DEFAULT_TRANSPORT_MODE
, int)
3414 if not host
.processModeForced
:
3415 host
.processMode
= settings
.value(CARLA_KEY_ENGINE_PROCESS_MODE
, CARLA_DEFAULT_PROCESS_MODE
, int)
3417 host
.nextProcessMode
= host
.processMode
3419 # --------------------------------------------------------------------------------------------------------
3420 # fix things if needed
3422 if host
.processMode
== ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS
:
3424 print("LADISH detected but using multiple clients (not allowed), forcing single client now")
3425 host
.nextProcessMode
= host
.processMode
= ENGINE_PROCESS_MODE_SINGLE_CLIENT
3428 host
.transportMode
= ENGINE_TRANSPORT_MODE_JACK
3431 host
.showLogs
= False
3433 # --------------------------------------------------------------------------------------------------------
3434 # run headless host now if nogui option enabled
3437 runHostWithoutUI(host
)
3439 # ------------------------------------------------------------------------------------------------------------
3442 def setHostSettings(host
):
3443 # kdevelop likes this :)
3444 if False: host
= CarlaHostNull()
3446 host
.set_engine_option(ENGINE_OPTION_FORCE_STEREO
, host
.forceStereo
, "")
3447 host
.set_engine_option(ENGINE_OPTION_MAX_PARAMETERS
, host
.maxParameters
, "")
3448 host
.set_engine_option(ENGINE_OPTION_RESET_XRUNS
, host
.resetXruns
, "")
3449 host
.set_engine_option(ENGINE_OPTION_PREFER_PLUGIN_BRIDGES
, host
.preferPluginBridges
, "")
3450 host
.set_engine_option(ENGINE_OPTION_PREFER_UI_BRIDGES
, host
.preferUIBridges
, "")
3451 host
.set_engine_option(ENGINE_OPTION_PREVENT_BAD_BEHAVIOUR
, host
.preventBadBehaviour
, "")
3452 host
.set_engine_option(ENGINE_OPTION_UI_BRIDGES_TIMEOUT
, host
.uiBridgesTimeout
, "")
3453 host
.set_engine_option(ENGINE_OPTION_UIS_ALWAYS_ON_TOP
, host
.uisAlwaysOnTop
, "")
3455 if host
.isPlugin
or host
.isRemote
or host
.is_engine_running():
3458 host
.set_engine_option(ENGINE_OPTION_PROCESS_MODE
, host
.nextProcessMode
, "")
3459 host
.set_engine_option(ENGINE_OPTION_TRANSPORT_MODE
, host
.transportMode
, host
.transportExtra
)
3460 host
.set_engine_option(ENGINE_OPTION_DEBUG_CONSOLE_OUTPUT
, host
.showLogs
, "")
3462 if not (NSM_URL
and host
.nsmOK
):
3463 host
.set_engine_option(ENGINE_OPTION_CLIENT_NAME_PREFIX
, 0, gCarla
.cnprefix
)
3465 # ---------------------------------------------------------------------------------------------------------------------
3466 # Set Engine settings according to carla preferences. Returns selected audio driver.
3468 def setEngineSettings(host
, settings
, oscPort
= None):
3469 # kdevelop likes this :)
3470 if False: host
= CarlaHostNull()
3472 # -----------------------------------------------------------------------------------------------------------------
3473 # do nothing if control
3478 # -----------------------------------------------------------------------------------------------------------------
3479 # fetch settings as needed
3481 if settings
is None:
3482 qsettings
= QSafeSettings("falkTX", "Carla2")
3484 if host
.audioDriverForced
is not None:
3485 audioDriver
= host
.audioDriverForced
3487 audioDriver
= qsettings
.value(CARLA_KEY_ENGINE_AUDIO_DRIVER
, CARLA_DEFAULT_AUDIO_DRIVER
, str)
3489 audioDriverPrefix
= CARLA_KEY_ENGINE_DRIVER_PREFIX
+ audioDriver
3493 CARLA_KEY_ENGINE_AUDIO_DRIVER
: audioDriver
,
3494 CARLA_KEY_ENGINE_AUDIO_DEVICE
: qsettings
.value(audioDriverPrefix
+"/Device", "", str),
3495 CARLA_KEY_ENGINE_BUFFER_SIZE
: qsettings
.value(audioDriverPrefix
+"/BufferSize", CARLA_DEFAULT_AUDIO_BUFFER_SIZE
, int),
3496 CARLA_KEY_ENGINE_SAMPLE_RATE
: qsettings
.value(audioDriverPrefix
+"/SampleRate", CARLA_DEFAULT_AUDIO_SAMPLE_RATE
, int),
3497 CARLA_KEY_ENGINE_TRIPLE_BUFFER
: qsettings
.value(audioDriverPrefix
+"/TripleBuffer", CARLA_DEFAULT_AUDIO_TRIPLE_BUFFER
, bool),
3500 CARLA_KEY_PATHS_AUDIO
: splitter
.join(qsettings
.value(CARLA_KEY_PATHS_AUDIO
, CARLA_DEFAULT_FILE_PATH_AUDIO
, list)),
3501 CARLA_KEY_PATHS_MIDI
: splitter
.join(qsettings
.value(CARLA_KEY_PATHS_MIDI
, CARLA_DEFAULT_FILE_PATH_MIDI
, list)),
3504 CARLA_KEY_PATHS_LADSPA
: splitter
.join(qsettings
.value(CARLA_KEY_PATHS_LADSPA
, CARLA_DEFAULT_LADSPA_PATH
, list)),
3505 CARLA_KEY_PATHS_DSSI
: splitter
.join(qsettings
.value(CARLA_KEY_PATHS_DSSI
, CARLA_DEFAULT_DSSI_PATH
, list)),
3506 CARLA_KEY_PATHS_LV2
: splitter
.join(qsettings
.value(CARLA_KEY_PATHS_LV2
, CARLA_DEFAULT_LV2_PATH
, list)),
3507 CARLA_KEY_PATHS_VST2
: splitter
.join(qsettings
.value(CARLA_KEY_PATHS_VST2
, CARLA_DEFAULT_VST2_PATH
, list)),
3508 CARLA_KEY_PATHS_VST3
: splitter
.join(qsettings
.value(CARLA_KEY_PATHS_VST3
, CARLA_DEFAULT_VST3_PATH
, list)),
3509 CARLA_KEY_PATHS_SF2
: splitter
.join(qsettings
.value(CARLA_KEY_PATHS_SF2
, CARLA_DEFAULT_SF2_PATH
, list)),
3510 CARLA_KEY_PATHS_SFZ
: splitter
.join(qsettings
.value(CARLA_KEY_PATHS_SFZ
, CARLA_DEFAULT_SFZ_PATH
, list)),
3511 CARLA_KEY_PATHS_JSFX
: splitter
.join(qsettings
.value(CARLA_KEY_PATHS_JSFX
, CARLA_DEFAULT_JSFX_PATH
, list)),
3512 CARLA_KEY_PATHS_CLAP
: splitter
.join(qsettings
.value(CARLA_KEY_PATHS_CLAP
, CARLA_DEFAULT_CLAP_PATH
, list)),
3515 CARLA_KEY_OSC_ENABLED
: qsettings
.value(CARLA_KEY_OSC_ENABLED
, CARLA_DEFAULT_OSC_ENABLED
, bool),
3516 CARLA_KEY_OSC_TCP_PORT_ENABLED
: qsettings
.value(CARLA_KEY_OSC_TCP_PORT_ENABLED
, CARLA_DEFAULT_OSC_TCP_PORT_ENABLED
, bool),
3517 CARLA_KEY_OSC_TCP_PORT_RANDOM
: qsettings
.value(CARLA_KEY_OSC_TCP_PORT_RANDOM
, CARLA_DEFAULT_OSC_TCP_PORT_RANDOM
, bool),
3518 CARLA_KEY_OSC_TCP_PORT_NUMBER
: qsettings
.value(CARLA_KEY_OSC_TCP_PORT_NUMBER
, CARLA_DEFAULT_OSC_TCP_PORT_NUMBER
, int),
3519 CARLA_KEY_OSC_UDP_PORT_ENABLED
: qsettings
.value(CARLA_KEY_OSC_UDP_PORT_ENABLED
, CARLA_DEFAULT_OSC_UDP_PORT_ENABLED
, bool),
3520 CARLA_KEY_OSC_UDP_PORT_RANDOM
: qsettings
.value(CARLA_KEY_OSC_UDP_PORT_RANDOM
, CARLA_DEFAULT_OSC_UDP_PORT_RANDOM
, bool),
3521 CARLA_KEY_OSC_UDP_PORT_NUMBER
: qsettings
.value(CARLA_KEY_OSC_UDP_PORT_NUMBER
, CARLA_DEFAULT_OSC_UDP_PORT_NUMBER
, int),
3524 CARLA_KEY_WINE_EXECUTABLE
: qsettings
.value(CARLA_KEY_WINE_EXECUTABLE
, CARLA_DEFAULT_WINE_EXECUTABLE
, str),
3525 CARLA_KEY_WINE_AUTO_PREFIX
: qsettings
.value(CARLA_KEY_WINE_AUTO_PREFIX
, CARLA_DEFAULT_WINE_AUTO_PREFIX
, bool),
3526 CARLA_KEY_WINE_FALLBACK_PREFIX
: qsettings
.value(CARLA_KEY_WINE_FALLBACK_PREFIX
, CARLA_DEFAULT_WINE_FALLBACK_PREFIX
, str),
3527 CARLA_KEY_WINE_RT_PRIO_ENABLED
: qsettings
.value(CARLA_KEY_WINE_RT_PRIO_ENABLED
, CARLA_DEFAULT_WINE_RT_PRIO_ENABLED
, bool),
3528 CARLA_KEY_WINE_BASE_RT_PRIO
: qsettings
.value(CARLA_KEY_WINE_BASE_RT_PRIO
, CARLA_DEFAULT_WINE_BASE_RT_PRIO
, int),
3529 CARLA_KEY_WINE_SERVER_RT_PRIO
: qsettings
.value(CARLA_KEY_WINE_SERVER_RT_PRIO
, CARLA_DEFAULT_WINE_SERVER_RT_PRIO
, int),
3532 # -----------------------------------------------------------------------------------------------------------------
3535 setHostSettings(host
)
3537 # -----------------------------------------------------------------------------------------------------------------
3540 host
.set_engine_option(ENGINE_OPTION_FILE_PATH
, FILE_AUDIO
, settings
[CARLA_KEY_PATHS_AUDIO
])
3541 host
.set_engine_option(ENGINE_OPTION_FILE_PATH
, FILE_MIDI
, settings
[CARLA_KEY_PATHS_MIDI
])
3543 # -----------------------------------------------------------------------------------------------------------------
3546 host
.set_engine_option(ENGINE_OPTION_PLUGIN_PATH
, PLUGIN_LADSPA
, settings
[CARLA_KEY_PATHS_LADSPA
])
3547 host
.set_engine_option(ENGINE_OPTION_PLUGIN_PATH
, PLUGIN_DSSI
, settings
[CARLA_KEY_PATHS_DSSI
])
3548 host
.set_engine_option(ENGINE_OPTION_PLUGIN_PATH
, PLUGIN_LV2
, settings
[CARLA_KEY_PATHS_LV2
])
3549 host
.set_engine_option(ENGINE_OPTION_PLUGIN_PATH
, PLUGIN_VST2
, settings
[CARLA_KEY_PATHS_VST2
])
3550 host
.set_engine_option(ENGINE_OPTION_PLUGIN_PATH
, PLUGIN_VST3
, settings
[CARLA_KEY_PATHS_VST3
])
3551 host
.set_engine_option(ENGINE_OPTION_PLUGIN_PATH
, PLUGIN_SF2
, settings
[CARLA_KEY_PATHS_SF2
])
3552 host
.set_engine_option(ENGINE_OPTION_PLUGIN_PATH
, PLUGIN_SFZ
, settings
[CARLA_KEY_PATHS_SFZ
])
3553 host
.set_engine_option(ENGINE_OPTION_PLUGIN_PATH
, PLUGIN_JSFX
, settings
[CARLA_KEY_PATHS_JSFX
])
3554 host
.set_engine_option(ENGINE_OPTION_PLUGIN_PATH
, PLUGIN_CLAP
, settings
[CARLA_KEY_PATHS_CLAP
])
3556 # -----------------------------------------------------------------------------------------------------------------
3557 # don't continue if plugin
3562 # -----------------------------------------------------------------------------------------------------------------
3565 if oscPort
is not None and isinstance(oscPort
, int):
3567 portNumTCP
= portNumUDP
= oscPort
3570 oscEnabled
= settings
[CARLA_KEY_OSC_ENABLED
]
3572 if not settings
[CARLA_KEY_OSC_TCP_PORT_ENABLED
]:
3574 elif settings
[CARLA_KEY_OSC_TCP_PORT_RANDOM
]:
3577 portNumTCP
= settings
[CARLA_KEY_OSC_TCP_PORT_NUMBER
]
3579 if not settings
[CARLA_KEY_OSC_UDP_PORT_ENABLED
]:
3581 elif settings
[CARLA_KEY_OSC_UDP_PORT_RANDOM
]:
3584 portNumUDP
= settings
[CARLA_KEY_OSC_UDP_PORT_NUMBER
]
3586 host
.set_engine_option(ENGINE_OPTION_OSC_ENABLED
, 1 if oscEnabled
else 0, "")
3587 host
.set_engine_option(ENGINE_OPTION_OSC_PORT_TCP
, portNumTCP
, "")
3588 host
.set_engine_option(ENGINE_OPTION_OSC_PORT_UDP
, portNumUDP
, "")
3590 # -----------------------------------------------------------------------------------------------------------------
3593 host
.set_engine_option(ENGINE_OPTION_WINE_EXECUTABLE
, 0, settings
[CARLA_KEY_WINE_EXECUTABLE
])
3594 host
.set_engine_option(ENGINE_OPTION_WINE_AUTO_PREFIX
, 1 if settings
[CARLA_KEY_WINE_AUTO_PREFIX
] else 0, "")
3595 host
.set_engine_option(ENGINE_OPTION_WINE_FALLBACK_PREFIX
, 0, os
.path
.expanduser(settings
[CARLA_KEY_WINE_FALLBACK_PREFIX
]))
3596 host
.set_engine_option(ENGINE_OPTION_WINE_RT_PRIO_ENABLED
, 1 if settings
[CARLA_KEY_WINE_RT_PRIO_ENABLED
] else 0, "")
3597 host
.set_engine_option(ENGINE_OPTION_WINE_BASE_RT_PRIO
, settings
[CARLA_KEY_WINE_BASE_RT_PRIO
], "")
3598 host
.set_engine_option(ENGINE_OPTION_WINE_SERVER_RT_PRIO
, settings
[CARLA_KEY_WINE_SERVER_RT_PRIO
], "")
3600 # -----------------------------------------------------------------------------------------------------------------
3601 # driver and device settings
3604 audioDriver
= settings
[CARLA_KEY_ENGINE_AUDIO_DRIVER
]
3606 # Only setup audio things if engine is not running
3607 if not host
.is_engine_running():
3608 host
.set_engine_option(ENGINE_OPTION_AUDIO_DRIVER
, 0, audioDriver
)
3609 host
.set_engine_option(ENGINE_OPTION_AUDIO_DEVICE
, 0, settings
[CARLA_KEY_ENGINE_AUDIO_DEVICE
])
3611 if not audioDriver
.startswith("JACK"):
3612 host
.set_engine_option(ENGINE_OPTION_AUDIO_BUFFER_SIZE
, settings
[CARLA_KEY_ENGINE_BUFFER_SIZE
], "")
3613 host
.set_engine_option(ENGINE_OPTION_AUDIO_SAMPLE_RATE
, settings
[CARLA_KEY_ENGINE_SAMPLE_RATE
], "")
3614 host
.set_engine_option(ENGINE_OPTION_AUDIO_TRIPLE_BUFFER
, 1 if settings
[CARLA_KEY_ENGINE_TRIPLE_BUFFER
] else 0, "")
3616 # -----------------------------------------------------------------------------------------------------------------
3617 # fix things if needed
3619 if audioDriver
!= "JACK" and host
.transportMode
== ENGINE_TRANSPORT_MODE_JACK
:
3620 host
.transportMode
= ENGINE_TRANSPORT_MODE_INTERNAL
3621 host
.set_engine_option(ENGINE_OPTION_TRANSPORT_MODE
, ENGINE_TRANSPORT_MODE_INTERNAL
, host
.transportExtra
)
3623 # -----------------------------------------------------------------------------------------------------------------
3624 # return selected driver name
3628 # ---------------------------------------------------------------------------------------------------------------------
3629 # Run Carla without showing UI
3631 def runHostWithoutUI(host
):
3632 # kdevelop likes this :)
3633 if False: host
= CarlaHostNull()
3635 # --------------------------------------------------------------------------------------------------------
3636 # Some initial checks
3638 if not gCarla
.nogui
:
3641 projectFile
= getInitialProjectFile(True)
3643 if gCarla
.nogui
is True:
3647 print("Carla no-gui mode can only be used together with a project file.")
3651 oscPort
= gCarla
.nogui
3653 # --------------------------------------------------------------------------------------------------------
3654 # Additional imports
3656 from time
import sleep
3658 # --------------------------------------------------------------------------------------------------------
3661 audioDriver
= setEngineSettings(host
, None, oscPort
)
3662 if not host
.engine_init(audioDriver
, CARLA_CLIENT_NAME
or "Carla"):
3663 print("Engine failed to initialize, possible reasons:\n%s" % host
.get_last_error())
3666 if projectFile
and not host
.load_project(projectFile
):
3667 print("Failed to load selected project file, possible reasons:\n%s" % host
.get_last_error())
3671 # --------------------------------------------------------------------------------------------------------
3674 print("Carla ready!")
3676 while host
.is_engine_running() and not gCarla
.term
:
3678 sleep(0.0333) # 30 Hz
3680 # --------------------------------------------------------------------------------------------------------
3686 # ------------------------------------------------------------------------------------------------------------