From 6ac999b5f07477ada21d3b1ae4c5031588dd522d Mon Sep 17 00:00:00 2001 From: Nils Date: Sun, 15 May 2022 20:10:02 +0200 Subject: [PATCH] Change metronome to use good port names. New menu settings with option to autoconnect metronome on startup --- engine/api.py | 13 +++++++++++++ engine/config.py | 3 ++- engine/tempotrack.py | 1 - qtgui/designer/mainwindow.py | 11 +++++++++++ qtgui/designer/mainwindow.ui | 21 +++++++++++++++++++++ qtgui/mainwindow.py | 25 ++++++++++++++++++++++++- qtgui/menu.py | 2 ++ template/engine/metronome.py | 4 ++++ template/engine/sequencer.py | 19 +++++++++++++++---- 9 files changed, 92 insertions(+), 7 deletions(-) diff --git a/engine/api.py b/engine/api.py index 273cdee..3585848 100644 --- a/engine/api.py +++ b/engine/api.py @@ -2668,6 +2668,19 @@ def connectModMidiMerger(): pass +def connectMetronomeToSystemPorts(): + try: + hardwareAudioPorts = cbox.JackIO.get_ports("system*", cbox.JackIO.AUDIO_TYPE, cbox.JackIO.PORT_IS_SINK | cbox.JackIO.PORT_IS_PHYSICAL) #don't sort. This is correctly sorted. Another sorted will do 1, 10, 11, + l, r = session.data.metronome.getPortNames() + cbox.JackIO.port_connect(l, hardwareAudioPorts[0]) + cbox.JackIO.port_connect(r, hardwareAudioPorts[1]) + except: + pass + + + + + #Debug def printPitches(): diff --git a/engine/config.py b/engine/config.py index 0c0f0fa..62f8d53 100644 --- a/engine/config.py +++ b/engine/config.py @@ -40,7 +40,8 @@ METADATA={ #How many audio outputs do you want? must be pairs. These are just unconnected jack outputs #that need to be connected internally to instrument outputs like fluidsynth - "cboxOutputs" : 1 * 2, #metronome + #DEPRECATED SOON + "cboxOutputs" : 0, #Does the program use a metronome? In this case you need at least two cboxOutputs above "metronome" : True, diff --git a/engine/tempotrack.py b/engine/tempotrack.py index 17bd111..117120b 100644 --- a/engine/tempotrack.py +++ b/engine/tempotrack.py @@ -721,5 +721,4 @@ class TempoTrack(GraphTrackCC): pairs = pairwise(onlyStandalone) result = " ".join(_ly(tempoItem, nextTempoItem) for tempoItem, nextTempoItem in pairs) - #return "" here to not generate any metronome marks. Not even the default lilypond one. return result diff --git a/qtgui/designer/mainwindow.py b/qtgui/designer/mainwindow.py index b3f9a73..db7388c 100644 --- a/qtgui/designer/mainwindow.py +++ b/qtgui/designer/mainwindow.py @@ -76,6 +76,8 @@ class Ui_MainWindow(object): self.menuMIDI.setObjectName("menuMIDI") self.menuLilypond = QtWidgets.QMenu(self.menubar) self.menuLilypond.setObjectName("menuLilypond") + self.menuSettings = QtWidgets.QMenu(self.menubar) + self.menuSettings.setObjectName("menuSettings") MainWindow.setMenuBar(self.menubar) self.leftToolBar = QtWidgets.QToolBar(MainWindow) self.leftToolBar.setEnabled(True) @@ -672,6 +674,9 @@ class Ui_MainWindow(object): self.actionMove_Block_to_end_of_track.setObjectName("actionMove_Block_to_end_of_track") self.actionMove_Block_to_start_of_track = QtWidgets.QAction(MainWindow) self.actionMove_Block_to_start_of_track.setObjectName("actionMove_Block_to_start_of_track") + self.actionAutoconnect_Metronome = QtWidgets.QAction(MainWindow) + self.actionAutoconnect_Metronome.setCheckable(True) + self.actionAutoconnect_Metronome.setObjectName("actionAutoconnect_Metronome") self.menuObjects.addAction(self.actionMetrical_Instruction) self.menuObjects.addAction(self.actionClef) self.menuObjects.addAction(self.actionKey_Signature) @@ -859,6 +864,7 @@ class Ui_MainWindow(object): self.menuLilypond.addAction(self.actionLyFree_Instruction) self.menuLilypond.addAction(self.actionLyMarkAbove) self.menuLilypond.addAction(self.actionLyMarkBelow) + self.menuSettings.addAction(self.actionAutoconnect_Metronome) self.menubar.addAction(self.menuView.menuAction()) self.menubar.addAction(self.menuEdit_2.menuAction()) self.menubar.addAction(self.menu.menuAction()) @@ -869,6 +875,7 @@ class Ui_MainWindow(object): self.menubar.addAction(self.menuToolbox.menuAction()) self.menubar.addAction(self.menu_2.menuAction()) self.menubar.addAction(self.menuLilypond.menuAction()) + self.menubar.addAction(self.menuSettings.menuAction()) self.menubar.addAction(self.menuHelp.menuAction()) self.menubar.addAction(self.menuGeneric.menuAction()) @@ -891,6 +898,7 @@ class Ui_MainWindow(object): self.menuInsert.setTitle(_translate("MainWindow", "&Note Generation")) self.menuMIDI.setTitle(_translate("MainWindow", "&MIDI")) self.menuLilypond.setTitle(_translate("MainWindow", "&Lilypond")) + self.menuSettings.setTitle(_translate("MainWindow", "Settings")) self.actionDelete.setText(_translate("MainWindow", "&Delete Item")) self.actionBackspace.setText(_translate("MainWindow", "Delete previous &Item")) self.actionAddCursorNoteToChord.setText(_translate("MainWindow", "&Add Note to Chord")) @@ -1012,3 +1020,6 @@ class Ui_MainWindow(object): self.actionMove_Block_to_end_of_track.setShortcut(_translate("MainWindow", "Alt+End")) self.actionMove_Block_to_start_of_track.setText(_translate("MainWindow", "Move Block to start of track")) self.actionMove_Block_to_start_of_track.setShortcut(_translate("MainWindow", "Alt+Home")) + self.actionAutoconnect_Metronome.setText(_translate("MainWindow", "Autoconnect Metronome")) + self.actionAutoconnect_Metronome.setIconText(_translate("MainWindow", "Wether to autoconnect the mixer ports on program start. Not for NSM.")) + self.actionAutoconnect_Metronome.setToolTip(_translate("MainWindow", "Wether to autoconnect the mixer ports on program start. Not for NSM.")) diff --git a/qtgui/designer/mainwindow.ui b/qtgui/designer/mainwindow.ui index 42a1d66..776a87f 100644 --- a/qtgui/designer/mainwindow.ui +++ b/qtgui/designer/mainwindow.ui @@ -328,6 +328,12 @@ + + + Settings + + + @@ -338,6 +344,7 @@ + @@ -1781,6 +1788,20 @@ Alt+Home + + + true + + + Autoconnect Metronome + + + Wether to autoconnect the mixer ports on program start. Not for NSM. + + + Wether to autoconnect the mixer ports on program start. Not for NSM. + + diff --git a/qtgui/mainwindow.py b/qtgui/mainwindow.py index dc6d115..94105f7 100644 --- a/qtgui/mainwindow.py +++ b/qtgui/mainwindow.py @@ -42,6 +42,7 @@ from .menu import MenuActionDatabase from .scoreview import ScoreView from .trackEditor import TrackEditor from .resources import * +from engine.config import METADATA class MainWindow(TemplateMainWindow): @@ -116,6 +117,20 @@ class MainWindow(TemplateMainWindow): self.start() #Inherited from template main window #This shows the GUI, or not, depends on the NSM gui save setting. We need to call that after the menu, otherwise the about dialog will block and then we get new menu entries, which looks strange. stepMidiInput.start() #imported directly. Handles everything else internally, we just need to start it after the engine somehow. Which is here. + #Check if to connect the metronome on startup. But only when not running under NSM + if api.isStandaloneMode(): + self.ui.actionAutoconnect_Metronome.setEnabled(True) + settings = QtCore.QSettings("LaborejoSoftwareSuite", METADATA["shortName"]) + if settings.contains("autoconnectMetronome"): + autoconnectMixer = settings.value("autoconnectMetronome", type=bool) + else: + autoconnectMixer = False + self.ui.actionAutoconnect_Metronome.setChecked(autoconnectMixer) + self.reactToAutoconnectMixerCheckbox(autoconnectMixer) #do the connection + + else: + self.ui.actionAutoconnect_Metronome.setEnabled(False) + #Populate the left toolbar. The upper toolbar is created in menu.py self.ui.leftToolBar.addWidget(LeftToolBarPrevailingDuration(self)) #needs stepmidiinput started @@ -128,7 +143,7 @@ class MainWindow(TemplateMainWindow): #Here is the crowbar-method. self.nsmClient.announceSaveStatus(isClean = True) - api.connectModMidiMerger() + def zoom(self, scaleFactor:float): @@ -179,6 +194,14 @@ class MainWindow(TemplateMainWindow): self.scoreView.updateMode() self.trackEditor.setEnabled(False) + def reactToAutoconnectMixerCheckbox(self, state:bool): + """Triggered by the user and programatically during startup in __init__""" + assert api.isStandaloneMode() + settings = QtCore.QSettings("LaborejoSoftwareSuite", METADATA["shortName"]) + settings.setValue("autoconnectMetronome", state) + if state: + api.connectMetronomeToSystemPorts() + class LeftToolBarPrevailingDuration(QtWidgets.QLabel): def __init__(self, mainWindow): super().__init__(self.makeText(api.D4)) diff --git a/qtgui/menu.py b/qtgui/menu.py index a75cc05..c80c527 100644 --- a/qtgui/menu.py +++ b/qtgui/menu.py @@ -210,6 +210,8 @@ class MenuActionDatabase(object): self.mainWindow.ui.actionPlayFromEditCursor : api.playFromCursor, self.mainWindow.ui.actionPlay_from_Block : api.playFromBlockStart, self.mainWindow.ui.actionMetronome_Enabled : api.toggleMetronome, #toggle is enough. The callback makes sure all the checkboxes have the correct value. + self.mainWindow.ui.actionAutoconnect_Metronome : self.mainWindow.reactToAutoconnectMixerCheckbox, + } self.noteEditActions = { #these are only available in Note Edit Mode, not in CC Edit Mode etc. #all xxxEditActions are mutually exclusive. diff --git a/template/engine/metronome.py b/template/engine/metronome.py index 496ed40..edf33b9 100644 --- a/template/engine/metronome.py +++ b/template/engine/metronome.py @@ -73,6 +73,10 @@ class Metronome(object): self.label = "" #E.g. current Track Name, but can be anything. self.setEnabled(False) #TODO: save load + def getPortNames(self)->(str,str): + """Return two client:port , for left and right channel""" + return (self.sfzInstrumentSequencerInterface.portnameL, self.sfzInstrumentSequencerInterface.portnameR) + def soundStresses(self, value:bool): self._soundStresses = value self.generate(self._cachedData, self.label) diff --git a/template/engine/sequencer.py b/template/engine/sequencer.py index b8ffee1..d4d29f4 100644 --- a/template/engine/sequencer.py +++ b/template/engine/sequencer.py @@ -503,10 +503,21 @@ class SfzInstrumentSequencerInterface(_Interface): self.calfboxTrack.set_external_output("") #Metadata - portnameL = f"{cbox.JackIO.status().client_name}:out_1" - portnameR = f"{cbox.JackIO.status().client_name}:out_2" - cbox.JackIO.Metadata.set_pretty_name(portnameL, name.title() + "-L") - cbox.JackIO.Metadata.set_pretty_name(portnameR, name.title() + "-R") + l = f"{cbox.JackIO.status().client_name}:out_1" + r = f"{cbox.JackIO.status().client_name}:out_2" + self.portnameL = cbox.JackIO.status().client_name + ":" + name.title() + "-L" + self.portnameR = cbox.JackIO.status().client_name + ":" + name.title() + "-R" + + luuid = cbox.JackIO.create_audio_output(name.title() + "-L") + ruuid = cbox.JackIO.create_audio_output(name.title() + "-R") + cbox.JackIO.Metadata.set_pretty_name(self.portnameL, name.title() + "-L") + cbox.JackIO.Metadata.set_pretty_name(self.portnameR, name.title() + "-R") + + + self.outputMergerRouter = cbox.JackIO.create_audio_output_router(luuid, ruuid) + self.outputMergerRouter.set_gain(-1.0) + self.instrumentLayer.get_output_slot(0).rec_wet.attach(self.outputMergerRouter) #output_slot is 0 based and means a pair. + def enable(self, enabled): if enabled: