From 0ab607a65fefe22209037fa7a7449a0c75d2c6d5 Mon Sep 17 00:00:00 2001
From: Reinhold Kainhofer
Date: Mon, 20 Aug 2007 00:21:30 +0200
Subject: [PATCH] Convert dynamic marks (given in a tag, assigned to the staff at a given position in xml, not to a note like in lilypond)
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 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 | 44 +++++++++++++++++++++++++++++++++++++
python/musicxml.py | 12 +++++++--
scripts/musicxml2ly.py | 57 ++++++++++++++++++++++++++++++++++++++++++++++-
3 files changed, 108 insertions(+), 5 deletions(-)
diff --git a/python/musicexp.py b/python/musicexp.py
index 56252f3..b543dbc 100644
--- a/python/musicexp.py
+++ b/python/musicexp.py
@@ -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
diff --git a/python/musicxml.py b/python/musicxml.py
index e7fe77d..132ce5a 100644
--- a/python/musicxml.py
+++ b/python/musicxml.py
@@ -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):
diff --git a/scripts/musicxml2ly.py b/scripts/musicxml2ly.py
index 4bb3081..9a09fa2 100644
--- a/scripts/musicxml2ly.py
+++ b/scripts/musicxml2ly.py
@@ -261,13 +261,43 @@ def musicxml_articulation_to_lily_event(mxl_event):
return ev
+def musicxml_direction_to_lily( n ):
+ # TODO: Handle the 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 ())]
--
1.5.2.3