From 665e9d74204d0b97d1fe865f816b199a1b7d4f74 Mon Sep 17 00:00:00 2001 From: Reinhold Kainhofer Date: Mon, 11 Feb 2008 17:40:18 +0100 Subject: [PATCH] MusicXML: Implement dashed slurs, glissando styles, directed and non-arpeggios Since I added functions print_before_note and print_after_note to the Event class, it's now possible to apply individual settings to things like glissando or slurs just once (using \once\override before the note). Also a --- ...JB.xml => 02b-Articulations-Texts-PJB.xml} | 0 ...l => 02c-MultipleNotationChildren-RFK.xml} | 0 input/regression/musicxml/02d-Arpeggio.xml | 242 ++++++++++++++ input/regression/musicxml/04b-Glissando.xml | 316 ++++++++++++++++++ python/musicexp.py | 80 +++-- python/musicxml.py | 4 + scripts/musicxml2ly.py | 26 +- 7 files changed, 640 insertions(+), 28 deletions(-) rename input/regression/musicxml/{02i-Articulations-Texts-PJB.xml => 02b-Articulations-Texts-PJB.xml} (100%) rename input/regression/musicxml/{02h-MultipleNotationChildren-RFK.xml => 02c-MultipleNotationChildren-RFK.xml} (100%) create mode 100644 input/regression/musicxml/02d-Arpeggio.xml create mode 100644 input/regression/musicxml/04b-Glissando.xml diff --git a/input/regression/musicxml/02i-Articulations-Texts-PJB.xml b/input/regression/musicxml/02b-Articulations-Texts-PJB.xml similarity index 100% rename from input/regression/musicxml/02i-Articulations-Texts-PJB.xml rename to input/regression/musicxml/02b-Articulations-Texts-PJB.xml diff --git a/input/regression/musicxml/02h-MultipleNotationChildren-RFK.xml b/input/regression/musicxml/02c-MultipleNotationChildren-RFK.xml similarity index 100% rename from input/regression/musicxml/02h-MultipleNotationChildren-RFK.xml rename to input/regression/musicxml/02c-MultipleNotationChildren-RFK.xml diff --git a/input/regression/musicxml/02d-Arpeggio.xml b/input/regression/musicxml/02d-Arpeggio.xml new file mode 100644 index 0000000000..97e33b15ff --- /dev/null +++ b/input/regression/musicxml/02d-Arpeggio.xml @@ -0,0 +1,242 @@ + + + + Arpeggios in MusicXML + + + + + + + + + + + + + 1 + + 0 + major + + + G + 2 + + + + + C4 + + 1 + 1 + quarter + + normal + + + + + E5 + + 1 + 1 + quarter + + + + + + G5 + + 1 + 1 + quarter + + + + + C4 + + 1 + 1 + quarter + + up + + + + + E5 + + 1 + 1 + quarter + + + + + + G5 + + 1 + 1 + quarter + + + + + C4 + + 1 + 1 + quarter + + normal + + + + + E5 + + 1 + 1 + quarter + + + + + + G5 + + 1 + 1 + quarter + + + + + C4 + + 1 + 1 + quarter + + down + + + + + E5 + + 1 + 1 + quarter + + + + + + G5 + + 1 + 1 + quarter + + + + + C4 + + 1 + 1 + quarter + + normal + + + + + E5 + + 1 + 1 + quarter + + + + + + G5 + + 1 + 1 + quarter + + + + + C4 + + 1 + 1 + quarter + + non-arp. + + + + + E5 + + 1 + 1 + quarter + + + + + G5 + + 1 + 1 + quarter + + + + + C4 + + 1 + 1 + quarter + + normal + + + + + E5 + + 1 + 1 + quarter + + + + + + G5 + + 1 + 1 + quarter + + + + light-heavy + + + + diff --git a/input/regression/musicxml/04b-Glissando.xml b/input/regression/musicxml/04b-Glissando.xml new file mode 100644 index 0000000000..a9e0e0a7da --- /dev/null +++ b/input/regression/musicxml/04b-Glissando.xml @@ -0,0 +1,316 @@ + + + + Glissando and Slide in MusicXML + + + + + + + + + + + + + 1 + + 0 + major + + + G + 2 + + + + + G + 4 + + 1 + 1 + quarter + down + + + + normal + + + + F + 5 + + 1 + 1 + quarter + down + + + + glissando + + + + G + 4 + + 1 + 1 + quarter + down + + text + + solid + + + + F + 5 + + 1 + 1 + quarter + down + + + + (+text) + + + + + + G + 4 + + 1 + 1 + quarter + down + + + + dashed + + + + F + 5 + + 1 + 1 + quarter + down + + + + + + + G + 4 + + 1 + 1 + quarter + down + + + + dotted + + + + F + 5 + + 1 + 1 + quarter + down + + + + + + + + + G + 4 + + 1 + 1 + quarter + down + + + + wavy + + + + F + 5 + + 1 + 1 + quarter + down + + + + + + + G + 4 + + 1 + 1 + quarter + down + + + + normal + + + + F + 5 + + 1 + 1 + quarter + down + + + + slide + + + + + + G + 4 + + 1 + 1 + quarter + down + + text + + solid + + + + F + 5 + + 1 + 1 + quarter + down + + + + (+text) + + + + G + 4 + + 1 + 1 + quarter + down + + + + dashed + + + + F + 5 + + 1 + 1 + quarter + down + + + + + + + + + G + 4 + + 1 + 1 + quarter + down + + + + dotted + + + + F + 5 + + 1 + 1 + quarter + down + + + + + + + G + 4 + + 1 + 1 + quarter + down + + + + wavy + + + + F + 5 + + 1 + 1 + quarter + down + + + + + + + light-heavy + + + + diff --git a/python/musicexp.py b/python/musicexp.py index f68c17ce19..07af416ab7 100644 --- a/python/musicexp.py +++ b/python/musicexp.py @@ -697,6 +697,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 +723,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 +762,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,24 +792,23 @@ 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): @@ -836,24 +855,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 + 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') @@ -883,6 +915,7 @@ class HairpinEvent (SpanEvent): class DynamicsEvent (Event): def __init__ (self): + Event.__init__ (self) self.type = None def wait_for_note (self): return True @@ -898,6 +931,7 @@ class DynamicsEvent (Event): class MarkEvent (Event): def __init__ (self, text="\\default"): + Event.__init__ (self) self.mark = text def wait_for_note (self): return False @@ -919,6 +953,7 @@ class MusicGlyphMarkEvent (MarkEvent): class TextEvent (Event): def __init__ (self): + Event.__init__ (self) self.Text = None self.force_direction = None self.markup = '' @@ -936,6 +971,7 @@ class TextEvent (Event): class ArticulationEvent (Event): def __init__ (self): + Event.__init__ (self) self.type = None self.force_direction = None def wait_for_note (self): diff --git a/python/musicxml.py b/python/musicxml.py index a08afb0814..f96895f638 100644 --- a/python/musicxml.py +++ b/python/musicxml.py @@ -776,6 +776,9 @@ class Pedal (Music_xml_spanner): class Glissando (Music_xml_spanner): pass +class Slide (Music_xml_spanner): + pass + class Octave_shift (Music_xml_spanner): # default is 8 for the octave-shift! def get_size (self): @@ -898,6 +901,7 @@ class_dict = { 'pitch': Pitch, 'rest': Rest, 'score-part': Score_part, + 'slide': Slide, 'slur': Slur, 'staff': Staff, 'syllabic': Syllabic, diff --git a/scripts/musicxml2ly.py b/scripts/musicxml2ly.py index a163522750..b982633348 100644 --- a/scripts/musicxml2ly.py +++ b/scripts/musicxml2ly.py @@ -190,9 +190,9 @@ class PartGroupInfo: def add_end (self, g): self.end[getattr (g, 'number', "1")] = g def print_ly (self, printer): - error_message ("Unprocessed PartGroupInfo %s encountered" % self) + error_message (_ ("Unprocessed PartGroupInfo %s encountered") % self) def ly_expression (self): - error_message ("Unprocessed PartGroupInfo %s encountered" % self) + error_message (_ ("Unprocessed PartGroupInfo %s encountered") % self) return '' def staff_attributes_to_string_tunings (mxl_attr): @@ -606,7 +606,7 @@ def musicxml_key_to_lily (attributes): start_pitch.step = n start_pitch.alteration = a except KeyError: - error_message ('unknown mode %s' % mode) + error_message (_ ("unknown mode %s, expecting 'major' or 'minor'") % mode) fifth = musicexp.Pitch() fifth.step = 4 @@ -711,6 +711,7 @@ spanner_event_dict = { 'glissando' : musicexp.GlissandoEvent, 'octave-shift' : musicexp.OctaveShiftEvent, 'pedal' : musicexp.PedalEvent, + 'slide' : musicexp.GlissandoEvent, 'slur' : musicexp.SlurEvent, 'wavy-line' : musicexp.TrillSpanEvent, 'wedge' : musicexp.HairpinEvent @@ -758,7 +759,7 @@ def musicxml_spanner_to_lily_event (mxl_event): return ev def musicxml_direction_to_indicator (direction): - return { "above": 1, "upright": 1, "up":1, "below": -1, "downright": -1, "down": -1, "inverted": -1 }.get (direction, 0) + return { "above": 1, "upright": 1, "up": 1, "below": -1, "downright": -1, "down": -1, "inverted": -1 }.get (direction, 0) def musicxml_fermata_to_lily_event (mxl_event): ev = musicexp.ArticulationEvent () @@ -776,6 +777,12 @@ def musicxml_arpeggiate_to_lily_event (mxl_event): ev.direction = musicxml_direction_to_indicator (getattr (mxl_event, 'direction', None)) return ev +def musicxml_nonarpeggiate_to_lily_event (mxl_event): + ev = musicexp.ArpeggioEvent () + ev.non_arpeggiate = True + ev.direction = musicxml_direction_to_indicator (getattr (mxl_event, 'direction', None)) + return ev + def musicxml_tremolo_to_lily_event (mxl_event): ev = musicexp.TremoloEvent () txt = mxl_event.get_text () @@ -1334,7 +1341,7 @@ class LilyPondVoiceBuilder: diff = moment - current_end if diff < Rational (0): - error_message ('Negative skip %s' % diff) + error_message (_ ('Negative skip %s') % diff) diff = Rational (0) if diff > Rational (0) and not (self.ignore_skips and moment == 0): @@ -1601,7 +1608,14 @@ def musicxml_voice_to_lily_voice (voice): if ev: ev_chord.append (ev) + arpeggiate = notations.get_named_children ('non-arpeggiate') + for a in arpeggiate: + ev = musicxml_nonarpeggiate_to_lily_event (a) + if ev: + ev_chord.append (ev) + glissandos = notations.get_named_children ('glissando') + glissandos += notations.get_named_children ('slide') for a in glissandos: ev = musicxml_spanner_to_lily_event (a) if ev: @@ -1893,7 +1907,7 @@ def update_score_setup (score_structure, part_list, voices): part_id = part_definition.id nv_dict = voices.get (part_id) if not nv_dict: - error_message ('unknown part in part-list: %s' % part_id) + error_message (_ ('unknown part in part-list: %s') % part_id) continue staves = reduce (lambda x,y: x+ y, -- 2.39.2