]> git.donarmstrong.com Git - lilypond.git/blobdiff - scripts/musicxml2ly.py
Add '-dcrop' option to ps and svg backends
[lilypond.git] / scripts / musicxml2ly.py
old mode 100644 (file)
new mode 100755 (executable)
index a1faae5..4d6b149
@@ -19,6 +19,7 @@ import lilylib as ly
 _ = ly._
 
 import utilities
+import musicxml2ly_conversion
 import musicxml
 import musicexp
 
@@ -229,7 +230,10 @@ def extract_score_information(tree):
         set_if_exists('encoder', ids.get_encoding_person())
         set_if_exists('encodingdescription', ids.get_encoding_description())
         set_if_exists('source', ids.get_source())
-        set_if_exists('miscellaneous', ids.get_file_description());
+
+        # <miscellaneous><miscellaneous-field name="description"> ... becomes
+        # \header { texidoc = ...
+        set_if_exists('texidoc', ids.get_file_description());
 
         # Finally, apply the required compatibility modes
         # Some applications created wrong MusicXML files, so we need to
@@ -300,12 +304,6 @@ class PartGroupInfo:
         ly.warning(_("Unprocessed PartGroupInfo %s encountered") % self)
         return ''
 
-def musicxml_step_to_lily(step):
-    if step:
-        return (ord(step) - ord('A') + 7 - 2) % 7
-    else:
-        return None
-
 def staff_attributes_to_string_tunings(mxl_attr):
     details = mxl_attr.get_maybe_exist_named_child('staff-details')
     if not details:
@@ -327,7 +325,7 @@ def staff_attributes_to_string_tunings(mxl_attr):
 
         step = i.get_named_child(u'tuning-step')
         step = step.get_text().strip()
-        p.step = musicxml_step_to_lily(step)
+        p.step = musicxml2ly_conversion.musicxml_step_to_lily(step)
 
         octave = i.get_named_child(u'tuning-octave')
         octave = octave.get_text().strip()
@@ -539,34 +537,11 @@ def extract_score_structure(part_list, staffinfo):
 
 
 
-def rational_to_lily_duration(rational_len):
-    d = musicexp.Duration()
-
-    rational_len.normalize_self()
-    d_log = {1: 0, 2: 1, 4:2, 8:3, 16:4, 32:5, 64:6, 128:7, 256:8, 512:9}.get(rational_len.denominator(), -1)
-
-    # Duration of the form 1/2^n or 3/2^n can be converted to a simple lilypond duration
-    dots = {1: 0, 3: 1, 7: 2, 15: 3, 31: 4, 63: 5, 127: 6}.get(rational_len.numerator(), -1)
-    if(d_log >= dots >= 0):
-        # account for the dots!
-        d.duration_log = d_log - dots
-        d.dots = dots
-    elif(d_log >= 0):
-        d.duration_log = d_log
-        d.factor = Rational(rational_len.numerator())
-    else:
-        ly.warning(_("Encountered rational duration with denominator %s, "
-                       "unable to convert to lilypond duration") %
-                    rational_len.denominator())
-        # TODO: Test the above error message
-        return None
-
-    return d
 
 def musicxml_partial_to_lily(partial_len):
     if partial_len > 0:
         p = musicexp.Partial()
-        p.partial = rational_to_lily_duration(partial_len)
+        p.partial = musicxml2ly_conversion.rational_to_lily_duration(partial_len)
         return p
     else:
         return None
@@ -597,7 +572,7 @@ def group_repeats(music_list):
         while pos < len(music_list) and not repeat_replaced:
             e = music_list[pos]
             repeat_finished = False
-            if isinstance(e, RepeatMarker):
+            if isinstance(e, musicxml2ly_conversion.RepeatMarker):
                 if not repeat_times and e.times:
                     repeat_times = e.times
                 if e.direction == -1:
@@ -614,7 +589,7 @@ def group_repeats(music_list):
                     if repeat_end < 0:
                         repeat_end = pos
                     final_marker = pos
-            elif isinstance(e, EndingMarker):
+            elif isinstance(e, musicxml2ly_conversion.EndingMarker):
                 if e.direction == -1:
                     if repeat_start < 0:
                         repeat_start = 0
@@ -759,6 +734,14 @@ def group_tuplets(music_list, events):
         new_list.extend(music_list[last:i1])
         seq = musicexp.SequentialMusic()
         last = i2 + 1
+
+        # At this point music_list[i1:last] encompasses all the notes of the
+        # tuplet. There might be dynamics following this range, however, which
+        # apply to the last note of the tuplet. Advance last to include them
+        # in the range.
+        while last < len(music_list) and isinstance(music_list[last], musicexp.DynamicsEvent):
+            last += 1
+
         seq.elements = music_list[i1:last]
 
         tsm.element = seq
@@ -851,7 +834,7 @@ def musicxml_key_to_lily(attributes):
         # MusicXML contains C,D,E,F,G,A,B as steps, lily uses 0-7, so convert
         alterations = []
         for k in key_sig:
-            k[0] = musicxml_step_to_lily(k[0])
+            k[0] = musicxml2ly_conversion.musicxml_step_to_lily(k[0])
             alterations.append(k)
         change.non_standard_alterations = alterations
     return change
@@ -966,21 +949,6 @@ def musicxml_print_to_lily(el):
     return elts
 
 
