Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

jackappdialog.py 9.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # Carla plugin host
  4. # Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com>
  5. #
  6. # This program is free software; you can redistribute it and/or
  7. # modify it under the terms of the GNU General Public License as
  8. # published by the Free Software Foundation; either version 2 of
  9. # the License, or any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # For a full copy of the GNU General Public License see the doc/GPL.txt file.
  17. # ---------------------------------------------------------------------------------------------------------------------
  18. # Imports (Global)
  19. import os
  20. from PyQt5.QtCore import pyqtSlot, Qt
  21. from PyQt5.QtWidgets import QDialog, QDialogButtonBox, QWidget
  22. # ---------------------------------------------------------------------------------------------------------------------
  23. # Imports (Carla)
  24. from utils import QSafeSettings
  25. # ---------------------------------------------------------------------------------------------------------------------
  26. # Imports (Local)
  27. from .jackappdialog_ui import Ui_Dialog
  28. # ---------------------------------------------------------------------------------------------------------------------
  29. # Imports (API)
  30. SESSION_MGR_NONE = 0
  31. SESSION_MGR_AUTO = 1
  32. SESSION_MGR_JACK = 2
  33. SESSION_MGR_LADISH = 3
  34. SESSION_MGR_NSM = 4
  35. FLAG_CONTROL_WINDOW = 0x01
  36. FLAG_CAPTURE_FIRST_WINDOW = 0x02
  37. FLAG_BUFFERS_ADDITION_MODE = 0x10
  38. FLAG_MIDI_OUTPUT_CHANNEL_MIXDOWN = 0x20
  39. FLAG_EXTERNAL_START = 0x40
  40. # ---------------------------------------------------------------------------------------------------------------------
  41. # Jack Application Dialog
  42. UI_SESSION_NONE = 0
  43. UI_SESSION_LADISH = 1
  44. UI_SESSION_NSM = 2
  45. class JackApplicationW(QDialog):
  46. def __init__(self, parent: QWidget, projectFilename: str):
  47. QDialog.__init__(self, parent)
  48. self.ui = Ui_Dialog()
  49. self.ui.setupUi(self)
  50. self.fProjectFilename = projectFilename
  51. # --------------------------------------------------------------------------------------------------------------
  52. # UI setup
  53. self.ui.group_error.setVisible(False)
  54. self.adjustSize()
  55. self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)
  56. # --------------------------------------------------------------------------------------------------------------
  57. # Load settings
  58. self._loadSettings()
  59. # --------------------------------------------------------------------------------------------------------------
  60. # Set-up connections
  61. self.finished.connect(self._slot_saveSettings)
  62. self.ui.cb_session_mgr.currentIndexChanged.connect(self._slot_sessionManagerChanged)
  63. self.ui.le_command.textChanged.connect(self._slot_commandChanged)
  64. # -----------------------------------------------------------------------------------------------------------------
  65. # public methods
  66. def getCommandAndFlags(self):
  67. name = self.ui.le_name.text()
  68. command = self.ui.le_command.text()
  69. smgr = SESSION_MGR_NONE
  70. flags = 0x0
  71. if not name:
  72. name = os.path.basename(command.split(" ",1)[0]).title()
  73. uiSessionMgrIndex = self.ui.cb_session_mgr.currentIndex()
  74. if uiSessionMgrIndex == UI_SESSION_LADISH:
  75. smgr = SESSION_MGR_LADISH
  76. elif uiSessionMgrIndex == UI_SESSION_NSM:
  77. smgr = SESSION_MGR_NSM
  78. if self.ui.cb_manage_window.isChecked():
  79. flags |= FLAG_CONTROL_WINDOW
  80. if self.ui.cb_capture_first_window.isChecked():
  81. flags |= FLAG_CAPTURE_FIRST_WINDOW
  82. if self.ui.cb_buffers_addition_mode.isChecked():
  83. flags |= FLAG_BUFFERS_ADDITION_MODE
  84. if self.ui.cb_out_midi_mixdown.isChecked():
  85. flags |= FLAG_MIDI_OUTPUT_CHANNEL_MIXDOWN
  86. if self.ui.cb_external_start.isChecked():
  87. flags |= FLAG_EXTERNAL_START
  88. bv = ord('0')
  89. v1 = chr(bv + self.ui.sb_audio_ins.value())
  90. v2 = chr(bv + self.ui.sb_audio_outs.value())
  91. v3 = chr(bv + self.ui.sb_midi_ins.value())
  92. v4 = chr(bv + self.ui.sb_midi_outs.value())
  93. v5 = chr(bv + smgr)
  94. v6 = chr(bv + flags)
  95. labelSetup = f"{v1}{v2}{v3}{v4}{v5}{v6}"
  96. return (command, name, labelSetup)
  97. # -----------------------------------------------------------------------------------------------------------------
  98. # private methods
  99. def _checkIfButtonBoxShouldBeEnabled(self, index: int, command: str):
  100. enabled = len(command) > 0
  101. showErr = ""
  102. # NSM applications must not be abstract or absolute paths, and must not contain arguments
  103. if enabled and index == UI_SESSION_NSM:
  104. if command[0] in (".", "/"):
  105. showErr = self.tr("NSM applications cannot use abstract or absolute paths")
  106. elif " " in command or ";" in command or "&" in command:
  107. showErr = self.tr("NSM applications cannot use CLI arguments")
  108. elif not self.fProjectFilename:
  109. showErr = self.tr("You need to save the current Carla project before NSM can be used")
  110. if showErr:
  111. enabled = False
  112. self.ui.l_error.setText(showErr)
  113. self.ui.group_error.setVisible(True)
  114. else:
  115. self.ui.group_error.setVisible(False)
  116. self.ui.buttonBox.button(QDialogButtonBox.Ok).setEnabled(enabled)
  117. def _loadSettings(self):
  118. settings = QSafeSettings("falkTX", "CarlaAddJackApp")
  119. smName = settings.value("SessionManager", "", str)
  120. if smName == "LADISH (SIGUSR1)":
  121. self.ui.cb_session_mgr.setCurrentIndex(UI_SESSION_LADISH)
  122. elif smName == "NSM":
  123. self.ui.cb_session_mgr.setCurrentIndex(UI_SESSION_NSM)
  124. else:
  125. self.ui.cb_session_mgr.setCurrentIndex(UI_SESSION_NONE)
  126. self.ui.le_command.setText(settings.value("Command", "", str))
  127. self.ui.le_name.setText(settings.value("Name", "", str))
  128. self.ui.sb_audio_ins.setValue(settings.value("NumAudioIns", 2, int))
  129. self.ui.sb_audio_ins.setValue(settings.value("NumAudioIns", 2, int))
  130. self.ui.sb_audio_outs.setValue(settings.value("NumAudioOuts", 2, int))
  131. self.ui.sb_midi_ins.setValue(settings.value("NumMidiIns", 0, int))
  132. self.ui.sb_midi_outs.setValue(settings.value("NumMidiOuts", 0, int))
  133. self.ui.cb_manage_window.setChecked(settings.value("ManageWindow", True, bool))
  134. self.ui.cb_capture_first_window.setChecked(settings.value("CaptureFirstWindow", False, bool))
  135. self.ui.cb_out_midi_mixdown.setChecked(settings.value("MidiOutMixdown", False, bool))
  136. self._checkIfButtonBoxShouldBeEnabled(self.ui.cb_session_mgr.currentIndex(),
  137. self.ui.le_command.text())
  138. # -----------------------------------------------------------------------------------------------------------------
  139. # private slots
  140. @pyqtSlot(str)
  141. def _slot_commandChanged(self, command: str):
  142. self._checkIfButtonBoxShouldBeEnabled(self.ui.cb_session_mgr.currentIndex(), command)
  143. @pyqtSlot(int)
  144. def _slot_sessionManagerChanged(self, index: int):
  145. self._checkIfButtonBoxShouldBeEnabled(index, self.ui.le_command.text())
  146. @pyqtSlot()
  147. def _slot_saveSettings(self):
  148. settings = QSafeSettings("falkTX", "CarlaAddJackApp")
  149. settings.setValue("Command", self.ui.le_command.text())
  150. settings.setValue("Name", self.ui.le_name.text())
  151. settings.setValue("SessionManager", self.ui.cb_session_mgr.currentText())
  152. settings.setValue("NumAudioIns", self.ui.sb_audio_ins.value())
  153. settings.setValue("NumAudioOuts", self.ui.sb_audio_outs.value())
  154. settings.setValue("NumMidiIns", self.ui.sb_midi_ins.value())
  155. settings.setValue("NumMidiOuts", self.ui.sb_midi_outs.value())
  156. settings.setValue("ManageWindow", self.ui.cb_manage_window.isChecked())
  157. settings.setValue("CaptureFirstWindow", self.ui.cb_capture_first_window.isChecked())
  158. settings.setValue("MidiOutMixdown", self.ui.cb_out_midi_mixdown.isChecked())
  159. # ---------------------------------------------------------------------------------------------------------------------
  160. # Testing
  161. if __name__ == '__main__':
  162. import sys
  163. # pylint: disable=ungrouped-imports
  164. from PyQt5.QtWidgets import QApplication
  165. # pylint: enable=ungrouped-imports
  166. _app = QApplication(sys.argv)
  167. _gui = JackApplicationW(None, "")
  168. if _gui.exec_():
  169. _command, _name, _labelSetup = _gui.getCommandAndFlags()
  170. print("Results:")
  171. print(f"\tCommand: {_command}")
  172. print(f"\tName: {_name}")
  173. print(f"\tLabelSetup: {_labelSetup}")
  174. # ---------------------------------------------------------------------------------------------------------------------