]> git.donarmstrong.com Git - lilypond.git/commitdiff
Convert dynamic marks (given in a <direction> tag, assigned to the staff at a given...
authorReinhold Kainhofer <reinhold@kainhofer.com>
Sun, 19 Aug 2007 22:21:30 +0000 (00:21 +0200)
committerHan-Wen Nienhuys <hanwen@xs4all.nl>
Mon, 20 Aug 2007 03:35:14 +0000 (00:35 -0300)
In the LilyPondVoiceBuilder, I added a method to store any pending dynamics and print them out only after the next note or rest (everything with duration>0) is encountered.

Also convert (de-)crescendo (begin/end also given in a <direction> tag, not assigned to a particular note)

Comment about broken dynamics, when they appear as first element of a part before any note (so that no voice_id is known yet).

python/musicexp.py
python/musicxml.py
scripts/musicxml2ly.py

index 56252f339e4e4e8e089da084b22ff8fc10893b41..b543dbc2e6056d5267406d485c13137d4dc25d15 100644 (file)
@@ -499,6 +499,50 @@ class TieEvent(Event):
         return '~'
 
 
+class HairpinEvent (Event):
+    def __init__ (self, type):
+        self.type = type
+    def hairpin_to_ly (self):
+        val = ''
+        tp = { 0: '\!', 1: '\<', -1: '\>' }.get (self.type)
+        if tp:
+            val += tp
+        return val
+    
+    def ly_expression (self):
+        return self.hairpin_to_ly ()
+    
+    def print_ly (self, printer):
+        val = self.hairpin_to_ly ()
+        if val:
+            printer.dump (val)
+
+
+
+class DynamicsEvent (Event):
+    def __init__ (self):
+        self.type = None
+        self.available_commands = [ "ppppp", "pppp", "ppp", "pp", "p", 
+                                    "mp", "mf", 
+                                    "f", "ff", "fff", "ffff", 
+                                    "fp", "sf", "sff", "sp", "spp", "sfz", "rfz" ];
+    def ly_expression (self):
+        if self.type == None:
+            return;
+        elif self.type in self.available_commands:
+            return '\%s' % self.type
+        else:
+            return '\markup{ \dynamic %s }' % self.type
+        
+    def print_ly (self, printer):
+        if self.type == None:
+            return
+        elif self.type in self.available_commands:
+            printer.dump ("\\%s" % self.type)
+        else:
+            printer.dump ("\\markup{ \\dynamic %s }" % self.type)
+
+
 class ArticulationEvent (Event):
     def __init__ (self):
         self.type = None
index e7fe77d69977de9fb6606964c3805f192a0a27ea..132ce5a752021d2798d60f0c86425873cb37b628 100644 (file)
@@ -357,14 +357,16 @@ class Part (Music_xml_node):
        for n in elements:
            voice_id = n.get_maybe_exist_typed_child (class_dict['voice'])
 
-           if not (voice_id or isinstance (n, Attributes)):
+            # TODO: If the first element of a voice is a dynamics entry,
+            #       then voice_id is not yet set! Thus it will currently be ignored
+           if not (voice_id or isinstance (n, Attributes) or isinstance (n, Direction) ):
                continue
 
            if isinstance (n, Attributes) and not start_attr:
                start_attr = n
                continue
 
-           if isinstance (n, Attributes):
+           if isinstance (n, Attributes) or isinstance (n, Direction):
                for v in voices.values ():
                    v.add_element (n)
                continue
@@ -477,6 +479,8 @@ class Direction (Music_xml_node):
     pass
 class DirType (Music_xml_node):
     pass
+class Wedge (Music_xml_node):
+    pass
 
 
 ## need this, not all classes are instantiated
@@ -515,7 +519,9 @@ class_dict = {
         'technical': Technical,
         'ornaments': Ornaments,
         'direction': Direction,
-        'direction-type': DirType
+        'direction-type': DirType,
+        'dynamics': Dynamics,
+        'wedge': Wedge
 }
 
 def name2class_name (name):
index 4bb3081558032836ceb929f3587f01cce3dfcaf7..9a09fa2dc50e90150293d806c44a23ad003d875a 100644 (file)
@@ -261,13 +261,43 @@ def musicxml_articulation_to_lily_event(mxl_event):
     return ev
 
 
+def musicxml_direction_to_lily( n ):
+    # TODO: Handle the <staff> element!
+    res = []
+    dirtype = n.get_maybe_exist_typed_child (musicxml.DirType)
+    if not dirtype: 
+      return res
+
+    for entry in dirtype.get_all_children ():
+        if entry.get_name () == "dynamics":
+            for dynentry in entry.get_all_children ():
+                dynamics_available = ( "p", "pp", "ppp", "pppp", "ppppp", "pppppp", 
+                    "f", "ff", "fff", "ffff", "fffff", "ffffff", 
+                    "mp", "mf", "sf", "sfp", "sfpp", "fp", 
+                    "rf", "rfz", "sfz", "sffz", "fz" )
+                if not dynentry.get_name() in dynamics_available: 
+                    continue
+                event = musicexp.DynamicsEvent ()
+                event.type = dynentry.get_name ()
+                res.append (event)
+      
+        if entry.get_name() == "wedge":
+            if hasattr (entry, 'type'):
+                wedgetype = entry.type;
+                wedgetypeval = {"crescendo" : 1, "decrescendo" : -1, 
+                                "diminuendo" : -1, "stop" : 0 }.get (wedgetype)
+                if wedgetypeval != None:
+                    event = musicexp.HairpinEvent (wedgetypeval)
+                    res.append (event)
+
+    return res
+
 instrument_drumtype_dict = {
     'Acoustic Snare Drum': 'acousticsnare',
     'Side Stick': 'sidestick',
     'Open Triangle': 'opentriangle',
     'Mute Triangle': 'mutetriangle',
-    'Tambourine': 'tambourine',
-    
+    'Tambourine': 'tambourine'
 }
 
 def musicxml_note_to_lily_main_event (n):
@@ -312,6 +342,7 @@ class NegativeSkip:
 class LilyPondVoiceBuilder:
     def __init__ (self):
         self.elements = []
+        self.pending_dynamics = []
         self.end_moment = Rational (0)
         self.begin_moment = Rational (0)
         self.pending_multibar = Rational (0)
@@ -339,6 +370,16 @@ class LilyPondVoiceBuilder:
         self.begin_moment = self.end_moment
         self.end_moment = self.begin_moment + duration 
 
+        # Insert all pending dynamics right after the note/rest:
+        if duration > Rational (0):
+            for d in self.pending_dynamics:
+                self.elements.append (d)
+            self.pending_dynamics = []
+
+    def add_dynamics (self, dynamic):
+        # store the dynamic item(s) until we encounter the next note/rest:
+        self.pending_dynamics.append (dynamic)
+
     def add_bar_check (self, number):
         b = musicexp.BarCheck ()
         b.bar_number = number
@@ -390,6 +431,11 @@ def musicxml_voice_to_lily_voice (voice):
         if n.get_name () == 'forward':
             continue
 
+        if isinstance (n, musicxml.Direction):
+            for a in musicxml_direction_to_lily (n):
+                voice_builder.add_dynamics (a)
+            continue
+        
         if not n.get_maybe_exist_named_child ('chord'):
             try:
                 voice_builder.jumpto (n._when)
@@ -512,6 +558,13 @@ def musicxml_voice_to_lily_voice (voice):
                     if ev: 
                         ev_chord.append (ev)
 
+            dynamics = notations.get_named_children ('dynamics')
+            for a in dynamics:
+                for ch in a.get_all_children ():
+                    ev = musicxml_dynamics_to_lily_event (ch)
+                    if ev:
+                        ev_chord.append (ev)
+
         mxl_beams = [b for b in n.get_named_children ('beam')
                      if (b.get_type () in ('begin', 'end')
                          and b.is_primary ())]