diff --git a/CHANGELOG b/CHANGELOG index 5406f68..2489fbb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -6,6 +6,7 @@ External contributors notice at the end of the line: (LastName, FirstName / nick ## 2022-07-15 2.1.0 +New function: custom key signature for any combination. Add two new functions to paste directly transposed (modal and real transposition) When not in F4-StepInput Mode use midi keyboard as pitch-cursor. Add midi-in selector drop down, as seen in Tembro and Fluajho. diff --git a/engine/api.py b/engine/api.py index 70dd9f9..7d3e80a 100644 --- a/engine/api.py +++ b/engine/api.py @@ -524,7 +524,7 @@ def pasteObjects(customBuffer=None, updateCursor=True, overwriteSelection=True): if updateCursor: callbacks._setCursor() -def pasteObjectsTransposedReal(root:int=None, toPitch:int=None, adjustToKeySignature=False): +def pasteObjectsTransposedReal(root:int=None, toPitch:int=None, adjustToKeySignKeySignature=False): """Uses the global/session clipboard buffer but pastes a transposed version, starting on the pitch cursor position, that is adjusted to the current keysignature. @@ -1070,6 +1070,12 @@ def getCursorSimpleLyNote(): lyNote = pitchmath.pitch2ly[pitch].strip("'").strip(",").lower() return lyNote +def getCursorPlainNote(): + """get the cursor pitch as plain note, for usage in a keysig etc.""" + root = pitchmath.plain(session.data.cursor.pitchindex) + keysig = session.data.currentTrack().state.keySignature() + pitchToInsert = pitchmath.toScale(root, keysig) + return pitchToInsert def toPosition(position:int): """Move the cursor to this position in the current track. """ @@ -1806,8 +1812,10 @@ def insertLegatoSlur(): #Key Signatures + def insertKeySignature(root:int, scheme:list, lilypondOverride:str=None): - keysig = items.KeySignature(pitchmath.plain(root), scheme) + """Scheme is deviation from _a_ major scale, relative to the root note""" + keysig = items.KeySignature(root, scheme) if lilypondOverride: keysig.lilypondParameters["override"] = lilypondOverride insertItem(keysig) @@ -1833,7 +1841,7 @@ def insertCommonKeySignature(root:int, scheme:str): """example: insertCommonKeySignature(P_C, "Major") """ - schemes = { + schemes = { #Scheme is deviation from _a_ major scale, relative to the root note "Major": [0,0,0,0,0,0,0], "Minor": [0,0,-10,0,0,-10,-10], "Dorian": [0,0,-10,0,0,0,-10], @@ -1861,13 +1869,15 @@ def insertCursorCommonKeySignature(scheme:str): into account. Scheme is a string as seen in commonKeySignaturesAsList() + Scheme is deviation from _a_ major scale, relative to the root note """ if not scheme in commonKeySignaturesAsList(): raise ValueError("Unknown key signature scheme string: " + scheme) root = pitchmath.plain(session.data.cursor.pitchindex) keysig = session.data.currentTrack().state.keySignature() - pitchToInsert = pitchmath.toScale(session.data.cursor.pitchindex, keysig) + #pitchToInsert = pitchmath.toScale(session.data.cursor.pitchindex, keysig) + pitchToInsert = pitchmath.toScale(root, keysig) insertCommonKeySignature(pitchToInsert, scheme) @@ -1934,6 +1944,14 @@ def insertCommonMetricalInstrucions(scheme): } insertMetricalInstruction(schemes[scheme], lilypondOverride = lilypond[scheme]) + +def metricalTest(): + scheme = ((D4, D4, D4), D4, D4) # wrong. should be... + scheme = (D4, D4, D4, D4, D4) #... just this. + scheme = ((D4, D4), (D4, D4, D4)) #real 5/4 as 2+3 + scheme = ( ((D4, D4), (D4, D4)), ((D4, D4, D4), (D4, D4)) ) #3 level 9/4 + insertMetricalInstruction( scheme, lilypondOverride = "\\time 9/4" ) + #Velocity and Dynamic Signatures def insertDynamicSignature(keyword): dynSig = items.DynamicSignature(keyword) diff --git a/engine/items.py b/engine/items.py index 1356fea..aaed582 100644 --- a/engine/items.py +++ b/engine/items.py @@ -2066,7 +2066,7 @@ class KeySignature(Item): G Major: KeySignature(220, [0, 0, 0, 10, 0, 0, 0]) Indian Scale ?: KeySignature(220, [0, -10, -20, 0, 0, -10, -20, 0]) #c, des, eeses, f, g, aes, beses, c - The input deviationFromMajorScale is transformed to an absolute + The input deviationFromMajorScale is a relative scale and transformed to an absolute keysig, compatible with Lilypond, in init. The result is saved permanently in self.keysigList in the following @@ -2093,7 +2093,7 @@ class KeySignature(Item): def __init__(self, root, deviationFromMajorScale): super().__init__() - assert root < 350 #really a plain note? + assert root < 350 #is it really a plain note? assert pitchmath.plain(root) == root self.root:int = root self.deviationFromMajorScale = deviationFromMajorScale @@ -2141,6 +2141,7 @@ class KeySignature(Item): self.keysigList = tuple(self.keysigList) #from list to tuple for hashing and caching + def hash(self): return self.keysigList @@ -2445,7 +2446,15 @@ class TimeSignature(Item): #Deprecated since 1750 class MetricalInstruction(Item): def __init__(self, treeOfInstructions, isMetrical = True): - """Don't edit. Delete and create a new one""" + """Don't edit. Delete and create a new one + + A few examples, but this has a real explanation in the manual + + 5/4 as 3+2 ((D4, D4, D4), (D4, D4)) + 5/4 broken as 3 + 2 unstressed notes ((D4, D4, D4), D4, D4) + this should have been (D4, D4, D4, D4, D4) + + """ super().__init__() for value in flatList(treeOfInstructions): if not type(value) is int: @@ -2493,11 +2502,14 @@ class MetricalInstruction(Item): return new def asText(self): + if not self.lilypondParameters["override"]: + return "MetricalInstruction" if self.lilypondParameters["override"] == "\\mark \"X\" \\cadenzaOn": return "\\time X" elif self.lilypondParameters["override"].startswith("\\cadenzaOff"): return self.lilypondParameters["override"][12:] - + elif self.lilypondParameters["override"]: + return self.lilypondParameters["override"] else: return "MetricalInstruction" diff --git a/qtgui/customkeysignature.py b/qtgui/customkeysignature.py new file mode 100644 index 0000000..56ebc52 --- /dev/null +++ b/qtgui/customkeysignature.py @@ -0,0 +1,249 @@ +#! /usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Copyright 2022, Nils Hilbricht, Germany ( https://www.hilbricht.net ) + +This file is part of the Laborejo Software Suite ( https://www.laborejo.org ), + +Laborejo2 is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +""" + +import logging; logger = logging.getLogger(__name__); logger.info("import") + + +#Third Party +from PyQt5 import QtCore, QtGui, QtWidgets + +#Template Modules +from template.engine.pitch import baseNotesToAccidentalNames, plain, intervalAutomatic, diatonicIndex + +#Our Modules +from .designer.customKeySignature import Ui_customKeySignature +import engine.api as api + + +class CustomKeySignatureWidget(QtWidgets.QDialog): + def __init__(self, mainWindow): + """Init is called everytime the dialog gets shown""" + super().__init__(mainWindow) + self.mainWindow = mainWindow + self.ui = Ui_customKeySignature() + self.ui.setupUi(self) + + + self.ui.buttonBox.accepted.connect(self.process) + self.ui.buttonBox.rejected.connect(self.reject) + + currentCursorPitch = api.getCursorPlainNote() + + self.resultLabels = ( + self.ui.label_result_c, + self.ui.label_result_d, + self.ui.label_result_e, + self.ui.label_result_f, + self.ui.label_result_g, + self.ui.label_result_a, + self.ui.label_result_b, + ) + + self.rootNotes = { + 20 : self.ui.root_c , + 70 : self.ui.root_d , + 120 : self.ui.root_e , + 170 : self.ui.root_f , + 220 : self.ui.root_g , + 270 : self.ui.root_a , + 320 : self.ui.root_b , + + 10 : self.ui.root_ces , + 60 : self.ui.root_des , + 110 : self.ui.root_ees , + 160 : self.ui.root_fes , + 210 : self.ui.root_ges , + 260 : self.ui.root_aes , + 310 : self.ui.root_bes , + + 30 : self.ui.root_cis , + 80: self.ui.root_dis , + 130 : self.ui.root_eis , + 180: self.ui.root_fis , + 230 : self.ui.root_gis , + 280: self.ui.root_ais , + 330 : self.ui.root_bis , + } + + #Add reverse lookup + self.buttonToRootNote = {} + for key, value in self.rootNotes.items(): + self.buttonToRootNote[value] = key + + self.rootNotes[currentCursorPitch].setChecked(True) + + for button in self.rootNotes.values(): + button.clicked.connect(self.sanityCheck) + + + ### Scale Radio Buttons. + ### Please note that the names are just shorthands because we create a relative scale here. + ### Those really should be roman numerals for first note, second note, third etc. but this is cumbersome to write + + self.scaleButtons = ( + ( + self.ui.isis_c , + self.ui.is_c , + self.ui.nat_c , + self.ui.es_c , + self.ui.eses_c , + ), + ( + self.ui.isis_d , + self.ui.is_d , + self.ui.nat_d , + self.ui.es_d , + self.ui.eses_d , + ), + ( + self.ui.isis_e , + self.ui.is_e , + self.ui.nat_e , + self.ui.es_e , + self.ui.eses_e , + ), + ( + self.ui.isis_f , + self.ui.is_f , + self.ui.nat_f , + self.ui.es_f , + self.ui.eses_f , + ), + ( + self.ui.isis_g , + self.ui.is_g , + self.ui.nat_g , + self.ui.es_g , + self.ui.eses_g , + ), + ( + self.ui.isis_a , + self.ui.is_a , + self.ui.nat_a , + self.ui.es_a , + self.ui.eses_a , + ), + ( + self.ui.isis_b , + self.ui.is_b , + self.ui.nat_b , + self.ui.es_b , + self.ui.eses_b , + ), + ) + + for group in self.scaleButtons: + group[2].setChecked(True) #Make natural the default. + for button in group: + button.setStyleSheet("QRadioButton { font : 18px }") + button.clicked.connect(self.sanityCheck) + + self.exec() #blocks until the dialog gets closed + + + def blockSignals(self, state:bool): + for group in self.scaleButtons: + for button in group: + button.blockSignals(state) + + for button in self.rootNotes.values(): + button.blockSignals(state) + + + + def findRootPitch(self)->int: + for rootButton, basePitch in self.buttonToRootNote.items(): + if rootButton.isChecked(): + return basePitch + else: + raise RuntimeError() + + + def groupToInScalePitch(self, groupIndex:int, checkSpecificStep:int=None): + selectedRootPitch = self.findRootPitch() + stepInCMajor = (groupIndex+1)*50 - 30 + + #The transposed interval scale is also major, of course. + stepInMajorRootScale = intervalAutomatic(originalPitch=stepInCMajor, rootPitch=20, targetPitch=selectedRootPitch) + + if checkSpecificStep is None: + #find the accidental mod + group = self.scaleButtons[groupIndex] + for counter, button in enumerate(reversed(group)): #group is isis to eses, so we need to reverse. + if button.isChecked(): + #counter remains + break + else: + counter = checkSpecificStep + + mod = 10*counter-20 #offset by -20 because the scale starts at -20 for double flat but we enumerate from 0 + + + #keysig = api.majorKeySignature(selectedRootPitch) #we deal with deviation from the major scale so we need the major scale for that root note + plainPitch = plain(stepInMajorRootScale + mod) + + pitchOk = diatonicIndex(stepInMajorRootScale) == diatonicIndex(plainPitch) #did we cross a diatonic note boundary? That means this was a triple accidental + + return plainPitch, pitchOk + + + + def sanityCheck(self, buttonChecked:bool): + """Called after every change to the whole widget. + Recalculates note names and checks if any of the steps result in triple accidentals. + + We choose signal:clicked because signal:toggled triggers this signal twice because + for each radio toggle another radio button get's deactivated automatically.""" + + for groupIndex, group in enumerate(self.scaleButtons): + #Sanity check. Check for triple accidentals + for counter, button in enumerate(reversed(group)): + plainPitch, pitchOk = self.groupToInScalePitch(groupIndex, counter) + if pitchOk: + button.setEnabled(True) + else: + button.setEnabled(False) + if button.isChecked(): + button.setChecked(False) #setChecked does NOT activate the clicked signal. We are safe from recursive calls. + group[2].setChecked(True) #Activate natural as fallback + + #Calculate Labels + plainPitch, pitchOk = self.groupToInScalePitch(groupIndex) + assert pitchOk + self.resultLabels[groupIndex].setText(baseNotesToAccidentalNames[plainPitch]) + + + def process(self): + selectedRootPitch = self.findRootPitch() + + #Gather selected scale into engine scale list, which is the deviation from the major scale. + #THIS IS A RELATIVE SCALE, not accidentals for notes. The GUI shows roman numerals for scale building, not note names. + #-20 is double flat, -10 is flat, 0 is natural, 10 is sharp, 20 is double sharp + #self.scaleButtons is semi-correctly ordered: ascending scale (outer list) but from double sharp to double flat (inner list). we reverse the latter + deviationFromMajorScale = [] + for group in self.scaleButtons: + for counter, button in enumerate(reversed(group)): + if button.isChecked(): + deviationFromMajorScale.append(10*counter -20) + + api.insertKeySignature(root=selectedRootPitch, scheme=deviationFromMajorScale) + + self.done(True) diff --git a/qtgui/designer/customKeySignature.py b/qtgui/designer/customKeySignature.py new file mode 100644 index 0000000..dd3ecfb --- /dev/null +++ b/qtgui/designer/customKeySignature.py @@ -0,0 +1,396 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'customKeySignature.ui' +# +# Created by: PyQt5 UI code generator 5.15.6 +# +# WARNING: Any manual changes made to this file will be lost when pyuic5 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_customKeySignature(object): + def setupUi(self, customKeySignature): + customKeySignature.setObjectName("customKeySignature") + customKeySignature.resize(517, 533) + self.verticalLayout_8 = QtWidgets.QVBoxLayout(customKeySignature) + self.verticalLayout_8.setSpacing(12) + self.verticalLayout_8.setObjectName("verticalLayout_8") + self.keysig_instruction_label = QtWidgets.QLabel(customKeySignature) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.keysig_instruction_label.sizePolicy().hasHeightForWidth()) + self.keysig_instruction_label.setSizePolicy(sizePolicy) + self.keysig_instruction_label.setWordWrap(True) + self.keysig_instruction_label.setObjectName("keysig_instruction_label") + self.verticalLayout_8.addWidget(self.keysig_instruction_label) + self.group_root = QtWidgets.QGroupBox(customKeySignature) + self.group_root.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) + self.group_root.setObjectName("group_root") + self.gridLayout = QtWidgets.QGridLayout(self.group_root) + self.gridLayout.setObjectName("gridLayout") + self.root_dis = QtWidgets.QRadioButton(self.group_root) + self.root_dis.setObjectName("root_dis") + self.gridLayout.addWidget(self.root_dis, 4, 1, 1, 1) + self.root_des = QtWidgets.QRadioButton(self.group_root) + self.root_des.setObjectName("root_des") + self.gridLayout.addWidget(self.root_des, 2, 1, 1, 1) + self.root_ees = QtWidgets.QRadioButton(self.group_root) + self.root_ees.setObjectName("root_ees") + self.gridLayout.addWidget(self.root_ees, 2, 2, 1, 1) + self.root_b = QtWidgets.QRadioButton(self.group_root) + self.root_b.setObjectName("root_b") + self.gridLayout.addWidget(self.root_b, 0, 6, 1, 1) + self.root_fes = QtWidgets.QRadioButton(self.group_root) + self.root_fes.setObjectName("root_fes") + self.gridLayout.addWidget(self.root_fes, 2, 3, 1, 1) + self.root_f = QtWidgets.QRadioButton(self.group_root) + self.root_f.setObjectName("root_f") + self.gridLayout.addWidget(self.root_f, 0, 3, 1, 1) + self.root_eis = QtWidgets.QRadioButton(self.group_root) + self.root_eis.setObjectName("root_eis") + self.gridLayout.addWidget(self.root_eis, 4, 2, 1, 1) + self.root_gis = QtWidgets.QRadioButton(self.group_root) + self.root_gis.setObjectName("root_gis") + self.gridLayout.addWidget(self.root_gis, 4, 4, 1, 1) + self.root_bes = QtWidgets.QRadioButton(self.group_root) + self.root_bes.setObjectName("root_bes") + self.gridLayout.addWidget(self.root_bes, 2, 6, 1, 1) + self.root_d = QtWidgets.QRadioButton(self.group_root) + self.root_d.setObjectName("root_d") + self.gridLayout.addWidget(self.root_d, 0, 1, 1, 1) + self.root_fis = QtWidgets.QRadioButton(self.group_root) + self.root_fis.setObjectName("root_fis") + self.gridLayout.addWidget(self.root_fis, 4, 3, 1, 1) + self.root_g = QtWidgets.QRadioButton(self.group_root) + self.root_g.setObjectName("root_g") + self.gridLayout.addWidget(self.root_g, 0, 4, 1, 1) + self.root_ces = QtWidgets.QRadioButton(self.group_root) + self.root_ces.setObjectName("root_ces") + self.gridLayout.addWidget(self.root_ces, 2, 0, 1, 1) + self.root_ais = QtWidgets.QRadioButton(self.group_root) + self.root_ais.setObjectName("root_ais") + self.gridLayout.addWidget(self.root_ais, 4, 5, 1, 1) + self.root_ges = QtWidgets.QRadioButton(self.group_root) + self.root_ges.setObjectName("root_ges") + self.gridLayout.addWidget(self.root_ges, 2, 4, 1, 1) + self.root_cis = QtWidgets.QRadioButton(self.group_root) + self.root_cis.setObjectName("root_cis") + self.gridLayout.addWidget(self.root_cis, 4, 0, 1, 1) + self.root_a = QtWidgets.QRadioButton(self.group_root) + self.root_a.setObjectName("root_a") + self.gridLayout.addWidget(self.root_a, 0, 5, 1, 1) + self.root_c = QtWidgets.QRadioButton(self.group_root) + self.root_c.setChecked(True) + self.root_c.setObjectName("root_c") + self.gridLayout.addWidget(self.root_c, 0, 0, 1, 1) + self.root_e = QtWidgets.QRadioButton(self.group_root) + self.root_e.setObjectName("root_e") + self.gridLayout.addWidget(self.root_e, 0, 2, 1, 1) + self.root_aes = QtWidgets.QRadioButton(self.group_root) + self.root_aes.setObjectName("root_aes") + self.gridLayout.addWidget(self.root_aes, 2, 5, 1, 1) + self.root_bis = QtWidgets.QRadioButton(self.group_root) + self.root_bis.setObjectName("root_bis") + self.gridLayout.addWidget(self.root_bis, 4, 6, 1, 1) + self.verticalLayout_8.addWidget(self.group_root) + self.group_accidentals = QtWidgets.QGroupBox(customKeySignature) + self.group_accidentals.setObjectName("group_accidentals") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.group_accidentals) + self.horizontalLayout.setObjectName("horizontalLayout") + self.group_c = QtWidgets.QGroupBox(self.group_accidentals) + self.group_c.setAlignment(QtCore.Qt.AlignCenter) + self.group_c.setObjectName("group_c") + self.verticalLayout = QtWidgets.QVBoxLayout(self.group_c) + self.verticalLayout.setSpacing(0) + self.verticalLayout.setObjectName("verticalLayout") + self.isis_c = QtWidgets.QRadioButton(self.group_c) + self.isis_c.setObjectName("isis_c") + self.verticalLayout.addWidget(self.isis_c) + self.is_c = QtWidgets.QRadioButton(self.group_c) + self.is_c.setObjectName("is_c") + self.verticalLayout.addWidget(self.is_c) + self.nat_c = QtWidgets.QRadioButton(self.group_c) + self.nat_c.setChecked(True) + self.nat_c.setObjectName("nat_c") + self.verticalLayout.addWidget(self.nat_c) + self.es_c = QtWidgets.QRadioButton(self.group_c) + self.es_c.setObjectName("es_c") + self.verticalLayout.addWidget(self.es_c) + self.eses_c = QtWidgets.QRadioButton(self.group_c) + self.eses_c.setObjectName("eses_c") + self.verticalLayout.addWidget(self.eses_c) + spacerItem = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + self.verticalLayout.addItem(spacerItem) + self.label_result_c = QtWidgets.QLabel(self.group_c) + self.label_result_c.setAlignment(QtCore.Qt.AlignCenter) + self.label_result_c.setObjectName("label_result_c") + self.verticalLayout.addWidget(self.label_result_c) + self.horizontalLayout.addWidget(self.group_c) + self.groupd_d = QtWidgets.QGroupBox(self.group_accidentals) + self.groupd_d.setAlignment(QtCore.Qt.AlignCenter) + self.groupd_d.setObjectName("groupd_d") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.groupd_d) + self.verticalLayout_2.setSpacing(0) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.isis_d = QtWidgets.QRadioButton(self.groupd_d) + self.isis_d.setObjectName("isis_d") + self.verticalLayout_2.addWidget(self.isis_d) + self.is_d = QtWidgets.QRadioButton(self.groupd_d) + self.is_d.setObjectName("is_d") + self.verticalLayout_2.addWidget(self.is_d) + self.nat_d = QtWidgets.QRadioButton(self.groupd_d) + self.nat_d.setChecked(True) + self.nat_d.setObjectName("nat_d") + self.verticalLayout_2.addWidget(self.nat_d) + self.es_d = QtWidgets.QRadioButton(self.groupd_d) + self.es_d.setObjectName("es_d") + self.verticalLayout_2.addWidget(self.es_d) + self.eses_d = QtWidgets.QRadioButton(self.groupd_d) + self.eses_d.setObjectName("eses_d") + self.verticalLayout_2.addWidget(self.eses_d) + spacerItem1 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + self.verticalLayout_2.addItem(spacerItem1) + self.label_result_d = QtWidgets.QLabel(self.groupd_d) + self.label_result_d.setAlignment(QtCore.Qt.AlignCenter) + self.label_result_d.setObjectName("label_result_d") + self.verticalLayout_2.addWidget(self.label_result_d) + self.horizontalLayout.addWidget(self.groupd_d) + self.group_e = QtWidgets.QGroupBox(self.group_accidentals) + self.group_e.setAlignment(QtCore.Qt.AlignCenter) + self.group_e.setObjectName("group_e") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.group_e) + self.verticalLayout_3.setSpacing(0) + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.isis_e = QtWidgets.QRadioButton(self.group_e) + self.isis_e.setObjectName("isis_e") + self.verticalLayout_3.addWidget(self.isis_e) + self.is_e = QtWidgets.QRadioButton(self.group_e) + self.is_e.setObjectName("is_e") + self.verticalLayout_3.addWidget(self.is_e) + self.nat_e = QtWidgets.QRadioButton(self.group_e) + self.nat_e.setChecked(True) + self.nat_e.setObjectName("nat_e") + self.verticalLayout_3.addWidget(self.nat_e) + self.es_e = QtWidgets.QRadioButton(self.group_e) + self.es_e.setObjectName("es_e") + self.verticalLayout_3.addWidget(self.es_e) + self.eses_e = QtWidgets.QRadioButton(self.group_e) + self.eses_e.setObjectName("eses_e") + self.verticalLayout_3.addWidget(self.eses_e) + spacerItem2 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + self.verticalLayout_3.addItem(spacerItem2) + self.label_result_e = QtWidgets.QLabel(self.group_e) + self.label_result_e.setAlignment(QtCore.Qt.AlignCenter) + self.label_result_e.setObjectName("label_result_e") + self.verticalLayout_3.addWidget(self.label_result_e) + self.horizontalLayout.addWidget(self.group_e) + self.group_f = QtWidgets.QGroupBox(self.group_accidentals) + self.group_f.setAlignment(QtCore.Qt.AlignCenter) + self.group_f.setObjectName("group_f") + self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.group_f) + self.verticalLayout_5.setSpacing(0) + self.verticalLayout_5.setObjectName("verticalLayout_5") + self.isis_f = QtWidgets.QRadioButton(self.group_f) + self.isis_f.setObjectName("isis_f") + self.verticalLayout_5.addWidget(self.isis_f) + self.is_f = QtWidgets.QRadioButton(self.group_f) + self.is_f.setObjectName("is_f") + self.verticalLayout_5.addWidget(self.is_f) + self.nat_f = QtWidgets.QRadioButton(self.group_f) + self.nat_f.setChecked(True) + self.nat_f.setObjectName("nat_f") + self.verticalLayout_5.addWidget(self.nat_f) + self.es_f = QtWidgets.QRadioButton(self.group_f) + self.es_f.setObjectName("es_f") + self.verticalLayout_5.addWidget(self.es_f) + self.eses_f = QtWidgets.QRadioButton(self.group_f) + self.eses_f.setObjectName("eses_f") + self.verticalLayout_5.addWidget(self.eses_f) + spacerItem3 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + self.verticalLayout_5.addItem(spacerItem3) + self.label_result_f = QtWidgets.QLabel(self.group_f) + self.label_result_f.setAlignment(QtCore.Qt.AlignCenter) + self.label_result_f.setObjectName("label_result_f") + self.verticalLayout_5.addWidget(self.label_result_f) + self.horizontalLayout.addWidget(self.group_f) + self.group_g = QtWidgets.QGroupBox(self.group_accidentals) + self.group_g.setAlignment(QtCore.Qt.AlignCenter) + self.group_g.setObjectName("group_g") + self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.group_g) + self.verticalLayout_6.setSpacing(0) + self.verticalLayout_6.setObjectName("verticalLayout_6") + self.isis_g = QtWidgets.QRadioButton(self.group_g) + self.isis_g.setObjectName("isis_g") + self.verticalLayout_6.addWidget(self.isis_g) + self.is_g = QtWidgets.QRadioButton(self.group_g) + self.is_g.setObjectName("is_g") + self.verticalLayout_6.addWidget(self.is_g) + self.nat_g = QtWidgets.QRadioButton(self.group_g) + self.nat_g.setChecked(True) + self.nat_g.setObjectName("nat_g") + self.verticalLayout_6.addWidget(self.nat_g) + self.es_g = QtWidgets.QRadioButton(self.group_g) + self.es_g.setObjectName("es_g") + self.verticalLayout_6.addWidget(self.es_g) + self.eses_g = QtWidgets.QRadioButton(self.group_g) + self.eses_g.setObjectName("eses_g") + self.verticalLayout_6.addWidget(self.eses_g) + spacerItem4 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + self.verticalLayout_6.addItem(spacerItem4) + self.label_result_g = QtWidgets.QLabel(self.group_g) + self.label_result_g.setAlignment(QtCore.Qt.AlignCenter) + self.label_result_g.setObjectName("label_result_g") + self.verticalLayout_6.addWidget(self.label_result_g) + self.horizontalLayout.addWidget(self.group_g) + self.group_a = QtWidgets.QGroupBox(self.group_accidentals) + self.group_a.setAlignment(QtCore.Qt.AlignCenter) + self.group_a.setObjectName("group_a") + self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.group_a) + self.verticalLayout_4.setSpacing(0) + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.isis_a = QtWidgets.QRadioButton(self.group_a) + self.isis_a.setObjectName("isis_a") + self.verticalLayout_4.addWidget(self.isis_a) + self.is_a = QtWidgets.QRadioButton(self.group_a) + self.is_a.setObjectName("is_a") + self.verticalLayout_4.addWidget(self.is_a) + self.nat_a = QtWidgets.QRadioButton(self.group_a) + self.nat_a.setChecked(True) + self.nat_a.setObjectName("nat_a") + self.verticalLayout_4.addWidget(self.nat_a) + self.es_a = QtWidgets.QRadioButton(self.group_a) + self.es_a.setObjectName("es_a") + self.verticalLayout_4.addWidget(self.es_a) + self.eses_a = QtWidgets.QRadioButton(self.group_a) + self.eses_a.setObjectName("eses_a") + self.verticalLayout_4.addWidget(self.eses_a) + spacerItem5 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + self.verticalLayout_4.addItem(spacerItem5) + self.label_result_a = QtWidgets.QLabel(self.group_a) + self.label_result_a.setAlignment(QtCore.Qt.AlignCenter) + self.label_result_a.setObjectName("label_result_a") + self.verticalLayout_4.addWidget(self.label_result_a) + self.horizontalLayout.addWidget(self.group_a) + self.group_b = QtWidgets.QGroupBox(self.group_accidentals) + self.group_b.setAlignment(QtCore.Qt.AlignCenter) + self.group_b.setObjectName("group_b") + self.verticalLayout_7 = QtWidgets.QVBoxLayout(self.group_b) + self.verticalLayout_7.setSpacing(0) + self.verticalLayout_7.setObjectName("verticalLayout_7") + self.isis_b = QtWidgets.QRadioButton(self.group_b) + self.isis_b.setObjectName("isis_b") + self.verticalLayout_7.addWidget(self.isis_b) + self.is_b = QtWidgets.QRadioButton(self.group_b) + self.is_b.setObjectName("is_b") + self.verticalLayout_7.addWidget(self.is_b) + self.nat_b = QtWidgets.QRadioButton(self.group_b) + self.nat_b.setChecked(True) + self.nat_b.setObjectName("nat_b") + self.verticalLayout_7.addWidget(self.nat_b) + self.es_b = QtWidgets.QRadioButton(self.group_b) + self.es_b.setObjectName("es_b") + self.verticalLayout_7.addWidget(self.es_b) + self.eses_b = QtWidgets.QRadioButton(self.group_b) + self.eses_b.setObjectName("eses_b") + self.verticalLayout_7.addWidget(self.eses_b) + spacerItem6 = QtWidgets.QSpacerItem(20, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) + self.verticalLayout_7.addItem(spacerItem6) + self.label_result_b = QtWidgets.QLabel(self.group_b) + self.label_result_b.setAlignment(QtCore.Qt.AlignCenter) + self.label_result_b.setObjectName("label_result_b") + self.verticalLayout_7.addWidget(self.label_result_b) + self.horizontalLayout.addWidget(self.group_b) + self.verticalLayout_8.addWidget(self.group_accidentals) + self.buttonBox = QtWidgets.QDialogButtonBox(customKeySignature) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.verticalLayout_8.addWidget(self.buttonBox) + spacerItem7 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.verticalLayout_8.addItem(spacerItem7) + + self.retranslateUi(customKeySignature) + self.buttonBox.accepted.connect(customKeySignature.accept) # type: ignore + self.buttonBox.rejected.connect(customKeySignature.reject) # type: ignore + QtCore.QMetaObject.connectSlotsByName(customKeySignature) + + def retranslateUi(self, customKeySignature): + _translate = QtCore.QCoreApplication.translate + customKeySignature.setWindowTitle(_translate("customKeySignature", "Custom Key Signature")) + self.keysig_instruction_label.setText(_translate("customKeySignature", "

Design your own scale. The key signature will be calculated. Choose a root note and how each step deviates from it\'s major scale. E.g. leaving all switches on "natural" will result in the major scale. Setting step III to flat will result in "melodic minor".

Not all combinations are possible: e.g. root G with step VII double sharp.
G-Major\'s "natural" VII is already f-sharp, thus choosing a normal sharp already results in a key signature with a double sharp "cross". Switching VII to double sharp would result in a "triple sharp" key signature.

")) + self.group_root.setTitle(_translate("customKeySignature", "Root Note")) + self.root_dis.setText(_translate("customKeySignature", "D♯")) + self.root_des.setText(_translate("customKeySignature", "D♭")) + self.root_ees.setText(_translate("customKeySignature", "E♭")) + self.root_b.setText(_translate("customKeySignature", "B / H")) + self.root_fes.setText(_translate("customKeySignature", "F♭")) + self.root_f.setText(_translate("customKeySignature", "F")) + self.root_eis.setText(_translate("customKeySignature", "E♯")) + self.root_gis.setText(_translate("customKeySignature", "G♯")) + self.root_bes.setText(_translate("customKeySignature", "B♭ / H♭")) + self.root_d.setText(_translate("customKeySignature", "D")) + self.root_fis.setText(_translate("customKeySignature", "F♯")) + self.root_g.setText(_translate("customKeySignature", "G")) + self.root_ces.setText(_translate("customKeySignature", "C♭")) + self.root_ais.setText(_translate("customKeySignature", "A♯")) + self.root_ges.setText(_translate("customKeySignature", "G♭")) + self.root_cis.setText(_translate("customKeySignature", "C♯")) + self.root_a.setText(_translate("customKeySignature", "A")) + self.root_c.setText(_translate("customKeySignature", "C")) + self.root_e.setText(_translate("customKeySignature", "E")) + self.root_aes.setText(_translate("customKeySignature", "A♭")) + self.root_bis.setText(_translate("customKeySignature", "B♯ / H♯")) + self.group_accidentals.setTitle(_translate("customKeySignature", "Scale - Deviation from the Major Scale")) + self.group_c.setTitle(_translate("customKeySignature", "Ⅰ")) + self.isis_c.setText(_translate("customKeySignature", "𝄪")) + self.is_c.setText(_translate("customKeySignature", "♯")) + self.nat_c.setText(_translate("customKeySignature", "♮")) + self.es_c.setText(_translate("customKeySignature", "♭")) + self.eses_c.setText(_translate("customKeySignature", "𝄫")) + self.label_result_c.setText(_translate("customKeySignature", "c")) + self.groupd_d.setTitle(_translate("customKeySignature", "Ⅱ")) + self.isis_d.setText(_translate("customKeySignature", "𝄪")) + self.is_d.setText(_translate("customKeySignature", "♯")) + self.nat_d.setText(_translate("customKeySignature", "♮")) + self.es_d.setText(_translate("customKeySignature", "♭")) + self.eses_d.setText(_translate("customKeySignature", "𝄫")) + self.label_result_d.setText(_translate("customKeySignature", "d")) + self.group_e.setTitle(_translate("customKeySignature", "Ⅲ")) + self.isis_e.setText(_translate("customKeySignature", "𝄪")) + self.is_e.setText(_translate("customKeySignature", "♯")) + self.nat_e.setText(_translate("customKeySignature", "♮")) + self.es_e.setText(_translate("customKeySignature", "♭")) + self.eses_e.setText(_translate("customKeySignature", "𝄫")) + self.label_result_e.setText(_translate("customKeySignature", "e")) + self.group_f.setTitle(_translate("customKeySignature", "Ⅳ")) + self.isis_f.setText(_translate("customKeySignature", "𝄪")) + self.is_f.setText(_translate("customKeySignature", "♯")) + self.nat_f.setText(_translate("customKeySignature", "♮")) + self.es_f.setText(_translate("customKeySignature", "♭")) + self.eses_f.setText(_translate("customKeySignature", "𝄫")) + self.label_result_f.setText(_translate("customKeySignature", "f")) + self.group_g.setTitle(_translate("customKeySignature", "Ⅴ")) + self.isis_g.setText(_translate("customKeySignature", "𝄪")) + self.is_g.setText(_translate("customKeySignature", "♯")) + self.nat_g.setText(_translate("customKeySignature", "♮")) + self.es_g.setText(_translate("customKeySignature", "♭")) + self.eses_g.setText(_translate("customKeySignature", "𝄫")) + self.label_result_g.setText(_translate("customKeySignature", "g")) + self.group_a.setTitle(_translate("customKeySignature", "Ⅵ")) + self.isis_a.setText(_translate("customKeySignature", "𝄪")) + self.is_a.setText(_translate("customKeySignature", "♯")) + self.nat_a.setText(_translate("customKeySignature", "♮")) + self.es_a.setText(_translate("customKeySignature", "♭")) + self.eses_a.setText(_translate("customKeySignature", "𝄫")) + self.label_result_a.setText(_translate("customKeySignature", "a")) + self.group_b.setTitle(_translate("customKeySignature", "Ⅶ")) + self.isis_b.setText(_translate("customKeySignature", "𝄪")) + self.is_b.setText(_translate("customKeySignature", "♯")) + self.nat_b.setText(_translate("customKeySignature", "♮")) + self.es_b.setText(_translate("customKeySignature", "♭")) + self.eses_b.setText(_translate("customKeySignature", "𝄫")) + self.label_result_b.setText(_translate("customKeySignature", "b")) diff --git a/qtgui/designer/customKeySignature.ui b/qtgui/designer/customKeySignature.ui new file mode 100644 index 0000000..74a8a3a --- /dev/null +++ b/qtgui/designer/customKeySignature.ui @@ -0,0 +1,820 @@ + + + customKeySignature + + + + 0 + 0 + 517 + 533 + + + + Custom Key Signature + + + + 12 + + + + + + 0 + 0 + + + + <html><head/><body><p>Design your own scale. The key signature will be calculated. Choose a root note and how each step deviates from it's major scale. E.g. leaving all switches on &quot;natural&quot; will result in the major scale. Setting step III to flat will result in &quot;melodic minor&quot;.</p><p>Not all combinations are possible: e.g. root G with step VII double sharp. <br/>G-Major's &quot;natural&quot; VII is already f-sharp, thus choosing a normal sharp already results in a key signature with a double sharp &quot;cross&quot;. Switching VII to double sharp would result in a &quot;triple sharp&quot; key signature.<br/></p></body></html> + + + true + + + + + + + Root Note + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + D♯ + + + + + + + D♭ + + + + + + + E♭ + + + + + + + B / H + + + + + + + F♭ + + + + + + + F + + + + + + + E♯ + + + + + + + G♯ + + + + + + + B♭ / H♭ + + + + + + + D + + + + + + + F♯ + + + + + + + G + + + + + + + C♭ + + + + + + + A♯ + + + + + + + G♭ + + + + + + + C♯ + + + + + + + A + + + + + + + C + + + true + + + + + + + E + + + + + + + A♭ + + + + + + + B♯ / H♯ + + + + + + + + + + Scale - Deviation from the Major Scale + + + + + + + + + Qt::AlignCenter + + + + 0 + + + + + 𝄪 + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + 𝄫 + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + c + + + Qt::AlignCenter + + + + + + + + + + + + + Qt::AlignCenter + + + + 0 + + + + + 𝄪 + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + 𝄫 + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + d + + + Qt::AlignCenter + + + + + + + + + + + + + Qt::AlignCenter + + + + 0 + + + + + 𝄪 + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + 𝄫 + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + e + + + Qt::AlignCenter + + + + + + + + + + + + + Qt::AlignCenter + + + + 0 + + + + + 𝄪 + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + 𝄫 + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + f + + + Qt::AlignCenter + + + + + + + + + + + + + Qt::AlignCenter + + + + 0 + + + + + 𝄪 + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + 𝄫 + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + g + + + Qt::AlignCenter + + + + + + + + + + + + + Qt::AlignCenter + + + + 0 + + + + + 𝄪 + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + 𝄫 + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + a + + + Qt::AlignCenter + + + + + + + + + + + + + Qt::AlignCenter + + + + 0 + + + + + 𝄪 + + + + + + + + + + + + + + + + + true + + + + + + + + + + + + + + 𝄫 + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + b + + + Qt::AlignCenter + + + + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + buttonBox + accepted() + customKeySignature + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + customKeySignature + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/qtgui/designer/mainwindow.py b/qtgui/designer/mainwindow.py index 06d6020..0e4f2a7 100644 --- a/qtgui/designer/mainwindow.py +++ b/qtgui/designer/mainwindow.py @@ -647,7 +647,6 @@ class Ui_MainWindow(object): self.actionUse_Current_Track_as_Metronome.setObjectName("actionUse_Current_Track_as_Metronome") self.actionMetronome_Enabled = QtWidgets.QAction(MainWindow) self.actionMetronome_Enabled.setCheckable(True) - self.actionMetronome_Enabled.setShortcut("Alt+U") self.actionMetronome_Enabled.setObjectName("actionMetronome_Enabled") self.actionRandom_in_scale_in_cursor_plus_octave = QtWidgets.QAction(MainWindow) self.actionRandom_in_scale_in_cursor_plus_octave.setObjectName("actionRandom_in_scale_in_cursor_plus_octave") @@ -688,9 +687,15 @@ class Ui_MainWindow(object): self.actionPaste_real_transposed.setObjectName("actionPaste_real_transposed") self.actionCustom_Multi_Measure_Rest = QtWidgets.QAction(MainWindow) self.actionCustom_Multi_Measure_Rest.setObjectName("actionCustom_Multi_Measure_Rest") + self.actionCustom_Key_Signature = QtWidgets.QAction(MainWindow) + self.actionCustom_Key_Signature.setObjectName("actionCustom_Key_Signature") + self.actionCustom_Metrical_Instruction = QtWidgets.QAction(MainWindow) + self.actionCustom_Metrical_Instruction.setObjectName("actionCustom_Metrical_Instruction") self.menuObjects.addAction(self.actionMetrical_Instruction) + self.menuObjects.addAction(self.actionCustom_Metrical_Instruction) self.menuObjects.addAction(self.actionClef) self.menuObjects.addAction(self.actionKey_Signature) + self.menuObjects.addAction(self.actionCustom_Key_Signature) self.menuObjects.addSeparator() self.menuObjects.addAction(self.actionDynamics) self.menuObjects.addAction(self.actionMulti_Measure_Rest) @@ -906,7 +911,7 @@ class Ui_MainWindow(object): self.menuView.setTitle(_translate("MainWindow", "&Control")) self.menuMode.setTitle(_translate("MainWindow", "&View and Edit Mode")) self.menu.setTitle(_translate("MainWindow", "|")) - self.menuEdit_MusicItem.setTitle(_translate("MainWindow", "Edit &MusicItem")) + self.menuEdit_MusicItem.setTitle(_translate("MainWindow", "Edit MusicIt&em")) self.menuEdit_2.setTitle(_translate("MainWindow", "E&dit")) self.menuToolbox.setTitle(_translate("MainWindow", "&Toolbox")) self.menuOrder.setTitle(_translate("MainWindow", "Note &Sorting")) @@ -1018,6 +1023,7 @@ class Ui_MainWindow(object): self.actionDelete_Current_Track.setText(_translate("MainWindow", "Delete Current Track")) self.actionUse_Current_Track_as_Metronome.setText(_translate("MainWindow", "Use Current Track as &Metronome")) self.actionMetronome_Enabled.setText(_translate("MainWindow", "Metronome &Enabled")) + self.actionMetronome_Enabled.setShortcut(_translate("MainWindow", "Ctrl+U")) self.actionRandom_in_scale_in_cursor_plus_octave.setText(_translate("MainWindow", "Random in-scale in cursor plus octave (authentic mode)")) self.actionRandom_in_scale_in_octave_around_cursor.setText(_translate("MainWindow", "Random in-scale in octave around cursor (hypo mode)")) self.actionLyBarline.setText(_translate("MainWindow", "Barline")) @@ -1044,3 +1050,7 @@ class Ui_MainWindow(object): self.actionPaste_real_transposed.setText(_translate("MainWindow", "Paste real transposed")) self.actionCustom_Multi_Measure_Rest.setText(_translate("MainWindow", "Custom Multi Measure Rest")) self.actionCustom_Multi_Measure_Rest.setShortcut(_translate("MainWindow", "Alt+R")) + self.actionCustom_Key_Signature.setText(_translate("MainWindow", "Custom Key Signature")) + self.actionCustom_Key_Signature.setShortcut(_translate("MainWindow", "Alt+K")) + self.actionCustom_Metrical_Instruction.setText(_translate("MainWindow", "Custom Metrical Instruction")) + self.actionCustom_Metrical_Instruction.setShortcut(_translate("MainWindow", "Alt+M")) diff --git a/qtgui/designer/mainwindow.ui b/qtgui/designer/mainwindow.ui index 05b589d..c894217 100644 --- a/qtgui/designer/mainwindow.ui +++ b/qtgui/designer/mainwindow.ui @@ -59,8 +59,10 @@ &Insert Objects + + @@ -254,7 +256,7 @@ - Edit &MusicItem + Edit MusicIt&em @@ -1708,7 +1710,7 @@ Metronome &Enabled - Alt+U + Ctrl+U @@ -1834,6 +1836,22 @@ Alt+R + + + Custom Key Signature + + + Alt+K + + + + + Custom Metrical Instruction + + + Alt+M + + diff --git a/qtgui/items.py b/qtgui/items.py index cfd1182..28d3161 100644 --- a/qtgui/items.py +++ b/qtgui/items.py @@ -634,7 +634,7 @@ class GuiKeySignature(GuiItem): self.bigNatural.setParentItem(self) self.bigNatural.setPos(constantsAndConfigs.magicPixel, constantsAndConfigs.stafflineGap * -1) - self.rootGlyph = QtWidgets.QGraphicsSimpleTextItem(pitch.baseNotesToBaseNames[self.staticItem["root"]]) + self.rootGlyph = QtWidgets.QGraphicsSimpleTextItem(pitch.baseNotesToAccidentalNames[self.staticItem["root"]]) self.rootGlyph.setParentItem(self) self.rootGlyph.setPos(constantsAndConfigs.negativeMagicPixel, 2*constantsAndConfigs.stafflineGap) @@ -645,6 +645,10 @@ class GuiKeySignature(GuiItem): 20 : lambda: QtSvg.QGraphicsSvgItem(":svg/accidentalsDoublesharp.svg"), -10 : lambda: QtSvg.QGraphicsSvgItem(":svg/accidentalsFlat.svg"), -20 : lambda: QtSvg.QGraphicsSvgItem(":svg/accidentalsFlatFlat.svg"), + + #TODO: Triple Sharps and Flats are not supported. But better wrong glyph than a crash: + -30 : lambda: QtSvg.QGraphicsSvgItem(":svg/accidentalsNatural.svg"), + 30 : lambda: QtSvg.QGraphicsSvgItem(":svg/accidentalsNatural.svg"), } class GuiClef(GuiItem): @@ -710,6 +714,7 @@ class GuiMetricalInstruction(GuiItem): def __init__(self, staticItem): super().__init__(staticItem) + print (staticItem) if staticItem["oneMeasureInTicks"] == 0: #Basically just a manual barline displayString = "X" diff --git a/qtgui/menu.py b/qtgui/menu.py index f1c4d34..9cc6cdf 100644 --- a/qtgui/menu.py +++ b/qtgui/menu.py @@ -38,6 +38,7 @@ import engine.api as api from engine.midiinput.stepmidiinput import stepMidiInput #singleton instance from .constantsAndConfigs import constantsAndConfigs from .submenus import SecondaryClefMenu, SecondaryKeySignatureMenu, SecondaryDynamicsMenu, SecondaryMetricalInstructionMenu, SecondaryTempoChangeMenu, SecondaryTemporaryTempoChangeMenu, SecondarySplitMenu, TransposeMenu, pedalNoteChooser, SecondaryProperties, SecondaryProgramChangeMenu, SecondaryChannelChangeMenu, ChooseOne, forwardText, SecondaryMultimeasureRestMenu +from .customkeysignature import CustomKeySignatureWidget class ModalKeys(object): def __init__(self): @@ -221,10 +222,14 @@ class MenuActionDatabase(object): self.mainWindow.ui.actionLegatoSlur : api.insertLegatoSlur, self.mainWindow.ui.actionClef : SecondaryClefMenu(self.mainWindow), #no lambda for submenus. They get created here once and have a __call__ option that executes them. There is no internal state in these menus. self.mainWindow.ui.actionKey_Signature : SecondaryKeySignatureMenu(self.mainWindow), + self.mainWindow.ui.actionCustom_Key_Signature : lambda: CustomKeySignatureWidget(self.mainWindow), + self.mainWindow.ui.actionDynamics : SecondaryDynamicsMenu(self.mainWindow), self.mainWindow.ui.actionMulti_Measure_Rest : lambda: api.insertMultiMeasureRest(1), self.mainWindow.ui.actionCustom_Multi_Measure_Rest : SecondaryMultimeasureRestMenu(self.mainWindow), self.mainWindow.ui.actionMetrical_Instruction : SecondaryMetricalInstructionMenu(self.mainWindow), + #self.mainWindow.ui.actionCustom_Metrical_Instruction : lambda: CustomMetricalInstructionWidget(self.mainWindow), + self.mainWindow.ui.actionCustom_Metrical_Instruction : api.metricalTest, self.mainWindow.ui.actionTempo_Change : lambda: SecondaryTempoChangeMenu(self.mainWindow), diff --git a/qtgui/tracklistwidget.py b/qtgui/tracklistwidget.py index e206b00..273cf09 100644 --- a/qtgui/tracklistwidget.py +++ b/qtgui/tracklistwidget.py @@ -114,10 +114,8 @@ class _TrackListWidget(QtWidgets.QListWidget): It only happens when the mouse etc. actually pressed an item. This list cannot be activated by cursor keys etc. directly. """ - api.toPosition(self.currentRow()) #currentRow is calculated after we already are on the item. - def syncTracks(self, listOfStaticTrackRepresentations): """Handles the number of tracks and track meta-data changes, but not track contents, which is handled by self.updateTrack through a different callback""" diff --git a/template/engine/pitch.py b/template/engine/pitch.py index 352bf25..ed7eb61 100644 --- a/template/engine/pitch.py +++ b/template/engine/pitch.py @@ -1006,7 +1006,7 @@ sortedNoteNameList = [ "bisis'''''" , ] -baseNotesToBaseNames = { +baseNotesToBaseLyNames = { 20 : "C", 70 : "D", 120 : "E", @@ -1021,7 +1021,15 @@ baseNotesToBaseNames = { 170-10 : "Fes", 220-10 : "Ges", 270-10 : "Aes", - 320-10 : "Bes/Bb", + 320-10 : "Bes", + + 20-20 : "Ceses", + 70-20 : "Deses", + 120-20 : "Eeses", + 170-20 : "Feses", + 220-20 : "Geses", + 270-20 : "Aeses", + 320-20 : "Beses", 20+10 : "Cis", 70+10 : "Dis", @@ -1029,7 +1037,57 @@ baseNotesToBaseNames = { 170+10 : "Fis", 220+10 : "Gis", 270+10 : "Ais", - 320+10 : "Bis/His", + 320+10 : "Bis", + + 20+20 : "Cisis", + 70+20 : "Disis", + 120+20 : "Eisis", + 170+20 : "Fisis", + 220+20 : "Gisis", + 270+20 : "Aisis", + 320+20 : "Bisis", + } + +baseNotesToAccidentalNames = { + 20 : "C", + 70 : "D", + 120 : "E", + 170 : "F", + 220 : "G", + 270 : "A", + 320 : "B♮/H", + + 20-10 : "C♭", + 70-10 : "D♭", + 120-10 : "E♭", + 170-10 : "F♭", + 220-10 : "G♭", + 270-10 : "A♭", + 320-10 : "B♭/H♭", + + 20-20 : "C𝄫", + 70-20 : "D𝄫", + 120-20 : "E𝄫", + 170-20 : "F𝄫", + 220-20 : "G𝄫", + 270-20 : "A𝄫", + 320-20 : "B𝄫/H𝄫", + + 20+10 : "C♯", + 70+10 : "D♯", + 120+10 : "E♯", + 170+10 : "F♯", + 220+10 : "G♯", + 270+10 : "A♯", + 320+10 : "B♯/H♯", + + 20+20 : "C𝄪", + 70+20 : "D𝄪", + 120+20 : "E𝄪", + 170+20 : "F𝄪", + 220+20 : "G𝄪", + 270+20 : "A𝄪", + 320+20 : "B𝄪/H𝄪", } orderedBaseNotes = ["C", "D", "E", "F", "G", "A", "H/B"]