]> git.donarmstrong.com Git - lilypond.git/commitdiff
MusicXML: Fix measure issues with chord names and figured bass
authorReinhold Kainhofer <reinhold@kainhofer.com>
Fri, 3 Apr 2009 15:59:01 +0000 (17:59 +0200)
committerReinhold Kainhofer <reinhold@kainhofer.com>
Fri, 3 Apr 2009 16:01:19 +0000 (18:01 +0200)
-) Add repeats also chordnames and figured bass
-) Barlines don't count as relevant voice elements (to check whether
   a voice is empty)
-) Properly insert bar checks for fb and chords, too
-) Test files for pickup measures, incomplete measures (skips added!)
-) Test file for two harmony elements at the same time (doesn't work correctly!)

input/regression/musicxml/46f-IncompleteMeasures.xml [new file with mode: 0644]
input/regression/musicxml/46g-PickupMeasure-Chordnames-FiguredBass.xml [new file with mode: 0644]
input/regression/musicxml/71g-MultipleChordnames.xml [new file with mode: 0644]
scripts/musicxml2ly.py

diff --git a/input/regression/musicxml/46f-IncompleteMeasures.xml b/input/regression/musicxml/46f-IncompleteMeasures.xml
new file mode 100644 (file)
index 0000000..d16a463
--- /dev/null
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 2.0 Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd">
+<score-partwise version="2.0">
+  <identification>
+    <miscellaneous>
+      <miscellaneous-field name="description">Measures can contain less notes
+          than the time signature says. Here, the first and third measures 
+          contain only two quarters instead of four.</miscellaneous-field>
+    </miscellaneous>
+  </identification>
+  <part-list>
+    <score-part id="P1">
+      <part-name>MusicXML Part</part-name>
+    </score-part>
+  </part-list>
+  <!--=========================================================-->
+  <part id="P1">
+        <measure number="1">
+            <attributes>
+                <divisions>1</divisions>
+                <time>
+                    <beats>4</beats>
+                    <beat-type>4</beat-type>
+                </time>
+                <clef>
+                    <sign>G</sign>
+                    <line>2</line>
+                </clef>
+            </attributes>
+            <note>
+                <pitch>
+                    <step>A</step>
+                    <octave>4</octave>
+                </pitch>
+                <duration>1</duration>
+                <voice>1</voice>
+                <type>quarter</type>
+            </note>
+            <note>
+                <pitch>
+                    <step>A</step>
+                    <octave>4</octave>
+                </pitch>
+                <duration>1</duration>
+                <voice>1</voice>
+                <type>quarter</type>
+            </note>
+        </measure>
+        <measure number="2">
+            <note>
+                <pitch>
+                    <step>A</step>
+                    <octave>4</octave>
+                </pitch>
+                <duration>1</duration>
+                <voice>1</voice>
+                <type>quarter</type>
+            </note>
+            <note>
+                <pitch>
+                    <step>A</step>
+                    <octave>4</octave>
+                </pitch>
+                <duration>1</duration>
+                <voice>1</voice>
+                <type>quarter</type>
+            </note>
+            <note>
+                <pitch>
+                    <step>A</step>
+                    <octave>4</octave>
+                </pitch>
+                <duration>1</duration>
+                <voice>1</voice>
+                <type>quarter</type>
+            </note>
+            <note>
+                <pitch>
+                    <step>A</step>
+                    <octave>4</octave>
+                </pitch>
+                <duration>1</duration>
+                <voice>1</voice>
+                <type>quarter</type>
+            </note>
+        </measure>
+        <measure number="3">
+            <note>
+                <pitch>
+                    <step>A</step>
+                    <octave>4</octave>
+                </pitch>
+                <duration>1</duration>
+                <voice>1</voice>
+                <type>quarter</type>
+            </note>
+            <note>
+                <pitch>
+                    <step>A</step>
+                    <octave>4</octave>
+                </pitch>
+                <duration>1</duration>
+                <voice>1</voice>
+                <type>quarter</type>
+            </note>
+        </measure>
+        <measure number="4">
+            <note>
+                <pitch>
+                    <step>A</step>
+                    <octave>4</octave>
+                </pitch>
+                <duration>1</duration>
+                <voice>1</voice>
+                <type>quarter</type>
+            </note>
+            <note>
+                <pitch>
+                    <step>A</step>
+                    <octave>4</octave>
+                </pitch>
+                <duration>1</duration>
+                <voice>1</voice>
+                <type>quarter</type>
+            </note>
+            <note>
+                <pitch>
+                    <step>A</step>
+                    <octave>4</octave>
+                </pitch>
+                <duration>1</duration>
+                <voice>1</voice>
+                <type>quarter</type>
+            </note>
+            <note>
+                <pitch>
+                    <step>A</step>
+                    <octave>4</octave>
+                </pitch>
+                <duration>1</duration>
+                <voice>1</voice>
+                <type>quarter</type>
+            </note>
+        </measure>
+    </part>
+</score-partwise>
diff --git a/input/regression/musicxml/46g-PickupMeasure-Chordnames-FiguredBass.xml b/input/regression/musicxml/46g-PickupMeasure-Chordnames-FiguredBass.xml
new file mode 100644 (file)
index 0000000..99af4c6
--- /dev/null
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 2.0 Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd">
+<score-partwise version="2.0">
+  <identification>
+    <miscellaneous>
+      <miscellaneous-field name="description">Pickup measure with chord names 
+           and figured bass.</miscellaneous-field>
+    </miscellaneous>
+  </identification>
+  <part-list>
+    <score-part id="P1">
+      <part-name>MusicXML Part</part-name>
+    </score-part>
+  </part-list>
+  <!--=========================================================-->
+  <part id="P1">
+    <measure number="0" implicit="yes">
+      <attributes>
+        <divisions>2</divisions>
+        <key>
+          <fifths>0</fifths>
+          <mode>major</mode>
+        </key>
+        <time>
+          <beats>4</beats>
+          <beat-type>4</beat-type>
+        </time>
+      </attributes>
+      <harmony print-frame="no">
+        <root>
+          <root-step>C</root-step>
+        </root>
+        <kind>major</kind>
+      </harmony>
+      <figured-bass>
+        <figure><figure-number>3</figure-number></figure>
+        <duration>1</duration>
+      </figured-bass>
+      <note>
+        <pitch>
+          <step>C</step>
+          <octave>5</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+      </note>
+      <note>
+        <pitch>
+          <step>C</step>
+          <octave>5</octave>
+        </pitch>
+        <duration>1</duration>
+        <voice>1</voice>
+        <type>eighth</type>
+      </note>
+    </measure>
+    <measure number="1">
+      <harmony print-frame="no">
+        <root>
+          <root-step>C</root-step>
+        </root>
+        <kind>major</kind>
+      </harmony>
+      <figured-bass>
+        <figure><figure-number>3</figure-number></figure>
+        <duration>1</duration>
+      </figured-bass>
+      <note>
+        <pitch>
+          <step>C</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+      </note>
+      <note>
+        <pitch>
+          <step>C</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+      </note>
+      <note>
+        <pitch>
+          <step>C</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+      </note>
+      <note>
+        <pitch>
+          <step>C</step>
+          <octave>4</octave>
+        </pitch>
+        <duration>2</duration>
+        <voice>1</voice>
+        <type>quarter</type>
+      </note>
+    </measure>
+  </part>
+</score-partwise>
diff --git a/input/regression/musicxml/71g-MultipleChordnames.xml b/input/regression/musicxml/71g-MultipleChordnames.xml
new file mode 100644 (file)
index 0000000..6c42cdb
--- /dev/null
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE score-partwise PUBLIC "-//Recordare//DTD MusicXML 2.0 Partwise//EN" "http://www.musicxml.org/dtds/partwise.dtd">
+<score-partwise version="2.0">
+  <identification>
+    <miscellaneous>
+      <miscellaneous-field name="description">There can be multiple subsequent
+          harmony elements, indicating a harmony change during a note</miscellaneous-field>
+    </miscellaneous>
+  </identification>
+  <part-list>
+    <score-part id="P1">
+      <part-name>MusicXML Part</part-name>
+    </score-part>
+  </part-list>
+  <!--=========================================================-->
+  <part id="P1">
+        <measure number="1">
+            <attributes>
+                <divisions>480</divisions>
+                <key>
+                    <fifths>0</fifths>
+                    <mode>major</mode>
+                </key>
+                <time>
+                    <beats>4</beats>
+                    <beat-type>4</beat-type>
+                </time>
+                <clef>
+                    <sign>G</sign>
+                    <line>2</line>
+                </clef>
+            </attributes>
+            <harmony print-frame="no">
+                <root>
+                    <root-step>C</root-step>
+                </root>
+                <kind text="">major</kind>
+            </harmony>
+            <harmony print-frame="no">
+                <root>
+                    <root-step>F</root-step>
+                    <root-alter>1</root-alter>
+                </root>
+                <kind text="m6">minor-sixth</kind>
+            </harmony>
+            <note>
+                <pitch>
+                    <step>A</step>
+                    <octave>4</octave>
+                </pitch>
+                <duration>960</duration>
+                <voice>1</voice>
+                <type>half</type>
+            </note>
+            <harmony print-frame="no">
+                <root>
+                    <root-step>D</root-step>
+                </root>
+                <kind text="m7">minor-seventh</kind>
+            </harmony>
+            <harmony print-frame="no">
+                <root>
+                    <root-step>G</root-step>
+                </root>
+                <kind text="7">dominant</kind>
+            </harmony>
+            <note>
+                <pitch>
+                    <step>G</step>
+                    <octave>4</octave>
+                </pitch>
+                <duration>960</duration>
+                <voice>1</voice>
+                <type>half</type>
+            </note>
+        </measure>
+    </part>
+</score-partwise>
index 38bfb1949ebd6d228cb4102389576c3a1e4b5be4..561d4cd5dac400408f9aad93007ef8a883567ba1 100644 (file)
@@ -1906,12 +1906,12 @@ class LilyPondVoiceBuilder:
     def current_duration (self):
         return self.end_moment - self.begin_moment
         
-    def add_music (self, music, duration):
+    def add_music (self, music, duration, relevant = True):
         assert isinstance (music, musicexp.Music)
         if self.pending_multibar > Rational (0):
             self._insert_multibar ()
 
-        self.has_relevant_elements = True
+        self.has_relevant_elements = self.has_relevant_elements or relevant
         self.elements.append (music)
         self.begin_moment = self.end_moment
         self.set_duration (duration)
@@ -1923,18 +1923,27 @@ class LilyPondVoiceBuilder:
             self.pending_dynamics = []
 
     # Insert some music command that does not affect the position in the measure
-    def add_command (self, command):
+    def add_command (self, command, relevant = True):
         assert isinstance (command, musicexp.Music)
         if self.pending_multibar > Rational (0):
             self._insert_multibar ()
-        self.has_relevant_elements = True
+        self.has_relevant_elements = self.has_relevant_elements or relevant
         self.elements.append (command)
-    def add_barline (self, barline):
-        # TODO: Implement merging of default barline and custom bar line
-        self.add_music (barline, Rational (0))
+    def add_barline (self, barline, relevant = False):
+        # Insert only if we don't have a barline already
+        # TODO: Implement proper merging of default barline and custom bar line
+        has_relevant = self.has_relevant_elements
+        if (not (self.elements) or 
+            not (isinstance (self.elements[-1], musicexp.BarLine)) or 
+            (self.pending_multibar > Rational (0))):
+            self.add_music (barline, Rational (0))
+        self.has_relevant_elements = has_relevant or relevant
     def add_partial (self, command):
         self.ignore_skips = True
+        # insert the partial, but restore relevant_elements (partial is not relevant)
+        relevant = self.has_relevant_elements
         self.add_command (command)
+        self.has_relevant_elements = relevant
 
     def add_dynamics (self, dynamic):
         # store the dynamic item(s) until we encounter the next note/rest:
@@ -1943,11 +1952,9 @@ class LilyPondVoiceBuilder:
     def add_bar_check (self, number):
         # re/store has_relevant_elements, so that a barline alone does not
         # trigger output for figured bass, chord names
-        has_relevant = self.has_relevant_elements
         b = musicexp.BarLine ()
         b.bar_number = number
         self.add_barline (b)
-        self.has_relevant_elements = has_relevant
 
     def jumpto (self, moment):
         current_end = self.end_moment + self.pending_multibar
@@ -1981,7 +1988,7 @@ class LilyPondVoiceBuilder:
 
             evc = musicexp.ChordEvent ()
             evc.elements.append (skip)
-            self.add_music (evc, diff)
+            self.add_music (evc, diff, False)
 
         if diff > Rational (0) and moment == 0:
             self.ignore_skips = False
@@ -2085,6 +2092,8 @@ def musicxml_voice_to_lily_voice (voice):
             a = musicxml_partial_to_lily (n.partial)
             if a:
                 voice_builder.add_partial (a)
+                figured_bass_builder.add_partial (a)
+                chordnames_builder.add_partial (a)
             continue
 
         is_chord = n.get_maybe_exist_named_child ('chord')
@@ -2092,8 +2101,12 @@ def musicxml_voice_to_lily_voice (voice):
         if not is_chord and not is_after_grace:
             try:
                 voice_builder.jumpto (n._when)
+                figured_bass_builder.jumpto (n._when)
+                chordnames_builder.jumpto (n._when)
             except NegativeSkip, neg:
                 voice_builder.correct_negative_skip (n._when)
+                figured_bass_builder.correct_negative_skip (n._when)
+                chordnames_builder.correct_negative_skip (n._when)
                 n.message (_ ("Negative skip found: from %s to %s, difference is %s") % (neg.here, neg.dest, neg.dest - neg.here))
 
         if isinstance (n, musicxml.Barline):
@@ -2101,8 +2114,12 @@ def musicxml_voice_to_lily_voice (voice):
             for a in barlines:
                 if isinstance (a, musicexp.BarLine):
                     voice_builder.add_barline (a)
+                    figured_bass_builder.add_barline (a, False)
+                    chordnames_builder.add_barline (a, False)
                 elif isinstance (a, RepeatMarker) or isinstance (a, EndingMarker):
                     voice_builder.add_command (a)
+                    figured_bass_builder.add_barline (a, False)
+                    chordnames_builder.add_barline (a, False)
             continue
 
         # Continue any multimeasure-rests before trying to add bar checks!
@@ -2431,7 +2448,7 @@ def musicxml_voice_to_lily_voice (voice):
     # create \figuremode { figured bass elements }
     if figured_bass_builder.has_relevant_elements:
         fbass_music = musicexp.SequentialMusic ()
-        fbass_music.elements = figured_bass_builder.elements
+        fbass_music.elements = group_repeats (figured_bass_builder.elements)
         v = musicexp.ModeChangingMusicWrapper()
         v.mode = 'figuremode'
         v.element = fbass_music
@@ -2440,7 +2457,7 @@ def musicxml_voice_to_lily_voice (voice):
     # create \chordmode { chords }
     if chordnames_builder.has_relevant_elements:
         cname_music = musicexp.SequentialMusic ()
-        cname_music.elements = chordnames_builder.elements
+        cname_music.elements = group_repeats (chordnames_builder.elements)
         v = musicexp.ModeChangingMusicWrapper()
         v.mode = 'chordmode'
         v.element = cname_music