Browse Source

Add two new functions to paste directly transposed (modal and real transposition)

master
Nils 2 years ago
parent
commit
ffa96d68ef
  1. 1
      CHANGELOG
  2. 54
      engine/api.py
  3. 11
      engine/items.py
  4. 8
      engine/main.py
  5. 9
      qtgui/designer/mainwindow.py
  6. 15
      qtgui/designer/mainwindow.ui
  7. 2
      qtgui/menu.py

1
CHANGELOG

@ -6,6 +6,7 @@ External contributors notice at the end of the line: (LastName, FirstName / nick
## 2022-07-15 2.1.0 ## 2022-07-15 2.1.0
Add two new functions to paste directly transposed (modal and real transposition)
When not in F4-StepInput Mode use midi keyboard as pitch-cursor. When not in F4-StepInput Mode use midi keyboard as pitch-cursor.
Add midi-in selector drop down, as seen in Tembro and Fluajho. Add midi-in selector drop down, as seen in Tembro and Fluajho.
Rewrite grid, which was a performance drag in the past. Rewrite grid, which was a performance drag in the past.

54
engine/api.py

@ -504,7 +504,7 @@ def copyObjects(): #ctrl+c
#The score doesn't change at all. No callback. #The score doesn't change at all. No callback.
#no undo. #no undo.
def pasteObjects(customBuffer = None, updateCursor = True, overwriteSelection = True): #ctrl+v def pasteObjects(customBuffer=None, updateCursor=True, overwriteSelection=True): #ctrl+v
"""api.duplicate overrides default paste behaviour by providing its own copyBuffer """api.duplicate overrides default paste behaviour by providing its own copyBuffer
and not destroying the selection/keep the cursor at its origin position and not destroying the selection/keep the cursor at its origin position
""" """
@ -524,6 +524,58 @@ def pasteObjects(customBuffer = None, updateCursor = True, overwriteSelection =
if updateCursor: if updateCursor:
callbacks._setCursor() callbacks._setCursor()
def pasteObjectsTransposedReal(root:int=None, toPitch:int=None, adjustToKeySignature=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.
The notes are transformed into a custom buffer. We use standard paste for everything else.
If root or toPitch for the transposition interval are None they will derive their pitch from
the first pitch in the copy buffer and the cursor position, respectively.
"""
if not session.data.copyObjectsBuffer:
return #guard
copyBuffer = session.data.getIndenpendetCopyObjectsBuffer()
#Determine the first of the two pitches for our transposition interval
if root is None or not type(root) is int:
#First iteration only until the very first note, which we use to calculate the interval
for track in copyBuffer:
for item in track:
if type(item) is items.Chord:
root = item.notelist[0].pitch #ordered by ascending pitch
break
else: #inner loop finished without break. No chord? in the first track.
logging.warning("Found copy buffer without note in the first track. This is worth an investigation.")
continue #jump to the start and don't execute the outer loop break
break #outer loop. We only get here if the inner loop did break as well.
#Final Sanity Check. I don't think selections without chords are even allowed...
if root is None:
logging.error("pasteObjectsTransposedModal without notes in the copy buffer! (but not empty)")
return
if toPitch is None:
toPitch = getCursorPitch()
keysig = session.data.currentTrack().state.keySignature()
#Edit the copy buffer in place. We don't modify the list, just the contents.
for track in copyBuffer:
for item in track:
if type(item) is items.Chord:
item.intervalAutomatic(root, toPitch)
if adjustToKeySignature:
item.adjustToKeySignature([keysig,]) #keysig must be in a list because it is a chord. If it is just len==1 the transpose function will deal with it correctly.
pasteObjects(customBuffer=copyBuffer) #normal paste except our special buffer
def pasteObjectsTransposedModal(root:int=None, toPitch:int=None):
pasteObjectsTransposedReal(root, toPitch, adjustToKeySignature=True)
def duplicate(): #ctrl+d def duplicate(): #ctrl+d
"""Duplicate a single object and put it right of the original. The cursor moves with it """Duplicate a single object and put it right of the original. The cursor moves with it
to enable follow up insertion. to enable follow up insertion.

11
engine/items.py

@ -1467,10 +1467,19 @@ class Chord(Item):
note.duration.toggleDurationKeyword(next(gen)) note.duration.toggleDurationKeyword(next(gen))
return lambda: self._setDurationlist(oldValues) return lambda: self._setDurationlist(oldValues)
def stepUp(self, keysigList): def adjustToKeySignature(self, keysigList):
"""We get a list as parameter but we already know it is not """We get a list as parameter but we already know it is not
possible to get more than one keysig for a chord. We play along possible to get more than one keysig for a chord. We play along
for compatibility""" for compatibility"""
gen = self._createParameterGenerator(self.notelist, keysigList)
oldValues = []
for note in self.notelist:
oldValues.append(note.pitch)
note.toScale(next(gen))
self._cachedClefForLedgerLines = None
return lambda: self._setPitchlist(oldValues)
def stepUp(self, keysigList):
gen = self._createParameterGenerator(self.notelist, keysigList) gen = self._createParameterGenerator(self.notelist, keysigList)
oldValues = [] oldValues = []
for note in self.notelist: for note in self.notelist:

8
engine/main.py

@ -525,6 +525,14 @@ class Data(template.engine.sequencer.Score):
#self.copyObjectsBuffer = [] #maybe that is a bit harsh. If you press Cltr+C by accident, without a selection, you loose your copied data. This is especially bad for cut and paste #self.copyObjectsBuffer = [] #maybe that is a bit harsh. If you press Cltr+C by accident, without a selection, you loose your copied data. This is especially bad for cut and paste
return [] return []
def getIndenpendetCopyObjectsBuffer(self):
"""Requests a copy of the copy-buffer, if you want to modify it in-memory before pasting
it. Used by pasting a transposed version"""
result = []
for track in self.copyObjectsBuffer:
result.append([item.copy() for item in track])
return result
def pasteObjects(self, customBuffer = None, overwriteSelection = True): def pasteObjects(self, customBuffer = None, overwriteSelection = True):
"""This is ctrl+v """This is ctrl+v

9
qtgui/designer/mainwindow.py

@ -679,6 +679,10 @@ class Ui_MainWindow(object):
self.actionAutoconnect_Metronome.setObjectName("actionAutoconnect_Metronome") self.actionAutoconnect_Metronome.setObjectName("actionAutoconnect_Metronome")
self.actionBlock_Properties = QtWidgets.QAction(MainWindow) self.actionBlock_Properties = QtWidgets.QAction(MainWindow)
self.actionBlock_Properties.setObjectName("actionBlock_Properties") self.actionBlock_Properties.setObjectName("actionBlock_Properties")
self.actionPaste_modal_transposed = QtWidgets.QAction(MainWindow)
self.actionPaste_modal_transposed.setObjectName("actionPaste_modal_transposed")
self.actionPaste_real_transposed = QtWidgets.QAction(MainWindow)
self.actionPaste_real_transposed.setObjectName("actionPaste_real_transposed")
self.menuObjects.addAction(self.actionMetrical_Instruction) self.menuObjects.addAction(self.actionMetrical_Instruction)
self.menuObjects.addAction(self.actionClef) self.menuObjects.addAction(self.actionClef)
self.menuObjects.addAction(self.actionKey_Signature) self.menuObjects.addAction(self.actionKey_Signature)
@ -840,6 +844,8 @@ class Ui_MainWindow(object):
self.menuEdit_2.addAction(self.actionRedo) self.menuEdit_2.addAction(self.actionRedo)
self.menuEdit_2.addAction(self.actionCopy) self.menuEdit_2.addAction(self.actionCopy)
self.menuEdit_2.addAction(self.actionPaste) self.menuEdit_2.addAction(self.actionPaste)
self.menuEdit_2.addAction(self.actionPaste_modal_transposed)
self.menuEdit_2.addAction(self.actionPaste_real_transposed)
self.menuEdit_2.addAction(self.actionCut) self.menuEdit_2.addAction(self.actionCut)
self.menuEdit_2.addAction(self.actionDuplicateItem) self.menuEdit_2.addAction(self.actionDuplicateItem)
self.menuOrder.addAction(self.actionRandom) self.menuOrder.addAction(self.actionRandom)
@ -1027,3 +1033,6 @@ class Ui_MainWindow(object):
self.actionAutoconnect_Metronome.setIconText(_translate("MainWindow", "Wether to autoconnect the mixer ports on program start. Not for NSM.")) 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.")) self.actionAutoconnect_Metronome.setToolTip(_translate("MainWindow", "Wether to autoconnect the mixer ports on program start. Not for NSM."))
self.actionBlock_Properties.setText(_translate("MainWindow", "Block Properties")) self.actionBlock_Properties.setText(_translate("MainWindow", "Block Properties"))
self.actionPaste_modal_transposed.setText(_translate("MainWindow", "Paste modal transposed"))
self.actionPaste_modal_transposed.setShortcut(_translate("MainWindow", "Ctrl+Shift+V"))
self.actionPaste_real_transposed.setText(_translate("MainWindow", "Paste real transposed"))

15
qtgui/designer/mainwindow.ui

@ -276,6 +276,8 @@
<addaction name="actionRedo"/> <addaction name="actionRedo"/>
<addaction name="actionCopy"/> <addaction name="actionCopy"/>
<addaction name="actionPaste"/> <addaction name="actionPaste"/>
<addaction name="actionPaste_modal_transposed"/>
<addaction name="actionPaste_real_transposed"/>
<addaction name="actionCut"/> <addaction name="actionCut"/>
<addaction name="actionDuplicateItem"/> <addaction name="actionDuplicateItem"/>
</widget> </widget>
@ -1808,6 +1810,19 @@
<string>Block Properties</string> <string>Block Properties</string>
</property> </property>
</action> </action>
<action name="actionPaste_modal_transposed">
<property name="text">
<string>Paste modal transposed</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+V</string>
</property>
</action>
<action name="actionPaste_real_transposed">
<property name="text">
<string>Paste real transposed</string>
</property>
</action>
</widget> </widget>
<resources/> <resources/>
<connections/> <connections/>

2
qtgui/menu.py

@ -283,6 +283,8 @@ class MenuActionDatabase(object):
self.mainWindow.ui.actionCut : api.cutObjects, self.mainWindow.ui.actionCut : api.cutObjects,
self.mainWindow.ui.actionCopy : api.copyObjects, self.mainWindow.ui.actionCopy : api.copyObjects,
self.mainWindow.ui.actionPaste : api.pasteObjects, self.mainWindow.ui.actionPaste : api.pasteObjects,
self.mainWindow.ui.actionPaste_modal_transposed : api.pasteObjectsTransposedModal,
self.mainWindow.ui.actionPaste_real_transposed : api.pasteObjectsTransposedReal,
self.mainWindow.ui.actionDuplicateItem : api.duplicate, self.mainWindow.ui.actionDuplicateItem : api.duplicate,
self.mainWindow.ui.actionUndo : api.undo, self.mainWindow.ui.actionUndo : api.undo,
self.mainWindow.ui.actionRedo : api.redo, self.mainWindow.ui.actionRedo : api.redo,

Loading…
Cancel
Save