From: Reinhold Kainhofer Date: Fri, 7 Nov 2008 19:22:40 +0000 (+0100) Subject: MusicXML: Implement after-grace notes X-Git-Tag: release/2.11.64-1~37 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=da149e7eb387ccac51e0094a9293f4036a665372;p=lilypond.git MusicXML: Implement after-grace notes also convert all grace notes at the end of a measure to after-graces, otherwise they won't appear at all... --- diff --git a/input/regression/musicxml/04g-Trill-EndingOnGraceNote-Finale.xml b/input/regression/musicxml/04g-Trill-EndingOnGraceNote-Finale.xml new file mode 100644 index 0000000000..5576ce7aba --- /dev/null +++ b/input/regression/musicxml/04g-Trill-EndingOnGraceNote-Finale.xml @@ -0,0 +1,155 @@ + + + + Sonata No. 2 + + Simon Bielman + + Finale 2007 for Windows + Dolet Light for Finale 2007 + 2008-08-20 + + + + + Piano + + Acoustic Grand Piano + + + 1 + 1 + + + + + + + + 336 + + 0 + major + + + 2 + + G + 2 + + + F + 4 + + + + + E + 5 + + 336 + 1 + quarter + down + 1 + + + + + + + F + 1 + 5 + + 84 + 1 + 16th + sharp + down + 1 + begin + begin + + + + G + 5 + + 84 + 1 + 16th + down + 1 + end + end + + + + + + + + + + + + B + 5 + + 1 + 16th + up + 1 + + + + A + 5 + + 504 + 1 + quarter + + down + 1 + + + + + G + 5 + + 1 + 16th + up + 1 + begin + begin + + + + + A + 5 + + 1 + 16th + up + 1 + end + end + + + + + + + + + + diff --git a/input/regression/musicxml/13d-AfterGrace.xml b/input/regression/musicxml/13d-AfterGrace.xml new file mode 100644 index 0000000000..a6662a4d49 --- /dev/null +++ b/input/regression/musicxml/13d-AfterGrace.xml @@ -0,0 +1,128 @@ + + + + Sonata No. 2 + + Simon Bielman + + Finale 2007 for Windows + Dolet Light for Finale 2007 + 2008-08-20 + + + + + Piano + + Acoustic Grand Piano + + + 1 + 1 + + + + + + + + 32 + + 0 + major + + + + G + 2 + + + + + E + 5 + + 64 + 1 + half + down + 1 + + + + + G + 5 + + 1 + 16th + up + 1 + + + + + A + 5 + + 1 + 16th + up + 1 + + + + + A + 5 + + 1 + 16th + up + 1 + + + + E + 5 + + 64 + 1 + half + down + 1 + + + + + G + 5 + + 1 + 16th + up + 1 + begin + begin + + + + + A + 5 + + 1 + 16th + up + 1 + end + end + + + + + diff --git a/python/musicexp.py b/python/musicexp.py index 9d9ea96dc6..22cfcdcd53 100644 --- a/python/musicexp.py +++ b/python/musicexp.py @@ -706,6 +706,7 @@ class Layout: class ChordEvent (NestedMusic): def __init__ (self): NestedMusic.__init__ (self) + self.after_grace_elements = None self.grace_elements = None self.grace_type = None def append_grace (self, element): @@ -713,6 +714,16 @@ class ChordEvent (NestedMusic): if not self.grace_elements: self.grace_elements = SequentialMusic () self.grace_elements.append (element) + def append_after_grace (self, element): + if element: + if not self.after_grace_elements: + self.after_grace_elements = SequentialMusic () + self.after_grace_elements.append (element) + + def has_elements (self): + return [e for e in self.elements if + isinstance (e, NoteEvent) or isinstance (e, RestEvent)] != [] + def get_length (self): l = Rational (0) @@ -739,6 +750,9 @@ class ChordEvent (NestedMusic): other_events = [e for e in self.elements if not isinstance (e, RhythmicEvent)] + if self.after_grace_elements: + printer ('\\afterGrace {') + if self.grace_elements and self.elements: if self.grace_type: printer ('\\%s' % self.grace_type) @@ -746,6 +760,15 @@ class ChordEvent (NestedMusic): printer ('\\grace') # don't print newlines after the { and } braces self.grace_elements.print_ly (printer, False) + elif self.grace_elements: # no self.elements! + warning (_ ("Grace note with no following music: %s") % self.grace_elements) + if self.grace_type: + printer ('\\%s' % self.grace_type) + else: + printer ('\\grace') + self.grace_elements.print_ly (printer, False) + printer ('{}') + # Print all overrides and other settings needed by the # articulations/ornaments before the note for e in other_events: @@ -777,6 +800,10 @@ class ChordEvent (NestedMusic): for e in other_events: e.print_after_note (printer) + if self.after_grace_elements: + printer ('}') + self.after_grace_elements.print_ly (printer, False) + self.print_comment (printer) class Partial (Music): diff --git a/python/musicxml.py b/python/musicxml.py index 295bdb326b..4bee0f10dc 100644 --- a/python/musicxml.py +++ b/python/musicxml.py @@ -352,7 +352,15 @@ class Note (Measure_element): def __init__ (self): Measure_element.__init__ (self) self.instrument_name = '' - + self._after_grace = False + def is_grace (self): + return self.get_maybe_exist_named_child (u'grace') + def is_after_grace (self): + if not self.is_grace(): + return False; + gr = self.get_maybe_exist_typed_child (Grace) + return self._after_grace or hasattr (gr, 'steal-time-previous'); + def get_duration_log (self): ch = self.get_maybe_exist_named_child (u'type') @@ -522,6 +530,9 @@ class Part (Music_xml_node): measure_start_moment = now is_first_measure = True previous_measure = None + # Graces at the end of a measure need to have their position set to the + # previous number! + pending_graces = [] for m in measures: # implicit measures are used for artificial measures, e.g. when # a repeat bar line splits a bar into two halves. In this case, @@ -575,6 +586,12 @@ class Part (Music_xml_node): if n.get_name() == 'backup': dur = - dur + # reset all graces before the backup to after-graces: + for n in pending_graces: + n._when = n._prev_when + n._measure_position = n._prev_measure_position + n._after_grace = True + pending_graces = [] if n.get_maybe_exist_typed_child (Grace): dur = Rational (0) @@ -592,6 +609,23 @@ class Part (Music_xml_node): n._when = now n._measure_position = measure_position + + # For all grace notes, store the previous note, in case need + # to turn the grace note into an after-grace later on! + if isinstance(n, Note) and n.is_grace (): + n._prev_when = last_moment + n._prev_measure_position = last_measure_position + # After-graces are placed at the same position as the previous note + if isinstance(n, Note) and n.is_after_grace (): + # TODO: We should do the same for grace notes at the end of + # a measure with no following note!!! + n._when = last_moment + n._measure_position = last_measure_position + elif isinstance(n, Note) and n.is_grace (): + pending_graces.append (n) + elif (dur > Rational (0)): + pending_graces = []; + n._duration = dur if dur > Rational (0): last_moment = now @@ -613,6 +647,12 @@ class Part (Music_xml_node): if instrument: n.instrument_name = part_list.get_instrument (instrument.id) + # reset all graces at the end of the measure to after-graces: + for n in pending_graces: + n._when = n._prev_when + n._measure_position = n._prev_measure_position + n._after_grace = True + pending_graces = [] # Incomplete first measures are not padded, but registered as partial if is_first_measure: is_first_measure = False diff --git a/scripts/musicxml2ly.py b/scripts/musicxml2ly.py index 695f855d49..50d2a0b67d 100644 --- a/scripts/musicxml2ly.py +++ b/scripts/musicxml2ly.py @@ -1763,8 +1763,10 @@ def musicxml_voice_to_lily_voice (voice): if a: voice_builder.add_partial (a) continue + is_chord = n.get_maybe_exist_named_child ('chord') - if not is_chord: + is_after_grace = (isinstance (n, musicxml.Note) and n.is_after_grace ()); + if not is_chord and not is_after_grace: try: voice_builder.jumpto (n._when) except NegativeSkip, neg: @@ -1857,15 +1859,31 @@ def musicxml_voice_to_lily_voice (voice): ev_chord = musicexp.ChordEvent() voice_builder.add_music (ev_chord, n._duration) + # For grace notes: grace = n.get_maybe_exist_typed_child (musicxml.Grace) - if grace: + if n.is_grace (): + is_after_grace = ev_chord.has_elements () or n.is_after_grace (); + is_chord = n.get_maybe_exist_typed_child (musicxml.Chord) + grace_chord = None - if n.get_maybe_exist_typed_child (musicxml.Chord) and ev_chord.grace_elements: - grace_chord = ev_chord.grace_elements.get_last_event_chord () - if not grace_chord: - grace_chord = musicexp.ChordEvent () - ev_chord.append_grace (grace_chord) - if hasattr (grace, 'slash'): + + # after-graces and other graces use different lists; Depending on + # whether we have a chord or not, obtain either a new ChordEvent or + # the previous one to create a chord + if is_after_grace: + if ev_chord.after_grace_elements and n.get_maybe_exist_typed_child (musicxml.Chord): + grace_chord = ev_chord.after_grace_elements.get_last_event_chord () + if not grace_chord: + grace_chord = musicexp.ChordEvent () + ev_chord.append_after_grace (grace_chord) + elif n.is_grace (): + if ev_chord.grace_elements and n.get_maybe_exist_typed_child (musicxml.Chord): + grace_chord = ev_chord.grace_elements.get_last_event_chord () + if not grace_chord: + grace_chord = musicexp.ChordEvent () + ev_chord.append_grace (grace_chord) + + if hasattr (grace, 'slash') and not is_after_grace: # TODO: use grace_type = "appoggiatura" for slurred grace notes if grace.slash == "yes": ev_chord.grace_type = "acciaccatura" @@ -1926,7 +1944,7 @@ def musicxml_voice_to_lily_voice (voice): frac = (1,1) if mod: frac = mod.get_fraction () - + tuplet_events.append ((ev_chord, tuplet_event, frac)) # First, close all open slurs, only then start any new slur @@ -2020,7 +2038,7 @@ def musicxml_voice_to_lily_voice (voice): for a in ornaments: for ch in a.get_all_children (): ev = musicxml_articulation_to_lily_event (ch) - if ev: + if ev: ev_chord.append (ev) dynamics = notations.get_named_children ('dynamics')