Browse Source

Fix channel change ly export. Better GUI text

master
Nils 5 years ago
parent
commit
e21076248a
  1. 7
      engine/items.py
  2. 28
      engine/track.py

7
engine/items.py

@ -2167,7 +2167,6 @@ class KeySignature(Item):
lyKeysignature = subtextRoot + "\\set Staff.keyAlterations = #`(( 0 . ,NATURAL))" #TODO: subtextRoot position is broken
return lyKeysignature
class Clef(Item):
"""A clef has no direct musical logical meaning. But it gives some hints:
Voice range. A typical musical voice in a polyphonic setup has between one and two octaves range
@ -2741,7 +2740,7 @@ class ChannelChange(Item):
"tickindex" : trackState.tickindex - duration, #we parse the tickindex after we stepped over the item.
"midiBytes" : [],
"text" : self.text,
"UIstring" : "ch{}".format(self.value), #this is for a UI, possibly a text UI, maybe for simple items of a GUI. Make it as short and unambigious as possible.
"UIstring" : f"{self.text}(ch{self.value})" if self.text else f"ch{self.value}", #this is for a UI, possibly a text UI, maybe for simple items of a GUI. Make it as short and unambigious as possible.
}
def _lilypond(self):
@ -2749,8 +2748,7 @@ class ChannelChange(Item):
Don't create white-spaces yourself, this is done by the structures.
When in doubt prefer functionality and robustness over 'beautiful' lilypond syntax."""
if self.text:
raise NotImplementedError("Implement _lilypond() with correct instrument change syntax")
return self.text
return f'\\mark \\markup {{\\small "{self.text}"}}'
else:
return ""
@ -2847,6 +2845,7 @@ class LilypondText(Item):
When in doubt prefer functionality and robustness over 'beautiful' lilypond syntax."""
return self.text
@classmethod
def instanceFromSerializedData(cls, serializedObject, parentObject):
"""see Score.instanceFromSerializedData"""

28
engine/track.py

@ -986,7 +986,8 @@ class Track(object):
#TODO: However, it is even less elegant to put this call in all rhythm editing methods and functions. inserts, block duplicate, content links, augment, tuplets undo etc.
#Taken out an placed in tempo Export. #self.score.tempoTrack.expandLastBlockToScoreDuration() #we guarantee that the tempo track is always at least as long as the music tracks.
patternBlob = bytes() # Create a binary blob that contains the MIDI events
midiNotesBinaryCoxData = bytes() # Create a binary blob that contains the MIDI events
instrumentChangesBinaryCoxData = bytes() # same as above, but only for instrument changes.
originalPosition = self.state.position()
self.getPreliminaryData()
@ -1005,9 +1006,9 @@ class Track(object):
assert self.initialMidiBankMsb == initialProgamChange.msb
assert self.initialMidiBankLsb == initialProgamChange.lsb
if initialProgamChange.program >= 0: #-1 is off.
patternBlob += cbox.Pattern.serialize_event(0, 0xC0 + self.initialMidiChannel, initialProgamChange.program, 0)
patternBlob += cbox.Pattern.serialize_event(0, 0xB0 + self.initialMidiChannel, 0, self.initialMidiBankMsb) #position, status byte+channel, controller number, controller value
patternBlob += cbox.Pattern.serialize_event(0, 0xB0 + self.initialMidiChannel, 32, self.initialMidiBankLsb) #position, status byte+channel, controller number, controller value
instrumentChangesBinaryCoxData += cbox.Pattern.serialize_event(0, 0xC0 + self.initialMidiChannel, initialProgamChange.program, 0)
instrumentChangesBinaryCoxData += cbox.Pattern.serialize_event(0, 0xB0 + self.initialMidiChannel, 0, self.initialMidiBankMsb) #position, status byte+channel, controller number, controller value
instrumentChangesBinaryCoxData += cbox.Pattern.serialize_event(0, 0xB0 + self.initialMidiChannel, 32, self.initialMidiBankLsb) #position, status byte+channel, controller number, controller value
localRight = self.right #performance
resultAppend = result.append #performance
@ -1024,10 +1025,14 @@ class Track(object):
expObj = previousItem.exportObject(self.state) #yes, it is correct that the state in the parameter is ahead by one position. Why is it that way? Because everything that matters, like new dynamics will only be parsed afterwards. The trackState is always correct except for the tickindex when exporting after parsing. Thats why exportObject sometimes substracts its own duration for finding its starting tick.
resultAppend(expObj)
dur = expObj["completeDuration"]
for blob in expObj["midiBytes"]: #a list of
patternBlob += blob
if expObj["type"] == "Chord" or expObj["type"] == "Rest": #save for later when we create Beams. No other use.
_allExportedChordsAppend(expObj)
if expObj["type"] != "InstrumentChange":
for blob in expObj["midiBytes"]: #a list of
midiNotesBinaryCoxData += blob
if expObj["type"] == "Chord" or expObj["type"] == "Rest": #save for later when we create Beams. No other use.
_allExportedChordsAppend(expObj)
else:
for blob in expObj["midiBytes"]: #a list of
instrumentChangesBinaryCoxData += blob
elif r == 2: #block end. Again, this is already the previous state. right now we are in the next block already.
lastBlock = self.blocks[self.state.blockindex-1] #why -1? see comment above
@ -1155,9 +1160,14 @@ class Track(object):
metaData["duration"] = self.state.tickindex #tickindex is now at the end, so this is the end duration. This includes Blocks minimumDuration as well since it is included in left/right
metaData["beams"] = resultBeamGroups
t = (patternBlob, 0, self.state.tickindex)
#Notes
t = (midiNotesBinaryCoxData, 0, self.state.tickindex)
self.sequencerInterface.setTrack([t]) #(bytes-blob, position, length) #tickindex is still on the last position, which means the second parameter is the length
#Instrument Changes
self.sequencerInterface.setSubtrack(key="instrumentChanges", blobs=[(instrumentChangesBinaryCoxData, 0, self.state.tickindex),]) #(bytes-blob, position, length)
self.toPosition(originalPosition, strict = False) #has head() in it
return result

Loading…
Cancel
Save