from rational import Rational
+def escape_instrument_string (input_string):
+ retstring = string.replace (input_string, "\"", "\\\"")
+ if re.match ('.*\n.*', retstring):
+ strings = retstring.split ('\r\n')
+ 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)
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):
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
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()
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 = []
class EventChord (NestedMusic):
def __init__ (self):
NestedMusic.__init__ (self)
- self.grace_elements = []
+ 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):
not isinstance (e, RhythmicEvent)]
if self.grace_elements and self.elements:
- printer ('\grace {')
- for g in self.grace_elements:
- g.print_ly (printer)
- printer ('}')
+ 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)
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 " | "
pass
class SpanEvent (Event):
- def __init__(self):
+ def __init__ (self):
Event.__init__ (self)
self.span_direction = 0 # start/stop
self.line_type = 'solid'
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, '')
def ly_expression (self):
return '%s%s' % (self.direction_mod (), self.type)
-class TremoloEvent (Event):
+class NoDirectionArticulationEvent (ArticulationEvent):
+ def ly_expression (self):
+ return '\\%s' % self.type
+
+class MarkupEvent (ShortArticulationEvent):
+ def __init__ (self):
+ 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 (Event):
+class BendEvent (ArticulationEvent):
def __init__ (self):
Event.__init__ (self)
self.alter = 0
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):
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):
+ StaffGroup.__init__ (self, "Staff")
+ self.is_group = False
+ self.part = None
+
+ def print_ly_overrides (self, printer):
+ pass
+
+ def print_ly_contents (self, printer):
+ if not self.id or not self.part_information:
+ return
+
+ for [staff_id, voices] in self.part_information:
+ if staff_id:
+ printer ('\\context Staff = "%s" << ' % staff_id)
+ else:
+ printer ('\\context Staff << ')
+ 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 Voice = "%s" {%s \\%s }' % (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"
+ StaffGroup.print_ly (self, printer)
+
+
def test_pitch ():
bflat = Pitch()
bflat.alteration = -1