-class Marker(musicexp.Music):
-    def __init__(self):
-        self.direction = 0
-        self.event = None
-    def print_ly(self, printer):
-        ly.warning(_("Encountered unprocessed marker %s\n") % self)
-        pass
-    def ly_expression(self):
-        return ""
-class RepeatMarker(Marker):
-    def __init__(self):
-        Marker.__init__(self)
-        self.times = 0
-class EndingMarker(Marker):
-    pass
 
 
 spanner_event_dict = {
@@ -1182,7 +1150,7 @@ articulations_dict = {
     #"shake": "?",
     "snap-pizzicato": "snappizzicato",
     #"spiccato": "?",
-    "staccatissimo": (musicexp.ShortArticulationEvent, "|"), # or "staccatissimo"
+    "staccatissimo": (musicexp.ShortArticulationEvent, "!"), # or "staccatissimo"
     "staccato": (musicexp.ShortArticulationEvent, "."), # or "staccato"
     "stopped": (musicexp.ShortArticulationEvent, "+"), # or "stopped"
     #"stress": "?",
@@ -1629,7 +1597,7 @@ notehead_styles_dict = {
 def musicxml_chordpitch_to_lily(mxl_cpitch):
     r = musicexp.ChordPitch()
     r.alteration = mxl_cpitch.get_alteration()
-    r.step = musicxml_step_to_lily(mxl_cpitch.get_step())
+    r.step = musicxml2ly_conversion.musicxml_step_to_lily(mxl_cpitch.get_step())
     return r
 
 chordkind_dict = {
@@ -1697,7 +1665,7 @@ def musicxml_get_string_tunings(lines):
         string_tunings = [musicexp.Pitch()] * lines
         for i in range(0, lines):
             p = musicexp.Pitch()
-            p.step = musicxml_step_to_lily(((("E","A","D","G","B")*(lines/5+1))[0:lines])[i])
+            p.step = musicxml2ly_conversion.musicxml_step_to_lily(((("E","A","D","G","B")*(lines/5+1))[0:lines])[i])
             p.octave = (([-2+int(x%5>1)+2*(x/5) for x in range(0,lines)][0:lines])[i])
             p.alteration = 0
             p._force_absolute_pitch = True
@@ -1858,7 +1826,7 @@ def musicxml_figured_bass_to_lily(n):
         # apply the duration to res
         length = Rational(int(dur.get_text()), n._divisions) * Rational(1, 4)
         res.set_real_duration(length)
-        duration = rational_to_lily_duration(length)
+        duration = musicxml2ly_conversion.rational_to_lily_duration(length)
         if duration:
             res.set_duration(duration)
     if hasattr(n, 'parentheses') and n.parentheses == "yes":
@@ -1945,7 +1913,7 @@ class LilyPondVoiceBuilder:
         layout_information.set_context_item('Score', 'skipBars = ##t')
         r = musicexp.MultiMeasureRest()
         lenfrac = self.measure_length
-        r.duration = rational_to_lily_duration(lenfrac)
+        r.duration = musicxml2ly_conversion.rational_to_lily_duration(lenfrac)
         r.duration.factor *= self.pending_multibar / lenfrac
         self.elements.append(r)
         self.begin_moment = self.end_moment
@@ -2159,6 +2127,9 @@ def extract_lyrics(voice, lyric_key, lyrics_dict):
     def is_rest(elem):
         return elem.get_typed_children(musicxml.Rest)
 
+    def is_chord(elem):
+        return elem.get_typed_children(musicxml.Chord)
+
     def is_note_and_not_rest(elem):
         return is_note(elem) and not is_rest(elem)
 
@@ -2185,6 +2156,11 @@ def extract_lyrics(voice, lyric_key, lyrics_dict):
              not note_has_lyric_belonging_to_lyric_part:
             result.append('\skip1 ')
         # Note does not have any lyric attached to it.
+        elif is_chord(elem):
+            # note without lyrics part of a chord. MusicXML format is
+            # unclear if a chord element could contain a lyric, lets
+            # asume that we do not want to put a skip here.
+            continue
         elif is_note_and_not_rest(elem):
             result.append('\skip1 ')
 
@@ -2276,7 +2252,7 @@ def musicxml_voice_to_lily_voice(voice):
                     figured_bass_builder.add_barline(a, False)
                     chordnames_builder.add_barline(a, False)
                     fretboards_builder.add_barline(a, False)
-                elif isinstance(a, RepeatMarker) or isinstance(a, EndingMarker):
+                elif isinstance(a, musicxml2ly_conversion.RepeatMarker) or isinstance(a, musicxml2ly_conversion.EndingMarker):
                     voice_builder.add_command(a)
                     figured_bass_builder.add_barline(a, False)
                     chordnames_builder.add_barline(a, False)
@@ -2780,7 +2756,7 @@ If the given filename is -, musicxml2ly reads from the command line.
 
     p.version = ('%prog (LilyPond) ' + lilypond_version + '\n\n'
 +
-_ ("""Copyright (c) 2005--2015 by
+_ ("""Copyright (c) 2005--2016 by
     Han-Wen Nienhuys <hanwen@xs4all.nl>,
     Jan Nieuwenhuizen <janneke@gnu.org> and
     Reinhold Kainhofer <reinhold@kainhofer.com>
@@ -3059,7 +3035,7 @@ def update_layout_information():
 
 def print_ly_preamble(printer, filename):
     printer.dump_version(lilypond_version)
-    printer.print_verbatim('% automatically converted by philomelos musicxml2ly v0.2.41\n')
+    printer.print_verbatim('% automatically converted by musicxml2ly from ' + filename)
     printer.newline()
     printer.dump(r'\pointAndClickOff')
     printer.newline()