]> git.donarmstrong.com Git - lilypond.git/commitdiff
MusicXML: Convert grace notes from MusicXML to Lilypond
authorReinhold Kainhofer <reinhold@kainhofer.com>
Sun, 16 Sep 2007 20:57:16 +0000 (22:57 +0200)
committerReinhold Kainhofer <reinhold@kainhofer.com>
Wed, 3 Oct 2007 16:39:23 +0000 (18:39 +0200)
Grace notes are normal <note> elements in XML, only with a <grace/>
child element. I append these notes to a special array of EventChord
and try to take care of the zero duration of grace notes (which
come before the real note and thus also create the EventChord with
duration zero!)

There is still one problem with things like beams or articulations on
grace notes (they are printed after the whole cord (not inside the
\grace!), but this is a general problem that musicxml2ly inserts
slurs, ties, beams, articulations, etc. as separate events not assigned
to any particular note/EventChord. The code should be changed to
assign these ornaments/settings directly to the note or the chord they
apply to. This would (1) get rid of e.g. triple [ with beamed chords,
(2) make it possible to combine multiple MusicXML articulations into
single lilypond articulations, (3) apply fingerings and ties to notes
inside chords rather than the whole chord, and (4) fix the grace notes.

The other problem is when a chord is used as a grace chord in MusicXML.
Due to the whole structure of musicxml2ly, this problem goes very deep
and I don't know of any way to fix this short of a big rewrite.

Signed-off-by: Reinhold Kainhofer <reinhold@kainhofer.com>
python/musicexp.py
scripts/musicxml2ly.py

index 0b41d275c992e6a0df81d8cde3062434f9f437c1..4f4b262f77e054f2f76e5d2a6976279f8826fb92 100644 (file)
@@ -434,6 +434,13 @@ class Lyrics:
 
 
 class EventChord (NestedMusic):
+    def __init__ (self):
+        NestedMusic.__init__ (self)
+        self.grace_elements = []
+    def append_grace (self, element):
+        if element:
+            self.grace_elements.append (element)
+
     def get_length (self):
         l = Rational (0)
         for e in self.elements:
@@ -451,6 +458,12 @@ class EventChord (NestedMusic):
         other_events = [e for e in self.elements if
                 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 rest_events:
             rest_events[0].print_ly (printer)
         elif len (note_events) == 1:
index 9a291a223d8c3e7083a007d220c13c6cc197f846..10b21980e340973cfacea51bc7970a1d4c421e9a 100644 (file)
@@ -80,7 +80,10 @@ def musicxml_duration_to_lily (mxl_note):
     d.duration_log = mxl_note.get_duration_log ()
 
     d.dots = len (mxl_note.get_typed_children (musicxml.Dot))
-    d.factor = mxl_note._duration / d.get_length ()
+    # Grace notes by specification have duration 0, so no time modification 
+    # factor is possible. It even messes up the output with *0/1
+    if not mxl_note.get_maybe_exist_typed_child (musicxml.Grace):
+        d.factor = mxl_note._duration / d.get_length ()
 
     return d         
 
@@ -467,7 +470,11 @@ class LilyPondVoiceBuilder:
         
     def add_multibar_rest (self, duration):
         self.pending_multibar += duration
-        
+
+    def set_duration (self, duration):
+        self.end_moment = self.begin_moment + duration
+    def current_duration (self):
+        return self.end_moment - self.begin_moment
         
     def add_music (self, music, duration):
         assert isinstance (music, musicexp.Music)
@@ -476,7 +483,7 @@ class LilyPondVoiceBuilder:
 
         self.elements.append (music)
         self.begin_moment = self.end_moment
-        self.end_moment = self.begin_moment + duration 
+        self.set_duration (duration)
         
         # Insert all pending dynamics right after the note/rest:
         if duration > Rational (0):
@@ -613,8 +620,15 @@ def musicxml_voice_to_lily_voice (voice):
         if not ev_chord: 
             ev_chord = musicexp.EventChord()
             voice_builder.add_music (ev_chord, n._duration)
-
-        ev_chord.append (main_event)
+        # When a note/chord has grace notes (duration==0), the duration of the 
+        # event chord is not yet known, but the event chord was already added
+        # with duration 0. The following correct this when we hit the real note!
+        if voice_builder.current_duration () == 0 and n._duration > 0:
+            voice_builder.set_duration (n._duration)
+        if n.get_maybe_exist_typed_child (musicxml.Grace):
+            ev_chord.append_grace (main_event)
+        else:
+            ev_chord.append (main_event)
         
         notations = n.get_maybe_exist_typed_child (musicxml.Notations)
         tuplet_event = None