X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=python%2Fmusicexp.py;h=862b5d8c4f70f5148c0a5b1899588b1859014c59;hb=76c76ae6a8328b0ad69f183cc7c36e166f15bd05;hp=07e4f5d7928f42f476ea17dfc3c0ad48238eb2e6;hpb=8d43e3ea585019009163fa20db9ba26432d92429;p=lilypond.git diff --git a/python/musicexp.py b/python/musicexp.py index 07e4f5d792..862b5d8c4f 100644 --- a/python/musicexp.py +++ b/python/musicexp.py @@ -2,6 +2,9 @@ import inspect import sys import string import re +import lilylib as ly + +_ = ly._ from rational import Rational @@ -9,6 +12,10 @@ from rational import Rational previous_pitch = None relative_pitches = False +def warning (str): + ly.stderr_write ((_ ("warning: %s") % str) + "\n") + + def escape_instrument_string (input_string): retstring = string.replace (input_string, "\"", "\\\"") if re.match ('.*[\r\n]+.*', retstring): @@ -148,8 +155,12 @@ class Duration: def ly_expression (self, factor = None): if not factor: factor = self.factor - - str = '%d%s' % (1 << self.duration_log, '.'*self.dots) + + if self.duration_log < 0: + str = {-1: "\\breve", -2: "\\longa"}.get (self.duration_log, "1") + else: + str = '%d' % (1 << self.duration_log) + str += '.'*self.dots if factor <> Rational (1,1): if factor.denominator () <> 1: @@ -567,7 +578,8 @@ class RepeatedMusic: self.music = SequentialMusic () self.music.elements = music else: - sys.stderr.write ("WARNING: Unable to set the music %s for the repeat %s" % (music, self)) + warning (_ ("unable to set the music %(music)s for the repeat %(repeat)s" % \ + {'music':music, 'repeat':self})) def add_ending (self, music): self.endings.append (music) def print_ly (self, printer): @@ -575,7 +587,7 @@ class RepeatedMusic: if self.music: self.music.print_ly (printer) else: - sys.stderr.write ("WARNING: Encountered repeat without body\n") + warning (_ ("encountered repeat without body")) printer.dump ('{}') if self.endings: printer.dump ('\\alternative {') @@ -661,6 +673,31 @@ class Paper: printer.dump ('}') printer.newline () +class Layout: + def __init__ (self): + self.context_dict = {} + def add_context (self, context): + if not self.context_dict.has_key (context): + self.context_dict[context] = [] + def set_context_item (self, context, item): + self.add_context (context) + if not item in self.context_dict[context]: + self.context_dict[context].append (item) + def print_ly (self, printer): + if self.context_dict.items (): + printer.dump ('\\layout {') + printer.newline () + for (context, defs) in self.context_dict.items (): + printer.dump ('\\context { \\%s' % context) + printer.newline () + for d in defs: + printer.dump (d) + printer.newline () + printer.dump ('}') + printer.newline () + printer.dump ('}') + printer.newline () + class ChordEvent (NestedMusic): def __init__ (self): @@ -697,6 +734,10 @@ class ChordEvent (NestedMusic): printer ('\\grace') # don't print newlines after the { and } braces self.grace_elements.print_ly (printer, False) + # Print all overrides and other settings needed by the + # articulations/ornaments before the note + for e in other_events: + e.print_before_note (printer) if rest_events: rest_events[0].print_ly (printer) @@ -719,6 +760,9 @@ class ChordEvent (NestedMusic): for e in other_events: e.print_ly (printer) + for e in other_events: + e.print_after_note (printer) + self.print_comment (printer) class Partial (Music): @@ -755,6 +799,19 @@ class BarLine (Music): return " | " class Event(Music): + def __init__ (self): + # strings to print before the note to which an event is attached. + # Ignored for notes etc. + self.before_note = None + self.after_note = None + # print something before the note to which an event is attached, e.g. overrides + def print_before_note (self, printer): + if self.before_note: + printer.dump (self.before_note) + # print something after the note to which an event is attached, e.g. resetting + def print_after_note (self, printer): + if self.after_note: + printer.dump (self.after_note) pass class SpanEvent (Event): @@ -772,34 +829,44 @@ class SpanEvent (Event): self.span_type = type class SlurEvent (SpanEvent): + def print_before_note (self, printer): + command = {'dotted': '\\slurDotted', + 'dashed' : '\\slurDashed'}.get (self.line_type, '') + if command and self.span_direction == -1: + printer.dump (command) + def print_after_note (self, printer): + # reset non-solid slur types! + command = {'dotted': '\\slurSolid', + 'dashed' : '\\slurSolid'}.get (self.line_type, '') + if command and self.span_direction == -1: + printer.dump (command) def ly_expression (self): - 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, '') + return {-1: '(', 1:')'}.get (self.span_direction, '') class BeamEvent (SpanEvent): def ly_expression (self): - return {-1: '[', - 1:']'}.get (self.span_direction, '') + return {-1: '[', 1:']'}.get (self.span_direction, '') class PedalEvent (SpanEvent): def ly_expression (self): return {-1: '\\sustainDown', + 0:'\\sustainUp\\sustainDown', 1:'\\sustainUp'}.get (self.span_direction, '') -# type==-1 means octave up, type==-2 means octave down +class TextSpannerEvent (SpanEvent): + def ly_expression (self): + return {-1: '\\startTextSpan', + 1:'\\stopTextSpan'}.get (self.span_direction, '') + +class BracketSpannerEvent (SpanEvent): + def ly_expression (self): + return {-1: '\\startGroup', + 1:'\\stopGroup'}.get (self.span_direction, '') + + class OctaveShiftEvent (SpanEvent): def wait_for_note (self): - return False; + return False def set_span_type (self, type): self.span_type = {'up': 1, 'down': -1}.get (type, 0) def ly_octave_shift_indicator (self): @@ -824,24 +891,37 @@ class TrillSpanEvent (SpanEvent): 1:'\\stopTrillSpan'}.get (self.span_direction, '') class GlissandoEvent (SpanEvent): + def print_before_note (self, printer): + if self.span_direction == -1: + style= { + "dashed" : "dashed-line", + "dotted" : "dotted-line", + "wavy" : "zigzag" + }. get (self.line_type, None) + if style: + printer.dump ("\once \override Glissando #'style = #'%s" % style) 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', + return {-1: '\\glissando', 1:''}.get (self.span_direction, '') class ArpeggioEvent(Event): def __init__ (self): Event.__init__ (self) self.direction = 0 + self.non_arpeggiate = False def wait_for_note (self): - return True; + return True + def print_before_note (self, printer): + if self.non_arpeggiate: + printer.dump ("\\arpeggioBracket") + else: + dir = { -1: "\\arpeggioDown", 1: "\\arpeggioUp" }.get (self.direction, '') + if dir: + printer.dump (dir) + def print_after_note (self, printer): + if self.non_arpeggiate or self.direction: + printer.dump ("\\arpeggioNeutral") def ly_expression (self): - # TODO: Use self.direction for up/down arpeggios return ('\\arpeggio') @@ -871,22 +951,45 @@ class HairpinEvent (SpanEvent): class DynamicsEvent (Event): def __init__ (self): + Event.__init__ (self) self.type = None def wait_for_note (self): - return True; + return True def ly_expression (self): if self.type: return '\%s' % self.type else: - return; + return def print_ly (self, printer): if self.type: printer.dump ("\\%s" % self.type) +class MarkEvent (Event): + def __init__ (self, text="\\default"): + Event.__init__ (self) + self.mark = text + def wait_for_note (self): + return False + def ly_contents (self): + if self.mark: + return '%s' % self.mark + else: + return "\"ERROR\"" + def ly_expression (self): + return '\\mark %s' % self.ly_contents () + +class MusicGlyphMarkEvent (MarkEvent): + def ly_contents (self): + if self.mark: + return '\\markup { \\musicglyph #"scripts.%s" }' % self.mark + else: + return '' + class TextEvent (Event): def __init__ (self): + Event.__init__ (self) self.Text = None self.force_direction = None self.markup = '' @@ -904,10 +1007,11 @@ class TextEvent (Event): class ArticulationEvent (Event): def __init__ (self): + Event.__init__ (self) self.type = None self.force_direction = None def wait_for_note (self): - return True; + return True def direction_mod (self): return { 1: '^', -1: '_', 0: '-' }.get (self.force_direction, '')