From: Reinhold Kainhofer Date: Sun, 30 Nov 2008 01:21:58 +0000 (+0100) Subject: MusicXML: First steps towards implementing general compound time signatures X-Git-Tag: release/2.12.0-1~40^2~15 X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=ffd4b1434da640477729308ca47c121d12f008e5;p=lilypond.git MusicXML: First steps towards implementing general compound time signatures -) correctly parse compound time signatures and senza-misura signatures. as a side-effect, crashes on these signatures have been fixed, too. -) correctly create the time signature change event -) switch measure length from (num, den) to a Rational -) Add test cases for general compound time signatures --- diff --git a/input/regression/musicxml/11-TimeSignatures.itexi b/input/regression/musicxml/11-TimeSignatures.itexi new file mode 100644 index 0000000000..2f59dccaea --- /dev/null +++ b/input/regression/musicxml/11-TimeSignatures.itexi @@ -0,0 +1,2 @@ +@section Time signatures + diff --git a/input/regression/musicxml/11a-TimeSignatures-CompoundSimple.xml b/input/regression/musicxml/11a-TimeSignatures-CompoundSimple.xml new file mode 100644 index 0000000000..576ad4e87c --- /dev/null +++ b/input/regression/musicxml/11a-TimeSignatures-CompoundSimple.xml @@ -0,0 +1,137 @@ + + + + + + Compound time signatures with + same denominator: (3+2)/8 and (5+3+1)/4. + + + + + MusicXML Part + + + + + + + 2 + + 0 + major + + + + G + 2 + + + + + B + 4 + + 1 + 1 + eighth + begin + + + + B + 4 + + 1 + 1 + eighth + continue + + + + B + 4 + + 1 + 1 + eighth + end + + + + B + 4 + + 1 + 1 + eighth + begin + + + + B + 4 + + 1 + 1 + eighth + end + + + + + + + + + + A + 4 + + 8 + + 1 + whole + + + + A + 4 + + 2 + 1 + quarter + + + + A + 4 + + 6 + 1 + half + + + + + A + 4 + + 2 + 1 + quarter + + + light-heavy + + + + + diff --git a/input/regression/musicxml/11b-TimeSignatures-CompoundMultiple.xml b/input/regression/musicxml/11b-TimeSignatures-CompoundMultiple.xml new file mode 100644 index 0000000000..8c9ccb0833 --- /dev/null +++ b/input/regression/musicxml/11b-TimeSignatures-CompoundMultiple.xml @@ -0,0 +1,159 @@ + + + + + + Compound time signatures with + separate fractions displayed: 3/8+2/8+3/4 and 5/2+1/8. + + + + + MusicXML Part + + + + + + + 2 + + 0 + major + + + + G + 2 + + + + + B + 4 + + 1 + 1 + eighth + begin + + + + B + 4 + + 1 + 1 + eighth + continue + + + + B + 4 + + 1 + 1 + eighth + end + + + + B + 4 + + 1 + 1 + eighth + begin + + + + B + 4 + + 1 + 1 + eighth + end + + + + B + 4 + + 2 + 1 + quarter + + + + B + 4 + + 2 + 1 + quarter + + + + B + 4 + + 2 + 1 + quarter + + + + + + + + + + A + 4 + + 16 + 1 + breve + + + + A + 4 + + 4 + 1 + half + + + + A + 4 + + 1 + 1 + eighth + + + light-heavy + + + + + diff --git a/input/regression/musicxml/11c-TimeSignatures-CompoundMixed.xml b/input/regression/musicxml/11c-TimeSignatures-CompoundMixed.xml new file mode 100644 index 0000000000..5f62ccfc07 --- /dev/null +++ b/input/regression/musicxml/11c-TimeSignatures-CompoundMixed.xml @@ -0,0 +1,119 @@ + + + + + + Compound time signatures of + mixed type: (3+2)/8+3/4. + + + + + MusicXML Part + + + + + + + 2 + + 0 + major + + + + G + 2 + + + + + B + 4 + + 1 + 1 + eighth + begin + + + + B + 4 + + 1 + 1 + eighth + continue + + + + B + 4 + + 1 + 1 + eighth + end + + + + B + 4 + + 1 + 1 + eighth + begin + + + + B + 4 + + 1 + 1 + eighth + end + + + + B + 4 + + 2 + 1 + quarter + + + + B + 4 + + 2 + 1 + quarter + + + + B + 4 + + 2 + 1 + quarter + + + light-heavy + + + + + diff --git a/input/regression/musicxml/11d-TimeSignatures-SingleNumber.xml b/input/regression/musicxml/11d-TimeSignatures-SingleNumber.xml new file mode 100644 index 0000000000..510b66932e --- /dev/null +++ b/input/regression/musicxml/11d-TimeSignatures-SingleNumber.xml @@ -0,0 +1,70 @@ + + + + + + Time signature displayed as a + single number. + + + + + MusicXML Part + + + + + + + 2 + + 0 + major + + + + G + 2 + + + + + B + 4 + + 1 + 1 + eighth + begin + + + + B + 4 + + 1 + 1 + eighth + continue + + + + B + 4 + + 1 + 1 + eighth + end + + + light-heavy + + + + + diff --git a/input/regression/musicxml/11e-TimeSignatures-SenzaMisura.xml b/input/regression/musicxml/11e-TimeSignatures-SenzaMisura.xml new file mode 100644 index 0000000000..32b372981d --- /dev/null +++ b/input/regression/musicxml/11e-TimeSignatures-SenzaMisura.xml @@ -0,0 +1,68 @@ + + + + + + Senza-misura time signature + + + + + MusicXML Part + + + + + + + 2 + + 0 + major + + + + G + 2 + + + + + B + 4 + + 1 + 1 + eighth + begin + + + + B + 4 + + 1 + 1 + eighth + continue + + + + B + 4 + + 1 + 1 + eighth + end + + + light-heavy + + + + + diff --git a/python/musicexp.py b/python/musicexp.py index e87b996ea3..e69f2ab9f0 100644 --- a/python/musicexp.py +++ b/python/musicexp.py @@ -1440,9 +1440,17 @@ class KeySignatureChange (Music): class TimeSignatureChange (Music): def __init__ (self): Music.__init__ (self) - self.fraction = (4,4) + self.fractions = [4,4] def ly_expression (self): - return '\\time %d/%d ' % self.fraction + # Easy case: self.fractions = [n,d] => normal \time n/d call: + if len (self.fractions) == 2 and isinstance (self.fractions[0], int): + return '\\time %d/%d ' % tuple (self.fractions) + elif self.fractions and not isinstance (self.fractions[0], list): + # TODO: Implement non-standard time-signatures + return '' + else: + # TODO: Implement non-standard time-signatures + return '' class ClefChange (Music): def __init__ (self): diff --git a/python/musicxml.py b/python/musicxml.py index 1c159924b0..1ababbc7d5 100644 --- a/python/musicxml.py +++ b/python/musicxml.py @@ -294,6 +294,7 @@ class Attributes (Measure_element): Measure_element.__init__ (self) self._dict = {} self._original_tag = None + self._time_signature_cache = None def is_first (self): cn = self._parent.get_typed_children (self.__class__) @@ -311,26 +312,68 @@ class Attributes (Measure_element): def get_named_attribute (self, name): return self._dict.get (name) + + def single_time_sig_to_fraction (self, sig): + if len (sig) < 2: + return 0 + n = 0 + for i in sig[0:-1]: + n += i + return Rational (n, sig[-1]) def get_measure_length (self): - (n,d) = self.get_time_signature () - return Rational (n,d) + sig = self.get_time_signature () + if len (sig) == 0: + return 0 + if isinstance (sig[0], list): + # Complex compound time signature + l = 0 + for i in sig: + l += self.single_time_sig_to_fraction (i) + return l + else: + # Simple (maybe compound) time signature of the form (beat, ..., type) + return self.single_time_sig_to_fraction (sig) + return 0 def get_time_signature (self): - "return time sig as a (beat, beat-type) tuple" + "Return time sig as a (beat, beat-type) tuple. For compound signatures," + "return either (beat, beat,..., beat-type) or ((beat,..., type), " + "(beat,..., type), ...)." + if self._time_signature_cache: + return self._time_signature_cache try: mxl = self.get_named_attribute ('time') - if mxl: - beats = mxl.get_maybe_exist_named_child ('beats') - type = mxl.get_maybe_exist_named_child ('beat-type') - return (int (beats.get_text ()), - int (type.get_text ())) - else: + if not mxl: + return (4, 4) + + if mxl.get_maybe_exist_named_child ('senza-misura'): + # TODO: Handle pieces without a time signature! + error (_ ("Senza-misura time signatures are not yet supported!")) return (4, 4) + else: + signature = [] + current_sig = [] + for i in mxl.get_all_children (): + if isinstance (i, Beats): + beats = string.split (i.get_text ().strip (), "+") + current_sig = [int (j) for j in beats] + elif isinstance (i, BeatType): + current_sig.append (int (i.get_text ())) + signature.append (current_sig) + current_sig = [] + if len (signature) == 1 and isinstance (signature[0], list): + signature = signature[0] + if len (signature) ==0: + error (_ ("requested time signature, but time sig is unknown")) + return (4, 4) + self._time_signature_cache = signature + return signature except KeyError: error (_ ("requested time signature, but time sig is unknown")) return (4, 4) + #except # returns clef information in the form ("cleftype", position, octave-shift) def get_clef_information (self): @@ -1064,6 +1107,12 @@ class Frame_Note (Music_xml_node): class FiguredBass (Music_xml_node): pass +class Beats (Music_xml_node): + pass + +class BeatType (Music_xml_node): + pass + class BeatUnit (Music_xml_node): pass @@ -1087,6 +1136,8 @@ class_dict = { 'bar-style': BarStyle, 'bass': Bass, 'beam' : Beam, + 'beats': Beats, + 'beat-type': BeatType, 'beat-unit': BeatUnit, 'beat-unit-dot': BeatUnitDot, 'bend' : Bend, diff --git a/scripts/musicxml2ly.py b/scripts/musicxml2ly.py index 2db934ae58..78d8325c6d 100644 --- a/scripts/musicxml2ly.py +++ b/scripts/musicxml2ly.py @@ -737,11 +737,14 @@ def musicxml_clef_to_lily (attributes): return change def musicxml_time_to_lily (attributes): - (beats, type) = attributes.get_time_signature () + sig = attributes.get_time_signature () + + # TODO: Handle single-digit time sigs + # TODO: Handle senza-misura measures change = musicexp.TimeSignatureChange() - change.fraction = (beats, type) - + change.fractions = sig + return change def musicxml_key_to_lily (attributes): @@ -1776,12 +1779,12 @@ class LilyPondVoiceBuilder: self.pending_multibar = Rational (0) self.ignore_skips = False self.has_relevant_elements = False - self.measure_length = (4, 4) + self.measure_length = Rational (4, 4) def _insert_multibar (self): layout_information.set_context_item ('Score', 'skipBars = ##t') r = musicexp.MultiMeasureRest () - lenfrac = Rational (self.measure_length[0], self.measure_length[1]) + lenfrac = self.measure_length r.duration = rational_to_lily_duration (lenfrac) r.duration.factor *= self.pending_multibar / lenfrac self.elements.append (r) @@ -1929,7 +1932,7 @@ def musicxml_step_to_lily (step): def measure_length_from_attributes (attr, current_measure_length): mxl = attr.get_named_attribute ('time') if mxl: - return attr.get_time_signature () + return attr.get_measure_length () else: return current_measure_length @@ -1965,7 +1968,7 @@ def musicxml_voice_to_lily_voice (voice): voice_builder = LilyPondVoiceBuilder () figured_bass_builder = LilyPondVoiceBuilder () chordnames_builder = LilyPondVoiceBuilder () - current_measure_length = (4, 4) + current_measure_length = Rational (4, 4) voice_builder.set_measure_length (current_measure_length) for n in voice._elements: