From 8025288feb5f0d9342b04fff801f9947575e3a81 Mon Sep 17 00:00:00 2001 From: Reinhold Kainhofer Date: Sat, 29 Nov 2008 19:16:32 +0100 Subject: [PATCH] MusicXML: Implement notehead styles and parenthesized notes --- .../regression/musicxml/07-NoteSettings.itexi | 1 + input/regression/musicxml/07a-Noteheads.xml | 1387 +++++++++++++++++ .../musicxml/07b-Staff-Notestyles.xml | 188 +++ .../musicxml/07c-Noteheads-Chords.xml | 179 +++ .../musicxml/07d-Parenthesized-Noteheads.xml | 140 ++ python/musicexp.py | 88 +- scripts/musicxml2ly.py | 52 +- 7 files changed, 2028 insertions(+), 7 deletions(-) create mode 100644 input/regression/musicxml/07-NoteSettings.itexi create mode 100644 input/regression/musicxml/07a-Noteheads.xml create mode 100644 input/regression/musicxml/07b-Staff-Notestyles.xml create mode 100644 input/regression/musicxml/07c-Noteheads-Chords.xml create mode 100644 input/regression/musicxml/07d-Parenthesized-Noteheads.xml diff --git a/input/regression/musicxml/07-NoteSettings.itexi b/input/regression/musicxml/07-NoteSettings.itexi new file mode 100644 index 0000000000..f73f6e4721 --- /dev/null +++ b/input/regression/musicxml/07-NoteSettings.itexi @@ -0,0 +1 @@ +@section Note settings, heads, etc. diff --git a/input/regression/musicxml/07a-Noteheads.xml b/input/regression/musicxml/07a-Noteheads.xml new file mode 100644 index 0000000000..287488727e --- /dev/null +++ b/input/regression/musicxml/07a-Noteheads.xml @@ -0,0 +1,1387 @@ + + + + + + Different note styles, using the + <notehead> element. First, each note head style is printed + with four quarter notes, two with filled heads, two with unfilled + heads, where first the stem is up and then the stem is down. After + that, each note head style is printed with a half note (should have + an unfilled head by default). Finally, the Aiken note head styles are + tested, once with stem up and once with stem down. + + + + + MusicXML Part + + + + + + + 1 + + 0 + major + + + + G + 2 + + + + + A + 4 + + 1 + 1 + quarter + slash + slash + + + + C + 5 + + 1 + 1 + quarter + slash + + + + A + 4 + + 1 + 1 + quarter + slash + + + + C + 5 + + 1 + 1 + quarter + slash + + + + + + + A + 4 + + 1 + 1 + quarter + triangle + triangle + + + + C + 5 + + 1 + 1 + quarter + triangle + + + + A + 4 + + 1 + 1 + quarter + triangle + + + + C + 5 + + 1 + 1 + quarter + triangle + + + + + + + A + 4 + + 1 + 1 + quarter + diamond + diamond + + + + C + 5 + + 1 + 1 + quarter + diamond + + + + A + 4 + + 1 + 1 + quarter + diamond + + + + C + 5 + + 1 + 1 + quarter + diamond + + + + + + + A + 4 + + 1 + 1 + quarter + square + square + + + + C + 5 + + 1 + 1 + quarter + square + + + + A + 4 + + 1 + 1 + quarter + square + + + + C + 5 + + 1 + 1 + quarter + square + + + + + + + A + 4 + + 1 + 1 + quarter + cross + cross + + + + C + 5 + + 1 + 1 + quarter + cross + + + + A + 4 + + 1 + 1 + quarter + cross + + + + C + 5 + + 1 + 1 + quarter + cross + + + + + + + A + 4 + + 1 + 1 + quarter + x + x + + + + C + 5 + + 1 + 1 + quarter + x + + + + A + 4 + + 1 + 1 + quarter + x + + + + C + 5 + + 1 + 1 + quarter + x + + + + + + + A + 4 + + 1 + 1 + quarter + circle-x + circle-x + + + + C + 5 + + 1 + 1 + quarter + circle-x + + + + A + 4 + + 1 + 1 + quarter + circle-x + + + + C + 5 + + 1 + 1 + quarter + circle-x + + + + + + + A + 4 + + 1 + 1 + quarter + inverted triangle + inverted triangle + + + + C + 5 + + 1 + 1 + quarter + inverted triangle + + + + A + 4 + + 1 + 1 + quarter + inverted triangle + + + + C + 5 + + 1 + 1 + quarter + inverted triangle + + + + + + + A + 4 + + 1 + 1 + quarter + arrow down + arrow down + + + + C + 5 + + 1 + 1 + quarter + arrow down + + + + A + 4 + + 1 + 1 + quarter + arrow down + + + + C + 5 + + 1 + 1 + quarter + arrow down + + + + + + + A + 4 + + 1 + 1 + quarter + arrow up + arrow up + + + + C + 5 + + 1 + 1 + quarter + arrow up + + + + A + 4 + + 1 + 1 + quarter + arrow up + + + + C + 5 + + 1 + 1 + quarter + arrow up + + + + + + + A + 4 + + 1 + 1 + quarter + slashed + slashed + + + + C + 5 + + 1 + 1 + quarter + slashed + + + + A + 4 + + 1 + 1 + quarter + slashed + + + + C + 5 + + 1 + 1 + quarter + slashed + + + + + + + A + 4 + + 1 + 1 + quarter + back slashed + back slashed + + + + C + 5 + + 1 + 1 + quarter + back slashed + + + + A + 4 + + 1 + 1 + quarter + back slashed + + + + C + 5 + + 1 + 1 + quarter + back slashed + + + + + + + A + 4 + + 1 + 1 + quarter + normal + normal + + + + C + 5 + + 1 + 1 + quarter + normal + + + + A + 4 + + 1 + 1 + quarter + normal + + + + C + 5 + + 1 + 1 + quarter + normal + + + + + + + A + 4 + + 1 + 1 + quarter + cluster + cluster + + + + C + 5 + + 1 + 1 + quarter + cluster + + + + A + 4 + + 1 + 1 + quarter + cluster + + + + C + 5 + + 1 + 1 + quarter + cluster + + + + + + + A + 4 + + 1 + 1 + quarter + none + none + + + + C + 5 + + 1 + 1 + quarter + none + + + + A + 4 + + 1 + 1 + quarter + none + + + + C + 5 + + 1 + 1 + quarter + none + + + + + + + A + 4 + + 2 + 1 + half + slash + slash + + + + A + 4 + + 2 + 1 + half + triangle + triangle + + + + + + + A + 4 + + 2 + 1 + half + diamond + diamond + + + + A + 4 + + 2 + 1 + half + square + square + + + + + + + A + 4 + + 2 + 1 + half + cross + cross + + + + A + 4 + + 2 + 1 + half + x + x + + + + + + + A + 4 + + 2 + 1 + half + circle-x + circle-x + + + + A + 4 + + 2 + 1 + half + inverted triangle + inverted triangle + + + + + + + A + 4 + + 2 + 1 + half + arrow down + arrow down + + + + A + 4 + + 2 + 1 + half + arrow up + arrow up + + + + + + + A + 4 + + 2 + 1 + half + slashed + slashed + + + + A + 4 + + 2 + 1 + half + back slashed + back slashed + + + + + + + A + 4 + + 2 + 1 + half + normal + normal + + + + A + 4 + + 2 + 1 + half + cluster + cluster + + + + + + + A + 4 + + 1 + 1 + quarter + do + do + + + + C + 5 + + 1 + 1 + quarter + do + + + + A + 4 + + 1 + 1 + quarter + do + + + + C + 5 + + 1 + 1 + quarter + do + + + + + + + A + 4 + + 1 + 1 + quarter + re + re + + + + C + 5 + + 1 + 1 + quarter + re + + + + A + 4 + + 1 + 1 + quarter + re + + + + C + 5 + + 1 + 1 + quarter + re + + + + + + + A + 4 + + 1 + 1 + quarter + mi + mi + + + + C + 5 + + 1 + 1 + quarter + mi + + + + A + 4 + + 1 + 1 + quarter + mi + + + + C + 5 + + 1 + 1 + quarter + mi + + + + + + + A + 4 + + 1 + 1 + quarter + fa + fa + + + + C + 5 + + 1 + 1 + quarter + fa + + + + A + 4 + + 1 + 1 + quarter + fa + + + + C + 5 + + 1 + 1 + quarter + fa + + + + + + + A + 4 + + 1 + 1 + quarter + so + so + + + + C + 5 + + 1 + 1 + quarter + so + + + + A + 4 + + 1 + 1 + quarter + so + + + + C + 5 + + 1 + 1 + quarter + so + + + + + + + A + 4 + + 1 + 1 + quarter + la + la + + + + C + 5 + + 1 + 1 + quarter + la + + + + A + 4 + + 1 + 1 + quarter + la + + + + C + 5 + + 1 + 1 + quarter + la + + + + + + + A + 4 + + 1 + 1 + quarter + ti + ti + + + + C + 5 + + 1 + 1 + quarter + ti + + + + A + 4 + + 1 + 1 + quarter + ti + + + + C + 5 + + 1 + 1 + quarter + ti + + + + + + + 3 + major + + + + + A + 3 + + 1 + 1 + quarter + do + do + + + + B + 3 + + 1 + 1 + quarter + re + re + + + + C + 1 + 4 + + 1 + 1 + quarter + mi + mi + + + + D + 4 + + 1 + 1 + quarter + fa + fa + + + + + + + E + 4 + + 1 + 1 + quarter + so + so + + + + F + 1 + 4 + + 1 + 1 + quarter + la + la + + + + G + 1 + 4 + + 1 + 1 + quarter + ti + ti + + + + A + 4 + + 1 + 1 + quarter + do + do + + + + + + + 0 + major + + + + + C + 5 + + 1 + 1 + quarter + do + do + + + + D + 5 + + 1 + 1 + quarter + re + re + + + + E + 5 + + 1 + 1 + quarter + mi + mi + + + + F + 5 + + 1 + 1 + quarter + fa + fa + + + + + + + G + 5 + + 1 + 1 + quarter + so + so + + + + A + 5 + + 1 + 1 + quarter + la + la + + + + B + 5 + + 1 + 1 + quarter + ti + ti + + + + C + 6 + + 1 + 1 + quarter + do + do + + + light-heavy + + + + diff --git a/input/regression/musicxml/07b-Staff-Notestyles.xml b/input/regression/musicxml/07b-Staff-Notestyles.xml new file mode 100644 index 0000000000..f4267b0621 --- /dev/null +++ b/input/regression/musicxml/07b-Staff-Notestyles.xml @@ -0,0 +1,188 @@ + + + + + + Staff-connected note styles: + slash notation, hidden notes (with and without hidden staff + lines) + + + + + MusicXML Part + + + + + + + + + 70 + 0 + + 211 + + + + 1 + + 0 + major + + + + G + 2 + + + + + A + 4 + + 1 + 1 + quarter + down + + + + + + + + + A + 4 + + 1 + 1 + quarter + up + slash, no stem + + + + C + 5 + + 1 + 1 + quarter + down + + + + + + + + + + + + A + 4 + + 1 + 1 + quarter + down + slash, with stem + + + + + + + C + 5 + + 1 + 1 + quarter + down + + + + + + + + + A + 4 + + 1 + 1 + quarter + up + hidden notes + + + + C + 5 + + 1 + 1 + quarter + down + + + + 0 + + + + + C + 4 + + 1 + 1 + quarter + up + hidden notes, staff lines + + + + + + D + 4 + + 2 + 1 + half + up + + + + 5 + + + + + G + 4 + + 2 + 1 + half + up + normal settings restored + + + light-heavy + + + + + diff --git a/input/regression/musicxml/07c-Noteheads-Chords.xml b/input/regression/musicxml/07c-Noteheads-Chords.xml new file mode 100644 index 0000000000..5196040aeb --- /dev/null +++ b/input/regression/musicxml/07c-Noteheads-Chords.xml @@ -0,0 +1,179 @@ + + + + + + Different note styles for + individual notes inside a chord, using the + <notehead> element. + + + + + MusicXML Part + + + + + + + 1 + + 0 + major + + + + G + 2 + + + + + E + 5 + + 1 + 1 + quarter + normal + + + + + C + 5 + + 1 + 1 + quarter + triangle + triangle + + + + + A + 4 + + 1 + 1 + quarter + slash + slash + + + + E + 5 + + 1 + 1 + quarter + cross + cross + + + + + C + 5 + + 1 + 1 + quarter + square + square + + + + + A + 4 + + 1 + 1 + quarter + diamond + diamond + + + + E + 5 + + 1 + 1 + quarter + inverted triangle + inverted triangle + + + + + C + 5 + + 1 + 1 + quarter + circle-x + circle-x + + + + + A + 4 + + 1 + 1 + quarter + x + x + + + + E + 5 + + 1 + 1 + quarter + slashed + slashed + + + + + C + 5 + + 1 + 1 + quarter + arrow up + arrow up + + + + + A + 4 + + 1 + 1 + quarter + arrow down + arrow down + + + light-heavy + + + + diff --git a/input/regression/musicxml/07d-Parenthesized-Noteheads.xml b/input/regression/musicxml/07d-Parenthesized-Noteheads.xml new file mode 100644 index 0000000000..4e4fefad3f --- /dev/null +++ b/input/regression/musicxml/07d-Parenthesized-Noteheads.xml @@ -0,0 +1,140 @@ + + + + + + Parenthesized note heads. First, + a single parenthesized note is tested, once with a normal and then + with a non-standard notehead, then two chords with some/all + parenthesized noteheads and finally a parenthesized rest. + + + + + MusicXML Part + + + + + + + 1 + + 0 + major + + + + G + 2 + + + + + A + 4 + + 1 + 1 + quarter + + + + + A + 4 + + 1 + 1 + quarter + x + + + + A + 4 + + 1 + 1 + quarter + + + + + C + 5 + + 1 + 1 + quarter + + + + + + E + 5 + + 1 + 1 + quarter + + + + A + 4 + + 1 + 1 + quarter + + + + + + C + 5 + + 1 + 1 + quarter + + + + + + E + 5 + + 1 + 1 + quarter + + + + + 1 + 1 + quarter + + + + + E + 4 + + 1 + 1 + quarter + + + + light-heavy + + + + diff --git a/python/musicexp.py b/python/musicexp.py index 71d2d8b80f..e87b996ea3 100644 --- a/python/musicexp.py +++ b/python/musicexp.py @@ -845,7 +845,7 @@ class ChordEvent (NestedMusic): pitches = [] basepitch = None for x in note_events: - pitches.append (x.pitch.ly_expression ()) + pitches.append (x.chord_element_ly ()) if not basepitch: basepitch = previous_pitch printer ('<%s>' % string.join (pitches)) @@ -1188,6 +1188,47 @@ class FretEvent (MarkupEvent): else: return '' + +class FunctionWrapperEvent (Event): + def __init__ (self, function_name = None): + Event.__init__ (self) + self.function_name = function_name + def pre_note_ly (self, is_chord_element): + if self.function_name: + return "\\%s" % self.function_name + else: + return '' + def pre_chord_ly (self): + return '' + def ly_expression (self): + if self.function_name: + return "\\%s" % self.function_name + else: + return '' + +class ParenthesizeEvent (FunctionWrapperEvent): + def __init__ (self): + FunctionWrapperEvent.__init__ (self, "parenthesize") + +class NotestyleEvent (Event): + def __init__ (self): + Event.__init__ (self) + self.style = None + self.filled = None + def pre_chord_ly (self): + if self.style: + return "\\once \\override NoteHead #'style = #%s" % self.style + else: + return '' + def pre_note_ly (self, is_chord_element): + if self.style and is_chord_element: + return "\\tweak #'style #%s" % self.style + else: + return '' + def ly_expression (self): + return self.pre_chord_ly () + + class ChordPitch: def __init__ (self): self.alteration = 0 @@ -1267,7 +1308,24 @@ class RhythmicEvent(Event): def __init__ (self): Event.__init__ (self) self.duration = Duration() - + self.associated_events = [] + + def add_associated_event (self, ev): + if ev: + self.associated_events.append (ev) + + def pre_chord_ly (self): + return [ev.pre_chord_ly () for ev in self.associated_events] + + def pre_note_ly (self, is_chord_element): + return [ev.pre_note_ly (is_chord_element) for ev in self.associated_events] + + def ly_expression_pre_note (self, is_chord_element): + res = string.join (self.pre_note_ly (is_chord_element), ' ') + if res != '': + res = res + ' ' + return res + def get_length (self): return self.duration.get_length() @@ -1279,13 +1337,17 @@ class RestEvent (RhythmicEvent): def __init__ (self): RhythmicEvent.__init__ (self) self.pitch = None + def ly_expression (self): + res = self.ly_expression_pre_note (False) if self.pitch: - return "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ()) + return res + "%s%s\\rest" % (self.pitch.ly_expression (), self.duration.ly_expression ()) else: return 'r%s' % self.duration.ly_expression () def print_ly (self, printer): + for ev in self.associated_events: + ev.print_ly (printer) if self.pitch: self.pitch.print_ly (printer) self.duration.print_ly (printer) @@ -1324,17 +1386,31 @@ class NoteEvent(RhythmicEvent): excl_question += '!' return excl_question - + def ly_expression (self): + # obtain all stuff that needs to be printed before the note: + res = self.ly_expression_pre_note (True) if self.pitch: - return '%s%s%s' % (self.pitch.ly_expression (), + return res + '%s%s%s' % (self.pitch.ly_expression (), self.pitch_mods(), self.duration.ly_expression ()) elif self.drum_type: - return '%s%s' (self.drum_type, + return res + '%s%s' (self.drum_type, self.duration.ly_expression ()) + def chord_element_ly (self): + # obtain all stuff that needs to be printed before the note: + res = self.ly_expression_pre_note (True) + if self.pitch: + return res + '%s%s' % (self.pitch.ly_expression (), + self.pitch_mods()) + elif self.drum_type: + return res + '%s%s' (self.drum_type) + + def print_ly (self, printer): + for ev in self.associated_events: + ev.print_ly (printer) if self.pitch: self.pitch.print_ly (printer) printer (self.pitch_mods ()) diff --git a/scripts/musicxml2ly.py b/scripts/musicxml2ly.py index 16cfb00c9e..f29fa3ecbc 100644 --- a/scripts/musicxml2ly.py +++ b/scripts/musicxml2ly.py @@ -1470,6 +1470,50 @@ def musicxml_harmony_to_lily (n): return res +notehead_styles_dict = { + 'slash': '\'slash', + 'triangle': '\'triangle', + 'diamond': '\'diamond', + 'square': '\'la', # TODO: Proper squared note head + 'cross': None, # TODO: + shaped note head + 'x': '\'cross', + 'circle-x': '\'xcircle', + 'inverted triangle': None, # TOD: Implement + 'arrow down': None, # TOD: Implement + 'arrow up': None, # TOD: Implement + 'slashed': None, # TOD: Implement + 'back slashed': None, # TOD: Implement + 'normal': None, + 'cluster': None, # TOD: Implement + 'none': '#f', + 'do': '\'do', + 're': '\'re', + 'mi': '\'mi', + 'fa': '\'fa', + 'so': None, + 'la': '\'la', + 'ti': '\'ti', + } + +def musicxml_notehead_to_lily (nh): + styles = [] + + # Notehead style + style = notehead_styles_dict.get (nh.get_text ().strip (), None) + style_elm = musicexp.NotestyleEvent () + if style: + style_elm.style = style + if hasattr (nh, 'filled'): + style_elm.filled = (getattr (nh, 'filled') == "yes") + if style_elm.style or (style_elm.filled != None): + styles.append (style_elm) + + # parentheses + if hasattr (nh, 'parentheses') and (nh.parentheses == "yes"): + styles.append (musicexp.ParenthesizeEvent ()) + + return styles + def musicxml_chordpitch_to_lily (mxl_cpitch): r = musicexp.ChordPitch () r.alteration = mxl_cpitch.get_alteration () @@ -1678,7 +1722,13 @@ def musicxml_note_to_lily_main_event (n): n.message (_ ("cannot find suitable event")) if event: - event.duration = musicxml_duration_to_lily (n) + event.duration = musicxml_duration_to_lily (n) + + noteheads = n.get_named_children ('notehead') + for nh in noteheads: + styles = musicxml_notehead_to_lily (nh) + for s in styles: + event.add_associated_event (s) return event -- 2.39.2