X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=python%2Fmusicexp.py;h=8fb4e5c31976c972e3544b182b15ccb14104b2a6;hb=34f50771ec53f5afbc49923833c32013f25fa1c2;hp=abe3125955437bd3e7352372c3a5f518aac9c95e;hpb=8f2493cf80f90a12938c305c5fcb01de7e9a03fc;p=lilypond.git diff --git a/python/musicexp.py b/python/musicexp.py index abe3125955..8fb4e5c319 100644 --- a/python/musicexp.py +++ b/python/musicexp.py @@ -5,6 +5,23 @@ import re from rational import Rational +# Store previously converted pitch for \relative conversion as a global state variable +previous_pitch = None +relative_pitches = False + +def escape_instrument_string (input_string): + retstring = string.replace (input_string, "\"", "\\\"") + if re.match ('.*[\r\n]+.*', retstring): + rx = re.compile (r'[\n\r]+') + strings = rx.split (retstring) + retstring = "\\markup { \\column { " + for s in strings: + retstring += "\\line {\"" + s + "\"} " + retstring += "} }" + else: + retstring = "\"" + retstring + "\"" + return retstring + class Output_stack_element: def __init__ (self): self.factor = Rational (1) @@ -62,8 +79,14 @@ class Output_printer: self._line += str def unformatted_output (self, str): - self._nesting += str.count ('<') + str.count ('{') - self._nesting -= str.count ('>') + str.count ('}') + # don't indent on \< and indent only once on << + self._nesting += ( str.count ('<') + - str.count ('\<') - str.count ('<<') + + str.count ('{') ) + self._nesting -= ( str.count ('>') - str.count ('\>') - str.count ('>>') + - str.count ('->') - str.count ('_>') + - str.count ('^>') + + str.count ('}') ) self.print_verbatim (str) def print_duration_string (self, str): @@ -107,8 +130,8 @@ class Output_printer: self.newline () self._file.close () self._file = None - - + + class Duration: def __init__ (self): self.duration_log = 0 @@ -129,7 +152,10 @@ class Duration: str = '%d%s' % (1 << self.duration_log, '.'*self.dots) if factor <> Rational (1,1): - str += '*%d/%d' % (factor.numerator (), factor.denominator ()) + if factor.denominator () <> 1: + str += '*%d/%d' % (factor.numerator (), factor.denominator ()) + else: + str += '*%d' % factor.numerator () return str @@ -160,7 +186,71 @@ class Duration: return base * dot_fact * self.factor - + +# Implement the different note names for the various languages +def pitch_generic (pitch, notenames, accidentals): + str = notenames[pitch.step] + if pitch.alteration < 0: + str += accidentals[0] * (-pitch.alteration) + elif pitch.alteration > 0: + str += accidentals[3] * (pitch.alteration) + return str + +def pitch_general (pitch): + str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['es', 'eh', 'ih', 'is']) + return str.replace ('aes', 'as').replace ('ees', 'es') + +def pitch_nederlands (pitch): + return pitch_general (pitch) + +def pitch_english (pitch): + str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'b'], ['f', 'qf', 'qs', 's']) + return str.replace ('aes', 'as').replace ('ees', 'es') + +def pitch_deutsch (pitch): + str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['es', 'eh', 'ih', 'is']) + return str.replace ('hes', 'b').replace ('aes', 'as').replace ('ees', 'es') + +def pitch_norsk (pitch): + return pitch_deutsch (pitch) + +def pitch_svenska (pitch): + str = pitch_generic (pitch, ['c', 'd', 'e', 'f', 'g', 'a', 'h'], ['ess', '', '', 'iss']) + return str.replace ('hess', 'b').replace ('aes', 'as').replace ('ees', 'es') + +def pitch_italiano (pitch): + str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', 'sb', 'sd', 'd']) + return str + +def pitch_catalan (pitch): + return pitch_italiano (pitch) + +def pitch_espanol (pitch): + str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 's']) + return str + +def pitch_vlaams (pitch): + str = pitch_generic (pitch, ['do', 're', 'mi', 'fa', 'sol', 'la', 'si'], ['b', '', '', 'k']) + return str + +def set_pitch_language (language): + global pitch_generating_function + function_dict = { + "nederlands": pitch_nederlands, + "english": pitch_english, + "deutsch": pitch_deutsch, + "norsk": pitch_norsk, + "svenska": pitch_svenska, + "italiano": pitch_italiano, + "catalan": pitch_catalan, + "espanol": pitch_espanol, + "vlaams": pitch_vlaams} + pitch_generating_function = function_dict.get (language, pitch_general) + +# global variable to hold the formatting function. +pitch_generating_function = pitch_general + + class Pitch: def __init__ (self): self.alteration = 0 @@ -207,21 +297,39 @@ class Pitch: return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration def ly_step_expression (self): - str = 'cdefgab'[self.step] - if self.alteration > 0: - str += 'is'* (self.alteration) - elif self.alteration < 0: - str += 'es'* (-self.alteration) + return pitch_generating_function (self) - return str.replace ('aes', 'as').replace ('ees', 'es') - - def ly_expression (self): - str = self.ly_step_expression () + def absolute_pitch (self): if self.octave >= 0: - str += "'" * (self.octave + 1) + return "'" * (self.octave + 1) elif self.octave < -1: - str += "," * (-self.octave - 1) - + return "," * (-self.octave - 1) + else: + return '' + + def relative_pitch (self): + global previous_pitch + if not previous_pitch: + previous_pitch = self + return self.absolute_pitch () + previous_pitch_steps = previous_pitch.octave * 7 + previous_pitch.step + this_pitch_steps = self.octave * 7 + self.step + pitch_diff = (this_pitch_steps - previous_pitch_steps) + previous_pitch = self + if pitch_diff > 3: + return "'" * ((pitch_diff + 3) / 7) + elif pitch_diff < -3: + return "," * ((-pitch_diff + 3) / 7) + else: + return "" + + def ly_expression (self): + str = self.ly_step_expression () + if relative_pitches: + str += self.relative_pitch () + else: + str += self.absolute_pitch () + return str def print_ly (self, outputter): @@ -309,6 +417,24 @@ class ModeChangingMusicWrapper (MusicWrapper): func ('\\%s' % self.mode) MusicWrapper.print_ly (self, func) +class RelativeMusic (MusicWrapper): + def __init__ (self): + MusicWrapper.__init__ (self) + self.basepitch = None + + def print_ly (self, func): + global previous_pitch + global relative_pitches + prev_relative_pitches = relative_pitches + relative_pitches = True + previous_pitch = self.basepitch + if not previous_pitch: + previous_pitch = Pitch () + func ('\\relative %s%s' % (pitch_generating_function (previous_pitch), + previous_pitch.absolute_pitch ())) + MusicWrapper.print_ly (self, func) + relative_pitches = prev_relative_pitches + class TimeScaledMusic (MusicWrapper): def print_ly (self, func): func ('\\times %d/%d ' % @@ -389,17 +515,31 @@ class NestedMusic(Music): return None class SequentialMusic (NestedMusic): - def print_ly (self, printer): + def get_last_event_chord (self): + value = None + at = len( self.elements ) - 1 + while (at >= 0 and + not isinstance (self.elements[at], EventChord) and + not isinstance (self.elements[at], BarLine)): + at -= 1 + + if (at >= 0 and isinstance (self.elements[at], EventChord)): + value = self.elements[at] + return value + + def print_ly (self, printer, newline = True): printer ('{') if self.comment: self.print_comment (printer) - printer.newline() + if newline: + printer.newline() for e in self.elements: e.print_ly (printer) printer ('}') - printer.newline() + if newline: + printer.newline() def lisp_sub_expression (self, pred): name = self.name() @@ -414,6 +554,36 @@ class SequentialMusic (NestedMusic): e.set_start (start) start += e.get_length() +class RepeatedMusic: + def __init__ (self): + self.repeat_type = "volta" + self.repeat_count = 2 + self.endings = [] + self.music = None + def set_music (self, music): + if isinstance (music, Music): + self.music = music + elif isinstance (music, list): + self.music = SequentialMusic () + self.music.elements = music + else: + sys.stderr.write ("WARNING: Unable to set the music %s for the repeat %s" % (music, self)) + def add_ending (self, music): + self.endings.append (music) + def print_ly (self, printer): + printer.dump ('\\repeat %s %s' % (self.repeat_type, self.repeat_count)) + if self.music: + self.music.print_ly (printer) + else: + sys.stderr.write ("WARNING: Encountered repeat without body\n") + printer.dump ('{}') + if self.endings: + printer.dump ('\\alternative {') + for e in self.endings: + e.print_ly (printer) + printer.dump ('}') + + class Lyrics: def __init__ (self): self.lyrics_syllables = [] @@ -432,7 +602,77 @@ class Lyrics: return lstr -class EventChord(NestedMusic): +class Header: + def __init__ (self): + self.header_fields = {} + def set_field (self, field, value): + self.header_fields[field] = value + + def print_ly (self, printer): + printer.dump ("\header {") + printer.newline () + for (k,v) in self.header_fields.items (): + if v: + printer.dump ('%s = %s' % (k,v)) + printer.newline () + printer.dump ("}") + printer.newline () + printer.newline () + + +class Paper: + def __init__ (self): + self.global_staff_size = -1 + # page size + self.page_width = -1 + self.page_height = -1 + # page margins + self.top_margin = -1 + self.bottom_margin = -1 + self.left_margin = -1 + self.right_margin = -1 + self.system_left_margin = -1 + self.system_right_margin = -1 + self.system_distance = -1 + self.top_system_distance = -1 + + def print_length_field (self, printer, field, value): + if value >= 0: + printer.dump ("%s = %s\\cm" % (field, value)) + printer.newline () + def print_ly (self, printer): + if self.global_staff_size > 0: + printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size) + printer.newline () + printer.dump ('\\paper {') + printer.newline () + self.print_length_field (printer, "paper-width", self.page_width) + self.print_length_field (printer, "paper-height", self.page_height) + self.print_length_field (printer, "top-margin", self.top_margin) + self.print_length_field (printer, "botton-margin", self.bottom_margin) + self.print_length_field (printer, "left-margin", self.left_margin) + # TODO: maybe set line-width instead of right-margin? + self.print_length_field (printer, "right-margin", self.right_margin) + # TODO: What's the corresponding setting for system_left_margin and + # system_right_margin in Lilypond? + self.print_length_field (printer, "between-system-space", self.system_distance) + self.print_length_field (printer, "page-top-space", self.top_system_distance) + + printer.dump ('}') + printer.newline () + + +class EventChord (NestedMusic): + def __init__ (self): + NestedMusic.__init__ (self) + self.grace_elements = None + self.grace_type = None + def append_grace (self, element): + if element: + if not self.grace_elements: + self.grace_elements = SequentialMusic () + self.grace_elements.append (element) + def get_length (self): l = Rational (0) for e in self.elements: @@ -450,13 +690,28 @@ class EventChord(NestedMusic): other_events = [e for e in self.elements if not isinstance (e, RhythmicEvent)] + if self.grace_elements and self.elements: + if self.grace_type: + printer ('\\%s' % self.grace_type) + else: + printer ('\\grace') + # don't print newlines after the { and } braces + self.grace_elements.print_ly (printer, False) + if rest_events: rest_events[0].print_ly (printer) elif len (note_events) == 1: note_events[0].print_ly (printer) elif note_events: - pitches = [x.pitch.ly_expression () for x in note_events] + global previous_pitch + pitches = [] + basepitch = None + for x in note_events: + pitches.append (x.pitch.ly_expression ()) + if not basepitch: + basepitch = previous_pitch printer ('<%s>' % string.join (pitches)) + previous_pitch = basepitch note_events[0].duration.print_ly (printer) else: pass @@ -466,21 +721,35 @@ class EventChord(NestedMusic): self.print_comment (printer) +class Partial (Music): + def __init__ (self): + Music.__init__ (self) + self.partial = None + def print_ly (self, printer): + if self.partial: + printer.dump ("\\partial %s" % self.partial.ly_expression ()) -class BarCheck (Music): +class BarLine (Music): def __init__ (self): Music.__init__ (self) self.bar_number = 0 + self.type = None def print_ly (self, printer): + bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': ":", + 'heavy': "|", 'light-light': "||", 'light-heavy': "|.", + 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'", + 'short': "'", 'none': "" }.get (self.type, None) + if bar_symbol <> None: + printer.dump ('\\bar "%s"' % bar_symbol) + else: + printer.dump ("|") + if self.bar_number > 0 and (self.bar_number % 10) == 0: - printer.dump ("| \\barNumberCheck #%d " % self.bar_number) - printer.newline () + printer.dump ("\\barNumberCheck #%d " % self.bar_number) else: - printer.dump ("| ") printer.print_verbatim (' %% %d' % self.bar_number) - printer.newline () - + printer.newline () def ly_expression (self): return " | " @@ -489,26 +758,90 @@ class Event(Music): pass class SpanEvent (Event): - def __init__(self): + def __init__ (self): Event.__init__ (self) - self.span_direction = 0 + self.span_direction = 0 # start/stop + self.line_type = 'solid' + self.span_type = 0 # e.g. cres/decrescendo, ottava up/down + self.size = 0 # size of e.g. ocrave shift + def wait_for_note (self): + return True def get_properties(self): return "'span-direction %d" % self.span_direction - + def set_span_type (self, type): + self.span_type = type + class SlurEvent (SpanEvent): def ly_expression (self): - return {-1: '(', - 0:'', + before = '' + after = '' + # TODO: setting dashed/dotted line style does not work, because that + # command needs to be written before the note, not when the + # event is observed after the note! + #before = {'dotted': '\\slurDotted', + # 'dashed' : '\\slurDashed'}.get (self.line_type, '') + #if before: + #after = '\\slurSolid' + + return {-1: before + '(' + after, 1:')'}.get (self.span_direction, '') class BeamEvent (SpanEvent): def ly_expression (self): return {-1: '[', - 0:'', 1:']'}.get (self.span_direction, '') +class PedalEvent (SpanEvent): + def ly_expression (self): + return {-1: '\\sustainDown', + 1:'\\sustainUp'}.get (self.span_direction, '') + +# type==-1 means octave up, type==-2 means octave down +class OctaveShiftEvent (SpanEvent): + def wait_for_note (self): + return False; + def set_span_type (self, type): + self.span_type = {'up': 1, 'down': -1}.get (type, 0) + def ly_octave_shift_indicator (self): + # convert 8/15 to lilypond indicators (+-1/+-2) + value = {8: 1, 15: 2}.get (self.size, 0) + # negative values go up! + value *= -1*self.span_type + return value + def ly_expression (self): + dir = self.ly_octave_shift_indicator () + value = '' + if dir: + value = '#(set-octavation %s)' % dir + return { + -1: value, + 1: '#(set-octavation 0)'}.get (self.span_direction, '') + +class TrillSpanEvent (SpanEvent): + def ly_expression (self): + return {-1: '\\startTrillSpan', + 0: '', # no need to write out anything for type='continue' + 1:'\\stopTrillSpan'}.get (self.span_direction, '') + +class GlissandoEvent (SpanEvent): + def ly_expression (self): + style = '' + # TODO: wavy-line glissandos don't work, becasue the style has to be + # set before the note, at the \glissando it's already too late! + #if self.line_type == 'wavy': + #style = "\once\override Glissando #'style = #'zigzag" + # In lilypond, glissando is NOT a spanner, unlike MusicXML. + return {-1: style + '\\glissando', + 1:''}.get (self.span_direction, '') + class ArpeggioEvent(Event): + def __init__ (self): + Event.__init__ (self) + self.direction = 0 + def wait_for_note (self): + return True; def ly_expression (self): + # TODO: Use self.direction for up/down arpeggios return ('\\arpeggio') @@ -517,11 +850,14 @@ class TieEvent(Event): return '~' -class HairpinEvent (Event): - def __init__ (self, type): - self.type = type +class HairpinEvent (SpanEvent): + def set_span_type (self, type): + self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0) def hairpin_to_ly (self): - return { 0: '\!', 1: '\<', -1: '\>' }.get (self.type, '') + if self.span_direction == 1: + return '\!' + else: + return {1: '\<', -1: '\>'}.get (self.span_type, '') def ly_expression (self): return self.hairpin_to_ly () @@ -540,13 +876,15 @@ class DynamicsEvent (Event): "mp", "mf", "f", "ff", "fff", "ffff", "fp", "sf", "sff", "sp", "spp", "sfz", "rfz" ]; + def wait_for_note (self): + return True; def ly_expression (self): if self.type == None: return; elif self.type in self.available_commands: return '\%s' % self.type else: - return '\markup{ \dynamic %s }' % self.type + return '-\markup{ \dynamic %s }' % self.type def print_ly (self, printer): if self.type == None: @@ -554,13 +892,32 @@ class DynamicsEvent (Event): elif self.type in self.available_commands: printer.dump ("\\%s" % self.type) else: - printer.dump ("\\markup{ \\dynamic %s }" % self.type) + printer.dump ("-\\markup{ \\dynamic %s }" % self.type) + +class TextEvent (Event): + def __init__ (self): + self.Text = None + self.force_direction = None + self.markup = '' + def wait_for_note (self): + return True + + def direction_mod (self): + return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-') + + def ly_expression (self): + base_string = '%s\"%s\"' + if self.markup: + base_string = '%s\markup{ ' + self.markup + ' {%s} }' + return base_string % (self.direction_mod (), self.text) class ArticulationEvent (Event): def __init__ (self): self.type = None self.force_direction = None + def wait_for_note (self): + return True; def direction_mod (self): return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '') @@ -568,17 +925,84 @@ class ArticulationEvent (Event): def ly_expression (self): return '%s\\%s' % (self.direction_mod (), self.type) +class ShortArticulationEvent (ArticulationEvent): + def direction_mod (self): + # default is - + return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-') + def ly_expression (self): + if self.type: + return '%s%s' % (self.direction_mod (), self.type) + else: + return '' -class TremoloEvent (Event): +class NoDirectionArticulationEvent (ArticulationEvent): + def ly_expression (self): + if self.type: + return '\\%s' % self.type + else: + return '' + +class MarkupEvent (ShortArticulationEvent): def __init__ (self): - self.bars = 0; + ArticulationEvent.__init__ (self) + self.contents = None + def ly_expression (self): + if self.contents: + return "%s\\markup { %s }" % (self.direction_mod (), self.contents) + else: + return '' + +class FretEvent (MarkupEvent): + def __init__ (self): + MarkupEvent.__init__ (self) + self.force_direction = 1 + self.strings = 6 + self.frets = 4 + self.barre = None + self.elements = [] + def ly_expression (self): + val = "" + if self.strings <> 6: + val += "w:%s;" % self.strings + if self.frets <> 4: + val += "h:%s;" % self.frets + if self.barre and len (self.barre) >= 3: + val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2]) + have_fingering = False + for i in self.elements: + if len (i) > 1: + val += "%s-%s" % (i[0], i[1]) + if len (i) > 2: + have_fingering = True + val += "-%s" % i[2] + val += ";" + if have_fingering: + val = "f:1;" + val + if val: + return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val) + else: + return '' + +class TremoloEvent (ArticulationEvent): + def __init__ (self): + Event.__init__ (self) + self.bars = 0 def ly_expression (self): str='' - if self.bars > 0: + if self.bars and self.bars > 0: str += ':%s' % (2 ** (2 + string.atoi (self.bars))) return str +class BendEvent (ArticulationEvent): + def __init__ (self): + Event.__init__ (self) + self.alter = 0 + def ly_expression (self): + if self.alter: + return "-\\bendAfter #%s" % self.alter + else: + return '' class RhythmicEvent(Event): def __init__ (self): @@ -593,12 +1017,23 @@ class RhythmicEvent(Event): % self.duration.lisp_expression ()) class RestEvent (RhythmicEvent): + def __init__ (self): + RhythmicEvent.__init__ (self) + self.pitch = None def ly_expression (self): - return 'r%s' % self.duration.ly_expression () + if self.pitch: + return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ()) + else: + return 'r%s' % self.duration.ly_expression () def print_ly (self, printer): - printer('r') - self.duration.print_ly (printer) + if self.pitch: + self.pitch.print_ly (printer) + self.duration.print_ly (printer) + printer ('\\rest') + else: + printer('r') + self.duration.print_ly (printer) class SkipEvent (RhythmicEvent): def ly_expression (self): @@ -613,7 +1048,7 @@ class NoteEvent(RhythmicEvent): self.forced_accidental = False def get_properties (self): - str = RhythmicEvent.get_properties () + str = RhythmicEvent.get_properties (self) if self.pitch: str += self.pitch.lisp_expression () @@ -678,10 +1113,27 @@ class ClefChange (Music): def __init__ (self): Music.__init__ (self) self.type = 'G' - - + self.position = 2 + self.octave = 0 + + def octave_modifier (self): + return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '') + def clef_name (self): + return {('G', 2): "treble", + ('G', 1): "french", + ('C', 1): "soprano", + ('C', 2): "mezzosoprano", + ('C', 3): "alto", + ('C', 4): "tenor", + ('C', 5): "baritone", + ('F', 3): "varbaritone", + ('F', 4): "bass", + ('F', 5): "subbass", + ("percussion", 2): "percussion", + ("TAB", 5): "tab"}.get ((self.type, self.position), None) def ly_expression (self): - return '\\clef "%s"' % self.type + return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ()) + clef_dict = { "G": ("clefs.G", -2, -6), "C": ("clefs.C", 0, 0), @@ -689,7 +1141,10 @@ class ClefChange (Music): } def lisp_expression (self): - (glyph, pos, c0) = self.clef_dict.get (self.type) + try: + (glyph, pos, c0) = self.clef_dict[self.type] + except KeyError: + return "" clefsetting = """ (make-music 'SequentialMusic 'elements (list @@ -703,6 +1158,17 @@ class ClefChange (Music): return clefsetting +class StaffChange (Music): + def __init__ (self, staff): + Music.__init__ (self) + self.staff = staff + def ly_expression (self): + if self.staff: + return "\\change Staff=\"%s\"" % self.staff + else: + return '' + + class MultiMeasureRest(Music): def lisp_expression (self): @@ -725,6 +1191,156 @@ class MultiMeasureRest(Music): return 'R%s' % self.duration.ly_expression () +class StaffGroup: + def __init__ (self, command = "StaffGroup"): + self.stafftype = command + self.id = None + self.instrument_name = None + self.short_instrument_name = None + self.symbol = None + self.spanbar = None + self.children = [] + self.is_group = True + # part_information is a list with entries of the form + # [staffid, voicelist] + # where voicelist is a list with entries of the form + # [voiceid1, [lyricsid11, lyricsid12,...] ] + self.part_information = None + + def append_staff (self, staff): + self.children.append (staff) + + def set_part_information (self, part_name, staves_info): + if part_name == self.id: + self.part_information = staves_info + else: + for c in self.children: + c.set_part_information (part_name, staves_info) + + def print_ly_contents (self, printer): + for c in self.children: + if c: + c.print_ly (printer) + def print_ly_overrides (self, printer): + needs_with = False + needs_with |= self.spanbar == "no" + needs_with |= self.instrument_name != None + needs_with |= self.short_instrument_name != None + needs_with |= (self.symbol != None) and (self.symbol != "bracket") + if needs_with: + printer.dump ("\\with {") + if self.instrument_name or self.short_instrument_name: + printer.dump ("\\consists \"Instrument_name_engraver\"") + if self.spanbar == "no": + printer.dump ("\\override SpanBar #'transparent = ##t") + brack = {"brace": "SystemStartBrace", + "none": "f", + "line": "SystemStartSquare"}.get (self.symbol, None) + if brack: + printer.dump ("systemStartDelimiter = #'%s" % brack) + printer.dump ("}") + + def print_ly (self, printer): + if self.stafftype: + printer.dump ("\\new %s" % self.stafftype) + self.print_ly_overrides (printer) + printer.dump ("<<") + printer.newline () + if self.stafftype and self.instrument_name: + printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype, + escape_instrument_string (self.instrument_name))) + printer.newline () + if self.stafftype and self.short_instrument_name: + printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype, + escape_instrument_string (self.short_instrument_name))) + printer.newline () + self.print_ly_contents (printer) + printer.newline () + printer.dump (">>") + printer.newline () + + +class Staff (StaffGroup): + def __init__ (self, command = "Staff"): + StaffGroup.__init__ (self, command) + self.is_group = False + self.part = None + self.voice_command = "Voice" + self.substafftype = None + + def print_ly_overrides (self, printer): + pass + + def print_ly_contents (self, printer): + if not self.id or not self.part_information: + return + sub_staff_type = self.substafftype + if not sub_staff_type: + sub_staff_type = self.stafftype + + for [staff_id, voices] in self.part_information: + if staff_id: + printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id)) + else: + printer ('\\context %s << ' % sub_staff_type) + printer.newline () + n = 0 + nr_voices = len (voices) + for [v, lyrics] in voices: + n += 1 + voice_count_text = '' + if nr_voices > 1: + voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo', + 3: ' \\voiceThree'}.get (n, ' \\voiceFour') + printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v)) + printer.newline () + + for l in lyrics: + printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l)) + printer.newline() + printer ('>>') + + def print_ly (self, printer): + if self.part_information and len (self.part_information) > 1: + self.stafftype = "PianoStaff" + self.substafftype = "Staff" + StaffGroup.print_ly (self, printer) + +class TabStaff (Staff): + def __init__ (self, command = "TabStaff"): + Staff.__init__ (self, command) + self.string_tunings = [] + self.tablature_format = None + self.voice_command = "TabVoice" + def print_ly_overrides (self, printer): + if self.string_tunings or self.tablature_format: + printer.dump ("\\with {") + if self.string_tunings: + printer.dump ("stringTunings = #'(") + for i in self.string_tunings: + printer.dump ("%s" % i.semitones ()) + printer.dump (")") + if self.tablature_format: + printer.dump ("tablatureFormat = #%s" % self.tablature_format) + printer.dump ("}") + + +class DrumStaff (Staff): + def __init__ (self, command = "DrumStaff"): + Staff.__init__ (self, command) + self.drum_style_table = None + self.voice_command = "DrumVoice" + def print_ly_overrides (self, printer): + if self.drum_style_table: + printer.dump ("\with {") + printer.dump ("drumStyleTable = #%s" % self.drum_style_table) + printer.dump ("}") + +class RhythmicStaff (Staff): + def __init__ (self, command = "RhythmicStaff"): + Staff.__init__ (self, command) + + def test_pitch (): bflat = Pitch() bflat.alteration = -1