new=type(self)(self.program,self.msb,self.lsb,self.instrumentName,self.shortInstrumentName)#all init parameters are immutable types and copied implicitly
new=type(self)(self.program,self.msb,self.lsb,self.shortInstrumentName)#all init parameters are immutable types and copied implicitly
returnnew
def_exportObject(self,trackState):
@ -2671,8 +2669,8 @@ class InstrumentChange(Item):
@ -2681,25 +2679,16 @@ class InstrumentChange(Item):
cbox.Pattern.serialize_event(tickPosition,0xB0+trackState.midiChannel(),0,self.msb),#position, status byte+channel, controller number, controller value
cbox.Pattern.serialize_event(tickPosition,0xB0+trackState.midiChannel(),32,self.lsb),#position, status byte+channel, controller number, controller value
],
"instrumentName":self.instrumentName,
"shortInstrumentName":self.shortInstrumentName,
"UIstring":"{}[pr{}{}{}]".format(_nameStr,self.program,_msbStr,_lsbStr),#this is for a UI, possibly a text UI, maybe for simple items of a GUI. Make it as short and unambigious as possible.
}
#hier weiter machen. die midiBytes können so exportiert werden, wahrscheinlich auch auf diesem channel.
#Aber die müssen im Track dann am Ende rausgefiltert werden und auf einen eigenen cbox midi track.
#Die Alternative wäre das aufzuteilen. Eins auf CC0, eins auf CC32 und der Program Change auf einen eigenen Kanal?
#Was ist mit sowas wie initial program? Wo wird das geändert? In den Track Properties. Vielleichst ist das selbst ein InstrumentChange Objekt. Könnte eins sein zumindest.
def_lilypond(self):
"""called by block.lilypond(), returns a string.
Don't create white-spaces yourself, this is done by the structures.
listOfChangedTrackIds.add(id(parentBlock.parentTrack))#there are items without parent Tracks. They have None. We must filter them out otherwise our changedTrackIds get polluted with id(None)
else:
continue
elifr==2:#block end. Again, this is already the previous state. right now we are in the next block already.
@ -482,7 +488,10 @@ class Data(template.engine.sequencer.Score):
track.toPosition(originalPosition)#has head() in it
finalResult.append(result)
#finalResult[4:] is only lists(tracks) with items
forchangedTrIdinlistOfChangedTrackIds:
assertself.trackById(changedTrId)inself.tracks,changedTrId#selecting from hidden or deleted tracks is impossible
returnfinalResult
#The next two functions have "Objects" in their name so copy gets not confused with block.copy or item.copy. This is Ctrl+C as in copy and paste.
@ -628,7 +637,10 @@ class Data(template.engine.sequencer.Score):
defdeleteSelection(self):
"""Mortals, Hear The Prophecy: Delete Selection is notoriously tricky. It was hard in Laborejo 1 and it is still hard
#We delete always from the same cursor position. After one deletion the rest items gravitate left to our position. Except block boundaries, those will not be crossed so we have to check for them:
foritem,cached6StateinselectionTrack:
foritem,cachedStateinselectionTrack:
ifitemisbottomRightCursor["item"]:
break#without this the program will delete the first non-selected item, if zero duration, as well
@ -696,6 +708,7 @@ class Data(template.engine.sequencer.Score):
#assert curTrack.state.tickindex == topLeftCursor["tickindex"] We cannot be sure of this. The selection could have started at a content-linked item that got deleted and the tickindex has no item anymore
#return [id(track) for track in self.tracks] #TODO: only for debug reasons. the GUI will draw everything with this! Either this function or the api has to figure out the tracks that really changed. we could do a len check of the blocks data.
returnlistOfChangedTrackIds
defgetBlockAndItemOrder(self):
@ -955,6 +968,11 @@ class Data(template.engine.sequencer.Score):
track=self.currentTrack()
startBlock=track.currentBlock()#this is the only unique thing we can rely on.
#startBlock will get deleted, but we don't remove the blocks as parent because we need them for undo
#They will be finally cleared on save.
#NO. This works for splitting, but not for undo. for item in startBlock.data:
@ -963,7 +981,6 @@ class Data(template.engine.sequencer.Score):
protoBlockRight=startBlock.copy(track)
protoBlockRight.data=startBlock.data[startBlock.localCursorIndex:]#everything right of the cursor. The local cursor index of the current block is guaranteed to be correct. The one from other blocks is not.
forblockinstartBlock.linkedContentBlocksInScore():#all linked blocks in all tracks, including currentBlock. All blocks are unique. The content is not.
self.duringLegatoSlur=False#there are no nested legato slurs
self.duringBeamGroup=False#no nested beam groups.
self.midiChannels=[track.initialMidiChannel]#these are just integers, not items. items.ChannelChange parsing changes this and items automatically get the new value. A stack of midi channels allows the cursor to know the current channel for immediate playback/feedback.