6 from rational import Rational
9 def escape_instrument_string (input_string):
10 retstring = string.replace (input_string, "\"", "\\\"")
11 if re.match ('.*[\r\n]+.*', retstring):
12 rx = re.compile (r'[\n\r]+')
13 strings = rx.split (retstring)
14 retstring = "\\markup { \\column { "
16 retstring += "\\line {\"" + s + "\"} "
19 retstring = "\"" + retstring + "\""
22 class Output_stack_element:
24 self.factor = Rational (1)
26 o = Output_stack_element()
27 o.factor = self.factor
32 """A class that takes care of formatting (eg.: indenting) a
33 Music expression as a .ly file.
36 ## TODO: support for \relative.
42 self._file = sys.stdout
44 self._output_state_stack = [Output_stack_element()]
45 self._skipspace = False
46 self._last_duration = None
48 def set_file (self, file):
51 def dump_version (self):
53 self.print_verbatim ('\\version "@TOPLEVEL_VERSION@"')
56 def get_indent (self):
57 return self._nesting * self._indent
60 last = self._output_state_stack[-1]
61 self._output_state_stack.append (last.copy())
63 def add_factor (self, factor):
65 self._output_state_stack[-1].factor *= factor
68 del self._output_state_stack[-1]
69 if not self._output_state_stack:
72 def duration_factor (self):
73 return self._output_state_stack[-1].factor
75 def print_verbatim (self, str):
78 def unformatted_output (self, str):
79 # don't indent on \< and indent only once on <<
80 self._nesting += ( str.count ('<')
81 - str.count ('\<') - str.count ('<<')
83 self._nesting -= ( str.count ('>') - str.count ('\>') - str.count ('>>')
84 - str.count ('->') - str.count ('_>')
87 self.print_verbatim (str)
89 def print_duration_string (self, str):
90 if self._last_duration == str:
93 self.unformatted_output (str)
95 def add_word (self, str):
96 if (len (str) + 1 + len (self._line) > self._line_len):
98 self._skipspace = True
100 if not self._skipspace:
102 self.unformatted_output (str)
103 self._skipspace = False
106 self._file.write (self._line + '\n')
107 self._line = ' ' * self._indent * self._nesting
108 self._skipspace = True
110 def skipspace (self):
111 self._skipspace = True
113 def __call__(self, arg):
116 def dump (self, str):
118 self._skipspace = False
119 self.unformatted_output (str)
121 words = string.split (str)
134 self.duration_log = 0
136 self.factor = Rational (1)
138 def lisp_expression (self):
139 return '(ly:make-duration %d %d %d %d)' % (self.duration_log,
141 self.factor.numerator (),
142 self.factor.denominator ())
145 def ly_expression (self, factor = None):
149 str = '%d%s' % (1 << self.duration_log, '.'*self.dots)
151 if factor <> Rational (1,1):
152 if factor.denominator () <> 1:
153 str += '*%d/%d' % (factor.numerator (), factor.denominator ())
155 str += '*%d' % factor.numerator ()
159 def print_ly (self, outputter):
160 str = self.ly_expression (self.factor / outputter.duration_factor ())
161 outputter.print_duration_string (str)
164 return self.ly_expression()
169 d.duration_log = self.duration_log
170 d.factor = self.factor
173 def get_length (self):
174 dot_fact = Rational( (1 << (1 + self.dots))-1,
177 log = abs (self.duration_log)
179 if self.duration_log < 0:
180 base = Rational (dur)
182 base = Rational (1, dur)
184 return base * dot_fact * self.factor
194 return self.ly_expression()
196 def transposed (self, interval):
198 c.alteration += interval.alteration
199 c.step += interval.step
200 c.octave += interval.octave
203 target_st = self.semitones() + interval.semitones()
204 c.alteration += target_st - c.semitones()
211 c.octave += c.step / 7
214 def lisp_expression (self):
215 return '(ly:make-pitch %d %d %d)' % (self.octave,
221 p.alteration = self.alteration
223 p.octave = self.octave
227 return self.step + self.octave *7
229 def semitones (self):
230 return self.octave * 12 + [0,2,4,5,7,9,11][self.step] + self.alteration
232 def ly_step_expression (self):
233 str = 'cdefgab'[self.step]
234 if self.alteration > 0:
235 str += 'is'* (self.alteration)
236 elif self.alteration < 0:
237 str += 'es'* (-self.alteration)
239 return str.replace ('aes', 'as').replace ('ees', 'es')
241 def ly_expression (self):
242 str = self.ly_step_expression ()
244 str += "'" * (self.octave + 1)
245 elif self.octave < -1:
246 str += "," * (-self.octave - 1)
250 def print_ly (self, outputter):
251 outputter (self.ly_expression())
256 self.start = Rational (0)
258 self.identifier = None
260 def get_length(self):
263 def get_properties (self):
266 def has_children (self):
269 def get_index (self):
271 return self.parent.elements.index (self)
275 return self.__class__.__name__
277 def lisp_expression (self):
280 props = self.get_properties ()
282 return "(make-music '%s %s)" % (name, props)
284 def set_start (self, start):
287 def find_first (self, predicate):
292 def print_comment (self, printer, text = None):
303 lines = string.split (text, '\n')
306 printer.unformatted_output ('% ' + l)
310 def print_with_identifier (self, printer):
312 printer ("\\%s" % self.identifier)
314 self.print_ly (printer)
316 def print_ly (self, printer):
317 printer (self.ly_expression ())
319 class MusicWrapper (Music):
323 def print_ly (self, func):
324 self.element.print_ly (func)
326 class ModeChangingMusicWrapper (MusicWrapper):
328 MusicWrapper.__init__ (self)
329 self.mode = 'notemode'
331 def print_ly (self, func):
332 func ('\\%s' % self.mode)
333 MusicWrapper.print_ly (self, func)
335 class TimeScaledMusic (MusicWrapper):
336 def print_ly (self, func):
337 func ('\\times %d/%d ' %
338 (self.numerator, self.denominator))
339 func.add_factor (Rational (self.numerator, self.denominator))
340 MusicWrapper.print_ly (self, func)
343 class NestedMusic(Music):
345 Music.__init__ (self)
348 def append (self, what):
350 self.elements.append (what)
352 def has_children (self):
355 def insert_around (self, succ, elt, dir):
356 assert elt.parent == None
357 assert succ == None or succ in self.elements
362 idx = self.elements.index (succ)
369 idx = len (self.elements)
371 self.elements.insert (idx, elt)
374 def get_properties (self):
375 return ("'elements (list %s)"
376 % string.join (map (lambda x: x.lisp_expression(),
379 def get_subset_properties (self, predicate):
380 return ("'elements (list %s)"
381 % string.join (map (lambda x: x.lisp_expression(),
382 filter ( predicate, self.elements))))
383 def get_neighbor (self, music, dir):
384 assert music.parent == self
385 idx = self.elements.index (music)
387 idx = min (idx, len (self.elements) -1)
390 return self.elements[idx]
392 def delete_element (self, element):
393 assert element in self.elements
395 self.elements.remove (element)
396 element.parent = None
398 def set_start (self, start):
400 for e in self.elements:
403 def find_first (self, predicate):
404 r = Music.find_first (self, predicate)
408 for e in self.elements:
409 r = e.find_first (predicate)
414 class SequentialMusic (NestedMusic):
415 def get_last_event_chord (self):
417 at = len( self.elements ) - 1
419 not isinstance (self.elements[at], EventChord) and
420 not isinstance (self.elements[at], BarLine)):
423 if (at >= 0 and isinstance (self.elements[at], EventChord)):
424 value = self.elements[at]
427 def print_ly (self, printer, newline = True):
430 self.print_comment (printer)
434 for e in self.elements:
441 def lisp_sub_expression (self, pred):
445 props = self.get_subset_properties (pred)
447 return "(make-music '%s %s)" % (name, props)
449 def set_start (self, start):
450 for e in self.elements:
452 start += e.get_length()
456 self.repeat_type = "volta"
457 self.repeat_count = 2
460 def set_music (self, music):
461 if isinstance (music, Music):
463 elif isinstance (music, list):
464 self.music = SequentialMusic ()
465 self.music.elements = music
467 sys.stderr.write ("WARNING: Unable to set the music %s for the repeat %s" % (music, self))
468 def add_ending (self, music):
469 self.endings.append (music)
470 def print_ly (self, printer):
471 printer.dump ('\\repeat %s %s' % (self.repeat_type, self.repeat_count))
473 self.music.print_ly (printer)
475 sys.stderr.write ("WARNING: Encountered repeat without body\n")
478 printer.dump ('\\alternative {')
479 for e in self.endings:
486 self.lyrics_syllables = []
488 def print_ly (self, printer):
489 printer.dump ("\lyricmode {")
490 for l in self.lyrics_syllables:
491 printer.dump ( "%s " % l )
494 def ly_expression (self):
495 lstr = "\lyricmode {\n "
496 for l in self.lyrics_syllables:
504 self.header_fields = {}
505 def set_field (self, field, value):
506 self.header_fields[field] = value
508 def print_ly (self, printer):
509 printer.dump ("\header {")
511 for (k,v) in self.header_fields.items ():
513 printer.dump ('%s = %s' % (k,v))
522 self.global_staff_size = -1
525 self.page_height = -1
528 self.bottom_margin = -1
529 self.left_margin = -1
530 self.right_margin = -1
531 self.system_left_margin = -1
532 self.system_right_margin = -1
533 self.system_distance = -1
534 self.top_system_distance = -1
536 def print_length_field (self, printer, field, value):
538 printer.dump ("%s = %s\\cm" % (field, value))
540 def print_ly (self, printer):
541 if self.global_staff_size > 0:
542 printer.dump ('#(set-global-staff-size %s)' % self.global_staff_size)
544 printer.dump ('\\paper {')
546 self.print_length_field (printer, "paper-width", self.page_width)
547 self.print_length_field (printer, "paper-height", self.page_height)
548 self.print_length_field (printer, "top-margin", self.top_margin)
549 self.print_length_field (printer, "botton-margin", self.bottom_margin)
550 self.print_length_field (printer, "left-margin", self.left_margin)
551 # TODO: maybe set line-width instead of right-margin?
552 self.print_length_field (printer, "right-margin", self.right_margin)
553 # TODO: What's the corresponding setting for system_left_margin and
554 # system_right_margin in Lilypond?
555 self.print_length_field (printer, "between-system-space", self.system_distance)
556 self.print_length_field (printer, "page-top-space", self.top_system_distance)
562 class EventChord (NestedMusic):
564 NestedMusic.__init__ (self)
565 self.grace_elements = None
566 self.grace_type = None
567 def append_grace (self, element):
569 if not self.grace_elements:
570 self.grace_elements = SequentialMusic ()
571 self.grace_elements.append (element)
573 def get_length (self):
575 for e in self.elements:
576 l = max(l, e.get_length())
579 def print_ly (self, printer):
580 note_events = [e for e in self.elements if
581 isinstance (e, NoteEvent)]
583 rest_events = [e for e in self.elements if
584 isinstance (e, RhythmicEvent)
585 and not isinstance (e, NoteEvent)]
587 other_events = [e for e in self.elements if
588 not isinstance (e, RhythmicEvent)]
590 if self.grace_elements and self.elements:
592 printer ('\\%s' % self.grace_type)
595 # don't print newlines after the { and } braces
596 self.grace_elements.print_ly (printer, False)
599 rest_events[0].print_ly (printer)
600 elif len (note_events) == 1:
601 note_events[0].print_ly (printer)
603 pitches = [x.pitch.ly_expression () for x in note_events]
604 printer ('<%s>' % string.join (pitches))
605 note_events[0].duration.print_ly (printer)
609 for e in other_events:
612 self.print_comment (printer)
614 class Partial (Music):
616 Music.__init__ (self)
618 def print_ly (self, printer):
620 printer.dump ("\\partial %s" % self.partial.ly_expression ())
622 class BarLine (Music):
624 Music.__init__ (self)
628 def print_ly (self, printer):
629 bar_symbol = { 'regular': "|", 'dotted': ":", 'dashed': ":",
630 'heavy': "|", 'light-light': "||", 'light-heavy': "|.",
631 'heavy-light': ".|", 'heavy-heavy': ".|.", 'tick': "'",
632 'short': "'", 'none': "" }.get (self.type, None)
633 if bar_symbol <> None:
634 printer.dump ('\\bar "%s"' % bar_symbol)
638 if self.bar_number > 0 and (self.bar_number % 10) == 0:
639 printer.dump ("\\barNumberCheck #%d " % self.bar_number)
641 printer.print_verbatim (' %% %d' % self.bar_number)
644 def ly_expression (self):
650 class SpanEvent (Event):
652 Event.__init__ (self)
653 self.span_direction = 0 # start/stop
654 self.line_type = 'solid'
655 self.span_type = 0 # e.g. cres/decrescendo, ottava up/down
656 self.size = 0 # size of e.g. ocrave shift
657 def wait_for_note (self):
659 def get_properties(self):
660 return "'span-direction %d" % self.span_direction
661 def set_span_type (self, type):
662 self.span_type = type
664 class SlurEvent (SpanEvent):
665 def ly_expression (self):
668 # TODO: setting dashed/dotted line style does not work, because that
669 # command needs to be written before the note, not when the
670 # event is observed after the note!
671 #before = {'dotted': '\\slurDotted',
672 # 'dashed' : '\\slurDashed'}.get (self.line_type, '')
674 #after = '\\slurSolid'
676 return {-1: before + '(' + after,
677 1:')'}.get (self.span_direction, '')
679 class BeamEvent (SpanEvent):
680 def ly_expression (self):
682 1:']'}.get (self.span_direction, '')
684 class PedalEvent (SpanEvent):
685 def ly_expression (self):
686 return {-1: '\\sustainDown',
687 1:'\\sustainUp'}.get (self.span_direction, '')
689 # type==-1 means octave up, type==-2 means octave down
690 class OctaveShiftEvent (SpanEvent):
691 def wait_for_note (self):
693 def set_span_type (self, type):
694 self.span_type = {'up': 1, 'down': -1}.get (type, 0)
695 def ly_octave_shift_indicator (self):
696 # convert 8/15 to lilypond indicators (+-1/+-2)
697 value = {8: 1, 15: 2}.get (self.size, 0)
698 # negative values go up!
699 value *= -1*self.span_type
701 def ly_expression (self):
702 dir = self.ly_octave_shift_indicator ()
705 value = '#(set-octavation %s)' % dir
708 1: '#(set-octavation 0)'}.get (self.span_direction, '')
710 class TrillSpanEvent (SpanEvent):
711 def ly_expression (self):
712 return {-1: '\\startTrillSpan',
713 0: '', # no need to write out anything for type='continue'
714 1:'\\stopTrillSpan'}.get (self.span_direction, '')
716 class GlissandoEvent (SpanEvent):
717 def ly_expression (self):
719 # TODO: wavy-line glissandos don't work, becasue the style has to be
720 # set before the note, at the \glissando it's already too late!
721 #if self.line_type == 'wavy':
722 #style = "\once\override Glissando #'style = #'zigzag"
723 # In lilypond, glissando is NOT a spanner, unlike MusicXML.
724 return {-1: style + '\\glissando',
725 1:''}.get (self.span_direction, '')
727 class ArpeggioEvent(Event):
729 Event.__init__ (self)
731 def wait_for_note (self):
733 def ly_expression (self):
734 # TODO: Use self.direction for up/down arpeggios
735 return ('\\arpeggio')
738 class TieEvent(Event):
739 def ly_expression (self):
743 class HairpinEvent (SpanEvent):
744 def set_span_type (self, type):
745 self.span_type = {'crescendo' : 1, 'decrescendo' : -1, 'diminuendo' : -1 }.get (type, 0)
746 def hairpin_to_ly (self):
747 if self.span_direction == 1:
750 return {1: '\<', -1: '\>'}.get (self.span_type, '')
752 def ly_expression (self):
753 return self.hairpin_to_ly ()
755 def print_ly (self, printer):
756 val = self.hairpin_to_ly ()
762 class DynamicsEvent (Event):
765 self.available_commands = [ "ppppp", "pppp", "ppp", "pp", "p",
767 "f", "ff", "fff", "ffff",
768 "fp", "sf", "sff", "sp", "spp", "sfz", "rfz" ];
769 def wait_for_note (self):
771 def ly_expression (self):
772 if self.type == None:
774 elif self.type in self.available_commands:
775 return '\%s' % self.type
777 return '-\markup{ \dynamic %s }' % self.type
779 def print_ly (self, printer):
780 if self.type == None:
782 elif self.type in self.available_commands:
783 printer.dump ("\\%s" % self.type)
785 printer.dump ("-\\markup{ \\dynamic %s }" % self.type)
788 class TextEvent (Event):
791 self.force_direction = None
793 def wait_for_note (self):
796 def direction_mod (self):
797 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
799 def ly_expression (self):
800 base_string = '%s\"%s\"'
802 base_string = '%s\markup{ ' + self.markup + ' {%s} }'
803 return base_string % (self.direction_mod (), self.text)
805 class ArticulationEvent (Event):
808 self.force_direction = None
809 def wait_for_note (self):
812 def direction_mod (self):
813 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')
815 def ly_expression (self):
816 return '%s\\%s' % (self.direction_mod (), self.type)
818 class ShortArticulationEvent (ArticulationEvent):
819 def direction_mod (self):
821 return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '-')
822 def ly_expression (self):
824 return '%s%s' % (self.direction_mod (), self.type)
828 class NoDirectionArticulationEvent (ArticulationEvent):
829 def ly_expression (self):
831 return '\\%s' % self.type
835 class MarkupEvent (ShortArticulationEvent):
837 ArticulationEvent.__init__ (self)
839 def ly_expression (self):
841 return "%s\\markup { %s }" % (self.direction_mod (), self.contents)
845 class FretEvent (MarkupEvent):
847 MarkupEvent.__init__ (self)
848 self.force_direction = 1
853 def ly_expression (self):
855 if self.strings <> 6:
856 val += "w:%s;" % self.strings
858 val += "h:%s;" % self.frets
859 if self.barre and len (self.barre) >= 3:
860 val += "c:%s-%s-%s;" % (self.barre[0], self.barre[1], self.barre[2])
861 have_fingering = False
862 for i in self.elements:
864 val += "%s-%s" % (i[0], i[1])
866 have_fingering = True
872 return "%s\\markup { \\fret-diagram #\"%s\" }" % (self.direction_mod (), val)
876 class TremoloEvent (ArticulationEvent):
878 Event.__init__ (self)
881 def ly_expression (self):
883 if self.bars and self.bars > 0:
884 str += ':%s' % (2 ** (2 + string.atoi (self.bars)))
887 class BendEvent (ArticulationEvent):
889 Event.__init__ (self)
891 def ly_expression (self):
893 return "-\\bendAfter #%s" % self.alter
897 class RhythmicEvent(Event):
899 Event.__init__ (self)
900 self.duration = Duration()
902 def get_length (self):
903 return self.duration.get_length()
905 def get_properties (self):
906 return ("'duration %s"
907 % self.duration.lisp_expression ())
909 class RestEvent (RhythmicEvent):
911 RhythmicEvent.__init__ (self)
913 def ly_expression (self):
915 return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ())
917 return 'r%s' % self.duration.ly_expression ()
919 def print_ly (self, printer):
921 self.pitch.print_ly (printer)
922 self.duration.print_ly (printer)
926 self.duration.print_ly (printer)
928 class SkipEvent (RhythmicEvent):
929 def ly_expression (self):
930 return 's%s' % self.duration.ly_expression ()
932 class NoteEvent(RhythmicEvent):
934 RhythmicEvent.__init__ (self)
936 self.drum_type = None
937 self.cautionary = False
938 self.forced_accidental = False
940 def get_properties (self):
941 str = RhythmicEvent.get_properties (self)
944 str += self.pitch.lisp_expression ()
946 str += "'drum-type '%s" % self.drum_type
950 def pitch_mods (self):
954 if self.forced_accidental:
959 def ly_expression (self):
961 return '%s%s%s' % (self.pitch.ly_expression (),
963 self.duration.ly_expression ())
965 return '%s%s' (self.drum_type,
966 self.duration.ly_expression ())
968 def print_ly (self, printer):
970 self.pitch.print_ly (printer)
971 printer (self.pitch_mods ())
973 printer (self.drum_type)
975 self.duration.print_ly (printer)
977 class KeySignatureChange (Music):
979 Music.__init__ (self)
984 def ly_expression (self):
985 return '\\key %s \\%s' % (self.tonic.ly_step_expression (),
988 def lisp_expression (self):
989 pairs = ['(%d . %d)' % (i , self.scale[i]) for i in range (0,7)]
990 scale_str = ("'(%s)" % string.join (pairs))
992 return """ (make-music 'KeyChangeEvent
993 'pitch-alist %s) """ % scale_str
995 class TimeSignatureChange (Music):
997 Music.__init__ (self)
998 self.fraction = (4,4)
999 def ly_expression (self):
1000 return '\\time %d/%d ' % self.fraction
1002 class ClefChange (Music):
1003 def __init__ (self):
1004 Music.__init__ (self)
1009 def octave_modifier (self):
1010 return {1: "^8", 2: "^15", -1: "_8", -2: "_15"}.get (self.octave, '')
1011 def clef_name (self):
1012 return {('G', 2): "treble",
1014 ('C', 1): "soprano",
1015 ('C', 2): "mezzosoprano",
1018 ('C', 5): "baritone",
1019 ('F', 3): "varbaritone",
1021 ('F', 5): "subbass",
1022 ("percussion", 2): "percussion",
1023 ("TAB", 5): "tab"}.get ((self.type, self.position), None)
1024 def ly_expression (self):
1025 return '\\clef "%s%s"' % (self.clef_name (), self.octave_modifier ())
1028 "G": ("clefs.G", -2, -6),
1029 "C": ("clefs.C", 0, 0),
1030 "F": ("clefs.F", 2, 6),
1033 def lisp_expression (self):
1035 (glyph, pos, c0) = self.clef_dict[self.type]
1039 (make-music 'SequentialMusic
1042 (make-property-set 'clefGlyph "%s") 'Staff)
1044 (make-property-set 'clefPosition %d) 'Staff)
1046 (make-property-set 'middleCPosition %d) 'Staff)))
1047 """ % (glyph, pos, c0)
1051 class StaffChange (Music):
1052 def __init__ (self, staff):
1053 Music.__init__ (self)
1055 def ly_expression (self):
1057 return "\\change Staff=\"%s\"" % self.staff
1062 class MultiMeasureRest(Music):
1064 def lisp_expression (self):
1067 'MultiMeasureRestMusicGroup
1069 (list (make-music (quote BarCheck))
1074 'MultiMeasureRestEvent
1077 (make-music (quote BarCheck))))
1078 """ % self.duration.lisp_expression ()
1080 def ly_expression (self):
1081 return 'R%s' % self.duration.ly_expression ()
1085 def __init__ (self, command = "StaffGroup"):
1086 self.stafftype = command
1088 self.instrument_name = None
1089 self.short_instrument_name = None
1093 self.is_group = True
1094 # part_information is a list with entries of the form
1095 # [staffid, voicelist]
1096 # where voicelist is a list with entries of the form
1097 # [voiceid1, [lyricsid11, lyricsid12,...] ]
1098 self.part_information = None
1100 def append_staff (self, staff):
1101 self.children.append (staff)
1103 def set_part_information (self, part_name, staves_info):
1104 if part_name == self.id:
1105 self.part_information = staves_info
1107 for c in self.children:
1108 c.set_part_information (part_name, staves_info)
1110 def print_ly_contents (self, printer):
1111 for c in self.children:
1113 c.print_ly (printer)
1114 def print_ly_overrides (self, printer):
1116 needs_with |= self.spanbar == "no"
1117 needs_with |= self.instrument_name != None
1118 needs_with |= self.short_instrument_name != None
1119 needs_with |= (self.symbol != None) and (self.symbol != "bracket")
1121 printer.dump ("\\with {")
1122 if self.instrument_name or self.short_instrument_name:
1123 printer.dump ("\\consists \"Instrument_name_engraver\"")
1124 if self.spanbar == "no":
1125 printer.dump ("\\override SpanBar #'transparent = ##t")
1126 brack = {"brace": "SystemStartBrace",
1128 "line": "SystemStartSquare"}.get (self.symbol, None)
1130 printer.dump ("systemStartDelimiter = #'%s" % brack)
1133 def print_ly (self, printer):
1135 printer.dump ("\\new %s" % self.stafftype)
1136 self.print_ly_overrides (printer)
1139 if self.stafftype and self.instrument_name:
1140 printer.dump ("\\set %s.instrumentName = %s" % (self.stafftype,
1141 escape_instrument_string (self.instrument_name)))
1143 if self.stafftype and self.short_instrument_name:
1144 printer.dump ("\\set %s.shortInstrumentName = %s" % (self.stafftype,
1145 escape_instrument_string (self.short_instrument_name)))
1147 self.print_ly_contents (printer)
1153 class Staff (StaffGroup):
1154 def __init__ (self, command = "Staff"):
1155 StaffGroup.__init__ (self, command)
1156 self.is_group = False
1158 self.voice_command = "Voice"
1159 self.substafftype = None
1161 def print_ly_overrides (self, printer):
1164 def print_ly_contents (self, printer):
1165 if not self.id or not self.part_information:
1167 sub_staff_type = self.substafftype
1168 if not sub_staff_type:
1169 sub_staff_type = self.stafftype
1171 for [staff_id, voices] in self.part_information:
1173 printer ('\\context %s = "%s" << ' % (sub_staff_type, staff_id))
1175 printer ('\\context %s << ' % sub_staff_type)
1178 nr_voices = len (voices)
1179 for [v, lyrics] in voices:
1181 voice_count_text = ''
1183 voice_count_text = {1: ' \\voiceOne', 2: ' \\voiceTwo',
1184 3: ' \\voiceThree'}.get (n, ' \\voiceFour')
1185 printer ('\\context %s = "%s" {%s \\%s }' % (self.voice_command, v, voice_count_text, v))
1189 printer ('\\new Lyrics \\lyricsto "%s" \\%s' % (v,l))
1193 def print_ly (self, printer):
1194 if self.part_information and len (self.part_information) > 1:
1195 self.stafftype = "PianoStaff"
1196 self.substafftype = "Staff"
1197 StaffGroup.print_ly (self, printer)
1199 class TabStaff (Staff):
1200 def __init__ (self, command = "TabStaff"):
1201 Staff.__init__ (self, command)
1202 self.string_tunings = []
1203 self.tablature_format = None
1204 self.voice_command = "TabVoice"
1205 def print_ly_overrides (self, printer):
1206 if self.string_tunings or self.tablature_format:
1207 printer.dump ("\\with {")
1208 if self.string_tunings:
1209 printer.dump ("stringTunings = #'(")
1210 for i in self.string_tunings:
1211 printer.dump ("%s" % i.semitones ())
1213 if self.tablature_format:
1214 printer.dump ("tablatureFormat = #%s" % self.tablature_format)
1218 class DrumStaff (Staff):
1219 def __init__ (self, command = "DrumStaff"):
1220 Staff.__init__ (self, command)
1221 self.drum_style_table = None
1222 self.voice_command = "DrumVoice"
1223 def print_ly_overrides (self, printer):
1224 if self.drum_style_table:
1225 printer.dump ("\with {")
1226 printer.dump ("drumStyleTable = #%s" % self.drum_style_table)
1229 class RhythmicStaff (Staff):
1230 def __init__ (self, command = "RhythmicStaff"):
1231 Staff.__init__ (self, command)
1236 bflat.alteration = -1
1246 print bflat.semitones()
1247 print bflat.transposed (fifth), bflat.transposed (fifth).transposed (fifth)
1248 print bflat.transposed (fifth).transposed (fifth).transposed (fifth)
1250 print bflat.semitones(), 'down'
1251 print bflat.transposed (down)
1252 print bflat.transposed (down).transposed (down)
1253 print bflat.transposed (down).transposed (down).transposed (down)
1257 def test_printer ():
1265 m = SequentialMusic()
1266 m.append (make_note ())
1267 m.append (make_note ())
1268 m.append (make_note ())
1271 t = TimeScaledMusic ()
1277 m = SequentialMusic ()
1278 m.append (make_tup ())
1279 m.append (make_tup ())
1280 m.append (make_tup ())
1282 printer = Output_printer()
1283 m.print_ly (printer)
1287 m = SequentialMusic()
1291 n.duration.duration_log = l
1293 evc.insert_around (None, n, 0)
1294 m.insert_around (None, evc, 0)
1298 n.duration.duration_log = l
1300 evc.insert_around (None, n, 0)
1301 m.insert_around (None, evc, 0)
1305 n.duration.duration_log = l
1307 evc.insert_around (None, n, 0)
1308 m.insert_around (None, evc, 0)
1312 m.insert_around (None, evc, 0)
1317 tonic.alteration = -2
1318 n = KeySignatureChange()
1319 n.tonic=tonic.copy()
1320 n.scale = [0, 0, -2, 0, 0,-2,-2]
1322 evc.insert_around (None, n, 0)
1323 m.insert_around (None, evc, 0)
1328 if __name__ == '__main__':
1334 expr.set_start (Rational (0))
1335 print expr.ly_expression()
1336 start = Rational (0,4)
1337 stop = Rational (4,2)
1338 def sub(x, start=start, stop=stop):
1339 ok = x.start >= start and x.start +x.get_length() <= stop
1342 print expr.lisp_sub_expression(sub)