@ -564,12 +564,12 @@ def setTrackPatternLengthMultiplicator(trackId, newMultiplicator:int):
#Track Switches
#Aka measures
def _setTrackStructure ( trackId , structure ) :
def _setTrackStructure ( trackId , structure , undoMessage ) :
""" For undo. Used by all functions as entry point, then calls itself for undo/redo.
structure is a set of integers which we can copy with . copy ( ) """
track = session . data . trackById ( trackId )
session . history . register ( lambda tr = trackId , v = track . structure . copy ( ) : _setTrackStructure ( trackId , v ) , descriptionString = " Set Measures " )
session . history . register ( lambda tr = trackId , v = track . structure . copy ( ) , msg = undoMessage : _setTrackStructure ( trackId , v , msg ) , descriptionString = undoMessage )
track . structure = structure #restore data
track . buildTrack ( )
@ -580,7 +580,7 @@ def _setTrackStructure(trackId, structure):
def setSwitches ( trackId , setOfPositions , newBool ) :
""" Used in the GUI to select multiple switches in a row by dragging the mouse """
track = session . data . trackById ( trackId )
session . history . register ( lambda tr = trackId , v = track . structure . copy ( ) : _setTrackStructure ( trackId , v ) , descriptionString = " Set Measures " )
session . history . register ( lambda tr = trackId , v = track . structure . copy ( ) : _setTrackStructure ( trackId , v , " Set Measures " ) , descriptionString = " Set Measures " )
if newBool :
track . structure = track . structure . union ( setOfPositions ) #merge: add setOfPositions to the existing one
else :
@ -591,7 +591,7 @@ def setSwitches(trackId, setOfPositions, newBool):
def setSwitch ( trackId , position , newBool ) :
track = session . data . trackById ( trackId )
session . history . register ( lambda trId = trackId , v = track . structure . copy ( ) : _setTrackStructure ( trId , v ) , descriptionString = " Set Measures " )
session . history . register ( lambda trId = trackId , v = track . structure . copy ( ) : _setTrackStructure ( trId , v , " Set Measures " ) , descriptionString = " Set Measures " )
if newBool :
if position in track . structure : return
track . structure . add ( position )
@ -605,7 +605,7 @@ def setSwitch(trackId, position, newBool):
def trackInvertSwitches ( trackId ) :
track = session . data . trackById ( trackId )
session . history . register ( lambda trId = trackId , v = track . structure . copy ( ) : _setTrackStructure ( trId , v ) , descriptionString = " Se t Measures" )
session . history . register ( lambda trId = trackId , v = track . structure . copy ( ) : _setTrackStructure ( trId , v , " Invert Measures " ) , descriptionString = " Inver t Measures" )
"""
if track . structure :
new = set ( i for i in range ( max ( track . structure ) ) )
@ -621,7 +621,7 @@ def trackInvertSwitches(trackId):
def trackOffAllSwitches ( trackId ) :
track = session . data . trackById ( trackId )
session . history . register ( lambda trId = trackId , v = track . structure . copy ( ) : _setTrackStructure ( trId , v ) , descriptionString = " Set Measures " )
session . history . register ( lambda trId = trackId , v = track . structure . copy ( ) : _setTrackStructure ( trId , v , " Track Measures Off " ) , descriptionString = " Track Measures Off " )
track . structure = set ( )
track . buildTrack ( )
updatePlayback ( )
@ -629,7 +629,7 @@ def trackOffAllSwitches(trackId):
def trackOnAllSwitches ( trackId ) :
track = session . data . trackById ( trackId )
session . history . register ( lambda trId = trackId , v = track . structure . copy ( ) : _setTrackStructure ( trId , v ) , descriptionString = " Set Measures " )
session . history . register ( lambda trId = trackId , v = track . structure . copy ( ) : _setTrackStructure ( trId , v , " Track Measures On " ) , descriptionString = " Track Measures On " )
track . structure = set ( i for i in range ( session . data . numberOfMeasures ) )
track . buildTrack ( )
updatePlayback ( )
@ -639,7 +639,7 @@ def trackMergeCopyFrom(sourceTrackId, targetTrackId):
if not sourceTrackId == targetTrackId :
sourceTrack = session . data . trackById ( sourceTrackId )
targetTrack = session . data . trackById ( targetTrackId )
session . history . register ( lambda trId = id ( targetTrack ) , v = targetTrack . structure . copy ( ) : _setTrackStructure ( trId , v ) , descriptionString = " Set Measures" )
session . history . register ( lambda trId = id ( targetTrack ) , v = targetTrack . structure . copy ( ) : _setTrackStructure ( trId , v , " Copy Measures " ) , descriptionString = " Copy Measures" )
targetTrack . structure = targetTrack . structure . union ( sourceTrack . structure )
targetTrack . whichPatternsAreScaleTransposed . update ( sourceTrack . whichPatternsAreScaleTransposed )
targetTrack . whichPatternsAreHalftoneTransposed . update ( sourceTrack . whichPatternsAreHalftoneTransposed )
@ -651,7 +651,7 @@ def trackPatternReplaceFrom(sourceTrackId, targetTrackId):
if not sourceTrackId == targetTrackId :
sourceTrack = session . data . trackById ( sourceTrackId )
targetTrack = session . data . trackById ( targetTrackId )
session . history . register ( lambda trId = id ( targetTrack ) , v = targetTrack . structure . copy ( ) : _setTrackStructure ( trId , v ) , descriptionString = " Set Measures" )
session . history . register ( lambda trId = id ( targetTrack ) , v = targetTrack . structure . copy ( ) : _setTrackStructure ( trId , v , " Replace Measures " ) , descriptionString = " Replace Measures" )
copyPattern = sourceTrack . pattern . copy ( newParentTrack = targetTrack )
targetTrack . pattern = copyPattern
@ -715,7 +715,7 @@ def _registerHistoryWholeTrackSwitches(track):
"""
trackId = id ( track )
session . history . register ( lambda trId = trackId , v = track . patternLengthMultiplicator : setTrackPatternLengthMultiplicator ( trId , v ) , descriptionString = " Pattern Multiplier " )
session . history . register ( lambda trId = trackId , v = track . structure . copy ( ) : _setTrackStructure ( trId , v ) , descriptionString = " Set Measures " )
session . history . register ( lambda trId = trackId , v = track . structure . copy ( ) : _setTrackStructure ( trId , v , " Change Group " ) , descriptionString = " Change Group " )
session . history . register ( lambda trId = trackId , v = track . whichPatternsAreScaleTransposed . copy ( ) : _setSwitchesScaleTranspose ( trId , v ) , descriptionString = " Set Modal Shift " )
session . history . register ( lambda trId = trackId , v = track . whichPatternsAreHalftoneTransposed . copy ( ) : _setSwitchHalftoneTranspose ( trId , v ) , descriptionString = " Set Half Tone Shift " )
@ -830,9 +830,17 @@ def deleteSwitches(howMany, fromMeasureNumber):
updatePlayback ( )
#Pattern Steps
def setPattern ( trackId , patternList ) :
""" Change the whole pattern, send a callback with the whole pattern """
def setPattern ( trackId , patternList , undoMessage ) :
""" Change the whole pattern, send a callback with the whole pattern.
This is also the main undo / redo function .
It is rarely used directly by the GUI , if at all . Normal changes are atomic .
"""
track = session . data . trackById ( trackId )
session . history . register ( lambda trId = trackId , v = track . pattern . copyData ( ) , msg = undoMessage : setPattern ( trId , v , msg ) , descriptionString = undoMessage )
track . pattern . data = patternList
track . pattern . buildExportCache ( )
track . buildTrack ( )
@ -847,8 +855,12 @@ def setStep(trackId, stepExportDict):
only sends that switch back via callback . A simple GUI
will most like not listen to that callback since they
already changed the step on their side . Only useful for parallel
views . """
views .
This is also for velocity !
"""
track = session . data . trackById ( trackId )
session . history . register ( lambda trId = trackId , v = track . pattern . copyData ( ) : setPattern ( trId , v , " Change Step " ) , descriptionString = " Change Step " )
oldNote = track . pattern . stepByIndexAndPitch ( index = stepExportDict [ " index " ] , pitch = stepExportDict [ " pitch " ] )
if oldNote : #modify existing note
oldNoteIndex = track . pattern . data . index ( oldNote )
@ -865,6 +877,7 @@ def setStep(trackId, stepExportDict):
def removeStep ( trackId , index , pitch ) :
""" Reverse of setStep """
track = session . data . trackById ( trackId )
session . history . register ( lambda trId = trackId , v = track . pattern . copyData ( ) : setPattern ( trId , v , " Remove Step " ) , descriptionString = " Remove Step " )
oldNote = track . pattern . stepByIndexAndPitch ( index , pitch )
track . pattern . data . remove ( oldNote )
track . pattern . buildExportCache ( )
@ -876,7 +889,8 @@ def setScale(trackId, scale, callback = True):
""" Expects a scale list or tuple from lowest index to highest.
Actual pitches don ' t matter. " " "
track = session . data . trackById ( trackId )
track . pattern . scale = scale
session . history . register ( lambda trId = trackId , v = track . pattern . scale [ : ] : setScale ( trId , v , callback = True ) , descriptionString = " Set Scale " )
track . pattern . scale = scale #tuple, or list if oversight in json loading :)
track . pattern . buildExportCache ( )
track . buildTrack ( )
updatePlayback ( )
@ -887,11 +901,13 @@ def setSimpleNoteNames(trackId, simpleNoteNames):
""" note names is a list of strings with length 128. One name for each midi note.
It is saved to file """
track = session . data . trackById ( trackId )
track . pattern . simpleNoteNames = simpleNoteNames
session . history . register ( lambda trId = trackId , v = track . pattern . simpleNoteNames [ : ] : setSimpleNoteNames ( trId , v ) , descriptionString = " Note Names " )
track . pattern . simpleNoteNames = simpleNoteNames #list of strings
callbacks . _trackMetaDataChanged ( track )
def transposeHalftoneSteps ( trackId , steps ) :
track = session . data . trackById ( trackId )
session . history . register ( lambda trId = trackId , v = track . pattern . scale [ : ] : setScale ( trId , v , callback = True ) , descriptionString = " Transpose Scale " )
track . pattern . scale = [ midipitch + steps for midipitch in track . pattern . scale ]
track . pattern . buildExportCache ( )
track . buildTrack ( )
@ -900,6 +916,7 @@ def transposeHalftoneSteps(trackId, steps):
def patternInvertSteps ( trackId ) :
track = session . data . trackById ( trackId )
session . history . register ( lambda trId = trackId , v = track . pattern . copyData ( ) : setPattern ( trId , v , " Invert Steps " ) , descriptionString = " Invert Steps " )
track . pattern . invert ( )
track . pattern . buildExportCache ( )
track . buildTrack ( )
@ -908,6 +925,7 @@ def patternInvertSteps(trackId):
def patternOnAllSteps ( trackId ) :
track = session . data . trackById ( trackId )
session . history . register ( lambda trId = trackId , v = track . pattern . copyData ( ) : setPattern ( trId , v , " All Steps On " ) , descriptionString = " All Steps On " )
track . pattern . fill ( )
track . pattern . buildExportCache ( )
track . buildTrack ( )
@ -916,6 +934,7 @@ def patternOnAllSteps(trackId):
def patternOffAllSteps ( trackId ) :
track = session . data . trackById ( trackId )
session . history . register ( lambda trId = trackId , v = track . pattern . copyData ( ) : setPattern ( trId , v , " All Steps Off " ) , descriptionString = " All Steps Off " )
track . pattern . empty ( )
track . pattern . buildExportCache ( )
track . buildTrack ( )
@ -925,6 +944,7 @@ def patternOffAllSteps(trackId):
def patternInvertRow ( trackId , pitchindex ) :
""" Pitchindex is the row """
track = session . data . trackById ( trackId )
session . history . register ( lambda trId = trackId , v = track . pattern . copyData ( ) : setPattern ( trId , v , " Invert Row " ) , descriptionString = " Invert Row " )
track . pattern . invertRow ( pitchindex )
track . pattern . buildExportCache ( )
track . buildTrack ( )
@ -935,6 +955,7 @@ def patternClearRow(trackId, pitchindex):
""" Pitchindex is the row.
Index is the column """
track = session . data . trackById ( trackId )
session . history . register ( lambda trId = trackId , v = track . pattern . copyData ( ) : setPattern ( trId , v , " Clear Row " ) , descriptionString = " Clear Row " )
track . pattern . clearRow ( pitchindex )
track . pattern . buildExportCache ( )
track . buildTrack ( )
@ -945,6 +966,7 @@ def patternRowRepeatFromStep(trackId, pitchindex, index):
""" Pitchindex is the row.
Index is the column """
track = session . data . trackById ( trackId )
session . history . register ( lambda trId = trackId , v = track . pattern . copyData ( ) : setPattern ( trId , v , " Fill Row with Repeat " ) , descriptionString = " Fill Row with Repeat " )
track . pattern . repeatFromStep ( pitchindex , index )
track . pattern . buildExportCache ( )
track . buildTrack ( )
@ -953,6 +975,7 @@ def patternRowRepeatFromStep(trackId, pitchindex, index):
def patternRowChangeVelocity ( trackId , pitchindex , delta ) :
track = session . data . trackById ( trackId )
session . history . register ( lambda trId = trackId , v = track . pattern . copyData ( ) : setPattern ( trId , v , " Change Row Velocity " ) , descriptionString = " Change Row Velocity " )
for note in track . pattern . getRow ( pitchindex ) :
new = note [ " velocity " ] + delta
note [ " velocity " ] = min ( max ( new , 0 ) , 127 )
@ -1004,6 +1027,7 @@ def setScaleToKeyword(trackId, keyword):
This function is called not often and does not need to be performant .
"""
track = session . data . trackById ( trackId )
session . history . register ( lambda trId = trackId , v = track . pattern . scale [ : ] : setScale ( trId , v , callback = True ) , descriptionString = " Set Scale " )
rememberRootNote = track . pattern . scale [ - 1 ] #The last note has a special role by convention. No matter if this is the lowest midi-pitch or not. Most of the time it is the lowest though.
@ -1047,6 +1071,7 @@ def setScaleToKeyword(trackId, keyword):
def changePatternVelocity ( trackId , steps ) :
track = session . data . trackById ( trackId )
session . history . register ( lambda trId = trackId , v = track . pattern . copyData ( ) : setPattern ( trId , v , " Change Pattern Velocity " ) , descriptionString = " Change Pattern Velocity " )
for note in track . pattern . data :
new = note [ " velocity " ] + steps
note [ " velocity " ] = min ( max ( new , 0 ) , 127 )
@ -1070,7 +1095,12 @@ def resizePatternWithoutScale(trackId, steps):
return
track = session . data . trackById ( trackId )
currentNr = track . pattern . numberOfSteps
#We could use setScale for undo. But this requires a different set of callbacks. We use our own function, eventhough some of the calculations are not needed for undo.
session . history . register ( lambda trId = trackId , v = track . pattern . numberOfSteps : resizePatternWithoutScale ( trId , v ) , descriptionString = " Number of Notes in Pattern " )
currentNr = track . pattern . numberOfSteps #int
oldid = id ( track . pattern . scale )
s = track . pattern . scale #GUI view: from top to bottom. Usually from higher pitches to lower. (49, 53, 50, 45, 42, 39, 38, 36)
if steps == currentNr :