diff --git a/engine/instrument.py b/engine/instrument.py index ad8767f..0aece73 100644 --- a/engine/instrument.py +++ b/engine/instrument.py @@ -122,6 +122,7 @@ class Instrument(object): self.currentKeySwitch:int = None # Midi pitch. Default is set on load. self.playableKeys:tuple = None #sorted tuple of ints. set by _parseKeys through chooseVariant. Set of int pitches. Used for export. + self.keyLabels = {60:"Middle C", 53:"𝄢", 67:"𝄞"} def exportStatus(self)->dict: """The call-often function to get the instrument status. Includes only data that can @@ -141,6 +142,7 @@ class Instrument(object): result["keySwitches"] = self.currentVariantKeySwitches[0] if self.currentVariantKeySwitches else {} #Internally this is a tuple with [0] being a dict: Unordered!! dict with midiPitch: (opcode, label). You need the opcode to see if it is a momentary switch or permanent. result["currentKeySwitch"] = self.currentKeySwitch result["playableKeys"] = self.playableKeys + result["keyLabels"] = self.keyLabels return result def exportMetadata(self)->dict: @@ -235,7 +237,7 @@ class Instrument(object): assert status.program_no == 0, status.program_no self.currentVariant = variantSfzFileName - self.currentVariantKeySwitches = self._parseKeyswitches() + self.currentVariantKeySwitches = self._parseKeyInfoAndLabels() if self.currentVariantKeySwitches and self.currentVariantKeySwitches[3]: #[3] is sw_default self.currentKeySwitch = self.currentVariantKeySwitches[3] else: @@ -243,7 +245,7 @@ class Instrument(object): logger.info(f"Finished loading samples for instrument {variantSfzFileName} with id key {self.idKey}") - def _parseKeyswitches(self): + def _parseKeyInfoAndLabels(self): """ Called only by chooseVariant. This is a function only for readability reasons and for the docstring. @@ -304,9 +306,9 @@ class Instrument(object): if "sw_label" in data: label = data["sw_label"] #remove leading int or key from label - mMidipitch = re.match("\d+", label) and not label[1] == "'" and not label[2] == "'" # 8' or 16' organs begin with a number as well. We sadly can't check for a space after the number so we have to check for the foot symbol + mMidipitch = re.match("\d+", label) mNotename = re.match("(c|(c#)|(db)|d|(d#)|(eb)|e|(e#)|(fb)|f|(f#)|(gb)|g|(g#)|(ab)|a|(a#)|(bb)|b|(b#))\d+", label, re.IGNORECASE) - if mMidipitch: #could be None + if mMidipitch and not label[1] == "'" and not label[2] == "'": # 8' or 16' organs begin with a number as well. We sadly can't check for a space after the number so we have to check for the foot symbol: #could be None label = label[mMidipitch.span()[1]:].lstrip() #remove number and potential leading space elif mNotename: label = label[mNotename.span()[1]:].lstrip() #remove notenames like C#6 and potential leading space @@ -375,7 +377,6 @@ class Instrument(object): findPlayableKeys(k3AsDict, allKeys) findKS(k3AsDict, result, others) - self.playableKeys = tuple(sorted(allKeys)) logger.info(f"Finished parsing possible keyswitches in the current variant/cbox-program for {self.name} {self.currentVariant}. Found: {len(result)} keyswitches.") if not result: diff --git a/qtgui/horizontalpiano.py b/qtgui/horizontalpiano.py index bf59988..222a14e 100644 --- a/qtgui/horizontalpiano.py +++ b/qtgui/horizontalpiano.py @@ -102,7 +102,7 @@ class _HorizontalPianoScene(QtWidgets.QGraphicsScene): numberX = x + 4 else: numberX = x - key.setPos(x, HEIGHT * -0.66) + key.setPos(x, HEIGHT * -0.7) key.setZValue(4) else: key = WhiteKey(self, i) @@ -181,6 +181,10 @@ class _HorizontalPianoScene(QtWidgets.QGraphicsScene): self.fakeDeactivationOverlay.hide() for keyPitch, keyObject in self.allKeys.items(): + + if keyPitch in instrumentStatus["keyLabels"]: + self.numberLabels[keyPitch].setLabel(instrumentStatus["keyLabels"][keyPitch]) #can be overwritten by keyswitch label. otherwise on any key, no matter if deactivated or not + if keyPitch in instrumentStatus["keySwitches"]: opcode, keyswitchLabel = instrumentStatus["keySwitches"][keyPitch] self.numberLabels[keyPitch].setLabel(keyswitchLabel) @@ -220,12 +224,12 @@ class _HorizontalPianoScene(QtWidgets.QGraphicsScene): self._leftMouseDown = True self._lastPlayPitch = None #this must not be in _play, otherwise you can't move the mouse while pressed down self._play(event) - super().mousePressEvent(event) + else: + super().mousePressEvent(event) def wheelEvent(self, event): event.ignore() #let the view handle it, for the scrollbar - def _off(self): if self._selectedInstrument and not self._lastPlayPitch is None: status, data = self._selectedInstrument @@ -236,9 +240,13 @@ class _HorizontalPianoScene(QtWidgets.QGraphicsScene): def _play(self, event): assert self._leftMouseDown - potentialItem = self.itemAt(event.scenePos(), self.parentView.transform() ) - if not (potentialItem and type(potentialItem) in (BlackKey, WhiteKey)): - return + potentialItems = self.items(event.scenePos() ) + + for potentialItem in potentialItems: + if type(potentialItem) in (BlackKey, WhiteKey): + break + else: + return #no item found. pitch = potentialItem.pitch @@ -278,16 +286,19 @@ class _HorizontalPianoScene(QtWidgets.QGraphicsScene): class NumberLabel(QtWidgets.QGraphicsSimpleTextItem): """In opposite to verticalPiano the key label is a different childItem as the number""" - def __init__(self, parentGrid, number:int): + def __init__(self, parentScene, number:int): super().__init__() - self.parentGrid = parentGrid + self.parentScene = parentScene self.number = number self.labelItem = QtWidgets.QGraphicsSimpleTextItem("") self.labelItem.setParentItem(self) + self.labelItem.setEnabled(False) self.currentLabel = "" self.setText(str(number)) self.setFlag(QtWidgets.QGraphicsItem.ItemIgnoresParentOpacity, True) + self.setEnabled(False) #Ignored? self.setAcceptedMouseButtons(QtCore.Qt.NoButton) + blackKey = number % 12 in (1, 3, 6, 8, 10) if blackKey: self.setBrush(QtGui.QColor("white")) @@ -310,9 +321,9 @@ class NumberLabel(QtWidgets.QGraphicsSimpleTextItem): class BlackKey(QtWidgets.QGraphicsRectItem): - def __init__(self, parentGrid, pitch): + def __init__(self, parentScene, pitch): super().__init__(0, 0, WIDTH * 0.8, HEIGHT) #x, y, w, h - self.parentGrid = parentGrid + self.parentScene = parentScene self.pitch = pitch self.setPen(QtGui.QPen(QtCore.Qt.NoPen)) self.setBrush(QtGui.QColor("black")) @@ -357,9 +368,9 @@ class BlackKey(QtWidgets.QGraphicsRectItem): self.highlight.hide() class WhiteKey(QtWidgets.QGraphicsRectItem): - def __init__(self, parentGrid, pitch:int): + def __init__(self, parentScene, pitch:int): super().__init__(0, 0, WIDTH, HEIGHT) #x, y, w, h - self.parentGrid = parentGrid + self.parentScene = parentScene self.pitch = pitch self.setPen(QtGui.QPen(QtCore.Qt.NoPen)) self.setBrush(QtGui.QColor("white")) @@ -367,21 +378,23 @@ class WhiteKey(QtWidgets.QGraphicsRectItem): self.setAcceptedMouseButtons(QtCore.Qt.NoButton) self.decorationOverlay = QtWidgets.QGraphicsRectItem(0, 0, WIDTH, HEIGHT) #x, y, w, h + self.decorationOverlay.setParentItem(self) self.decorationOverlay.setEnabled(False) self.decorationOverlay.setAcceptedMouseButtons(QtCore.Qt.NoButton) self.decorationOverlay.setFlag(QtWidgets.QGraphicsItem.ItemIgnoresParentOpacity, True) self.decorationOverlay.setOpacity(0.2) #just a tint self.decorationOverlay.hide() - self.decorationOverlay.setParentItem(self) + self.highlight = QtWidgets.QGraphicsRectItem(0, 0, WIDTH, HEIGHT) #x, y, w, h + self.highlight.setParentItem(self) self.highlight.setEnabled(False) self.highlight.setAcceptedMouseButtons(QtCore.Qt.NoButton) self.highlight.setFlag(QtWidgets.QGraphicsItem.ItemIgnoresParentOpacity, True) self.highlight.setOpacity(0.5) self.highlight.setBrush(QtGui.QColor("cyan")) self.highlight.hide() - self.highlight.setParentItem(self) + def setPlayable(self, state:bool): diff --git a/qtgui/verticalpiano.py b/qtgui/verticalpiano.py index b476393..658211b 100644 --- a/qtgui/verticalpiano.py +++ b/qtgui/verticalpiano.py @@ -188,6 +188,8 @@ class _VerticalPianoScene(QtWidgets.QGraphicsScene): #self.numberLabels[keyPitch].show() keyObject.show() + if keyPitch in instrumentStatus["keyLabels"]: + self.numberLabels[keyPitch].setLabel(instrumentStatus["keyLabels"][keyPitch]) #can be overwritten by keyswitch label. otherwise on any key, no matter if deactivated or not if keyPitch in instrumentStatus["keySwitches"]: opcode, keyswitchLabel = instrumentStatus["keySwitches"][keyPitch] self.numberLabels[keyPitch].setLabel(keyswitchLabel) @@ -198,7 +200,6 @@ class _VerticalPianoScene(QtWidgets.QGraphicsScene): #self.numberLabels[keyPitch].hide() keyObject.hide() - def selectedInstrumentChanged(self, instrumentStatus, instrumentData): """GUI click to different instrument. The arguments are cached GUI data