+ def get_key_signature(self):
+ "return(fifths, mode) tuple if the key signatures is given as "
+ "major/minor in the Circle of fifths. Otherwise return an alterations"
+ "list of the form [[step,alter<,octave>], [step,alter<,octave>], ...], "
+ "where the octave values are optional."
+
+ key = self.get_named_attribute('key')
+ if not key:
+ return None
+ fifths_elm = key.get_maybe_exist_named_child('fifths')
+ if fifths_elm:
+ mode_node = key.get_maybe_exist_named_child('mode')
+ mode = None
+ if mode_node:
+ mode = mode_node.get_text()
+ if not mode or mode == '':
+ mode = 'major'
+ fifths = int(fifths_elm.get_text())
+ # TODO: Shall we try to convert the key-octave and the cancel, too?
+ return(fifths, mode)
+ else:
+ alterations = []
+ current_step = 0
+ for i in key.get_all_children():
+ if isinstance(i, KeyStep):
+ current_step = i.get_text().strip()
+ elif isinstance(i, KeyAlter):
+ alterations.append([current_step, utilities.interpret_alter_element(i)])
+ elif isinstance(i, KeyOctave):
+ nr = -1
+ if hasattr(i, 'number'):
+ nr = int(i.number)
+ if(nr > 0) and(nr <= len(alterations)):
+ # MusicXML Octave 4 is middle C -> shift to 0
+ alterations[nr - 1].append(int(i.get_text()) - 4)
+ else:
+ i.message(_("Key alteration octave given for a "
+ "non-existing alteration nr. %s, available numbers: %s!") %(nr, len(alterations)))
+ return alterations
+
+ def get_transposition(self):
+ return self.get_named_attribute('transpose')
+
+
+class Barline(Measure_element):
+
+ def to_lily_object(self):
+ # retval contains all possible markers in the order:
+ # 0..bw_ending, 1..bw_repeat, 2..barline, 3..fw_repeat, 4..fw_ending
+ retval = {}
+ bartype_element = self.get_maybe_exist_named_child("bar-style")
+ repeat_element = self.get_maybe_exist_named_child("repeat")
+ ending_element = self.get_maybe_exist_named_child("ending")
+
+ bartype = None
+ if bartype_element:
+ bartype = bartype_element.get_text()
+
+ if repeat_element and hasattr(repeat_element, 'direction'):
+ repeat = musicxml2ly_conversion.RepeatMarker()
+ repeat.direction = {"forward":-1, "backward": 1}.get(
+ repeat_element.direction, 0)
+
+ if((repeat_element.direction == "forward" and bartype == "heavy-light") or
+ (repeat_element.direction == "backward" and bartype == "light-heavy")):
+ bartype = None
+ if hasattr(repeat_element, 'times'):
+ try:
+ repeat.times = int(repeat_element.times)
+ except ValueError:
+ repeat.times = 2
+ repeat.event = self
+ if repeat.direction == -1:
+ retval[3] = repeat
+ else:
+ retval[1] = repeat
+
+ if ending_element and hasattr(ending_element, 'type'):
+ ending = musicxml2ly_conversion.EndingMarker()
+ ending.direction = {"start":-1, "stop": 1, "discontinue": 1}.get(
+ ending_element.type, 0)
+ ending.event = self
+ if ending.direction == -1:
+ retval[4] = ending
+ else:
+ retval[0] = ending
+ # TODO. ending number=""
+
+ if bartype:
+ b = musicexp.BarLine()
+ b.type = bartype
+ retval[2] = b
+
+ return retval.values()
+
+
+class Partial(Measure_element):
+ def __init__(self, partial):
+ Measure_element.__init__(self)
+ self.partial = partial
+
+
+class Stem(Music_xml_node):
+
+ stem_value_dict = {
+ 'down': 'stemDown',
+ 'up': 'stemUp',
+ 'double': None, # TODO: Implement
+ 'none': 'stemNeutral'
+ }
+
+ def to_stem_event(self):
+ values = []
+ value = self.stem_value_dict.get(self.get_text(), None)
+ stem_value = musicexp.StemEvent()
+ if value:
+ stem_value.value = value
+ values.append(stem_value)
+ return values
+
+ def to_stem_style_event(self):
+ styles = []
+ style_elm = musicexp.StemstyleEvent()
+ if hasattr(self, 'color'):
+ style_elm.color = utilities.hex_to_color(getattr(self, 'color'))
+ if(style_elm.color != None):
+ styles.append(style_elm)
+ return styles
+
+
+class Notehead(Music_xml_node):
+
+ 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, # TODO: Implement
+ 'arrow down': None, # TODO: Implement
+ 'arrow up': None, # TODO: Implement
+ 'slashed': None, # TODO: Implement
+ 'back slashed': None, # TODO: Implement
+ 'normal': None,
+ 'cluster': None, # TODO: Implement
+ 'none': '#f',
+ 'do': '\'do',
+ 're': '\'re',
+ 'mi': '\'mi',
+ 'fa': '\'fa',
+ 'so': None,
+ 'la': '\'la',
+ 'ti': '\'ti',
+ }
+
+ def to_lily_object(self): #function changed: additionally processcolor attribute
+ styles = []
+
+ # Notehead style
+ key = self.get_text().strip()
+ style = self.notehead_styles_dict.get(key, None)
+ event = musicexp.NotestyleEvent()
+ if style:
+ event.style = style
+ if hasattr(self, 'filled'):
+ event.filled =(getattr(self, 'filled') == "yes")
+ if hasattr(self, 'color'):
+ event.color = utilities.hex_to_color(getattr(self, 'color'))
+ if event.style or(event.filled != None) or(event.color != None):
+ styles.append(event)
+ # parentheses
+ if hasattr(self, 'parentheses') and(self.parentheses == "yes"):
+ styles.append(musicexp.ParenthesizeEvent())
+
+ return styles
+
+
+class Note(Measure_element):
+
+ drumtype_dict = {
+ 'Acoustic Snare Drum': 'acousticsnare',
+ 'Side Stick': 'sidestick',
+ 'Open Triangle': 'opentriangle',
+ 'Mute Triangle': 'mutetriangle',
+ 'Tambourine': 'tambourine',
+ 'Bass Drum': 'bassdrum',
+ }
+
+ def __init__(self):
+ Measure_element.__init__(self)
+ self.instrument_name = ''
+ self._after_grace = False
+ self._duration = 1
+
+ def is_grace(self):
+ return self.get_maybe_exist_named_child(u'grace')
+
+ def is_after_grace(self):
+ if not self.is_grace():
+ return False;
+ gr = self.get_maybe_exist_typed_child(Grace)
+ return self._after_grace or hasattr(gr, 'steal-time-previous');
+
+ def get_duration_log(self):
+ ch = self.get_maybe_exist_named_child(u'type')
+
+ if ch:
+ log = ch.get_text().strip()
+ return utilities.musicxml_duration_to_log(log)
+ elif self.get_maybe_exist_named_child(u'grace'):
+ # FIXME: is it ok to default to eight note for grace notes?
+ return 3
+ else:
+ return None
+
+ def get_duration_info(self):
+ log = self.get_duration_log()
+ if log != None:
+ dots = len(self.get_typed_children(Dot))
+ return(log, dots)
+ else:
+ return None
+
+ def get_factor(self):
+ return 1
+
+ def get_pitches(self):
+ return self.get_typed_children(get_class(u'pitch'))
+
+ def set_notehead_style(self, event):
+ noteheads = self.get_named_children('notehead')
+ for nh in noteheads:
+ styles = nh.to_lily_object()
+ for style in styles:
+ event.add_associated_event(style)
+
+ def set_stem_directions(self, event):
+ stems = self.get_named_children('stem')
+ for stem in stems:
+ values = stem.to_stem_event()
+ for v in values:
+ event.add_associated_event(v)
+
+ def set_stem_style(self, event):
+ stems = self.get_named_children('stem')
+ for stem in stems:
+ styles = stem.to_stem_style_event()
+ for style in styles:
+ event.add_associated_event(style)
+
+ def initialize_duration(self):
+ from musicxml2ly_conversion import rational_to_lily_duration
+ from musicexp import Duration
+ # if the note has no Type child, then that method returns None. In that case,
+ # use the <duration> tag instead. If that doesn't exist, either -> Error
+ dur = self.get_duration_info()
+ if dur:
+ d = Duration()
+ d.duration_log = dur[0]
+ d.dots = dur[1]
+ # Grace notes by specification have duration 0, so no time modification
+ # factor is possible. It even messes up the output with *0/1
+ if not self.get_maybe_exist_typed_child(Grace):
+ d.factor = self._duration / d.get_length()
+ return d
+ else:
+ if self._duration > 0:
+ return rational_to_lily_duration(self._duration)
+ else:
+ self.message(
+ _("Encountered note at %s without type and duration(=%s)") \
+ %(mxl_note.start, mxl_note._duration))
+ return None
+
+ def initialize_pitched_event(self):
+ mxl_pitch = self.get_maybe_exist_typed_child(Pitch)
+ pitch = mxl_pitch.to_lily_object()
+ event = musicexp.NoteEvent()
+ event.pitch = pitch
+ acc = self.get_maybe_exist_named_child('accidental')
+ if acc:
+ # let's not force accs everywhere.
+ event.cautionary = acc.cautionary
+ # TODO: Handle editorial accidentals
+ # TODO: Handle the level-display setting for displaying brackets/parentheses
+ return event
+
+ def initialize_unpitched_event(self):
+ # Unpitched elements have display-step and can also have
+ # display-octave.
+ unpitched = self.get_maybe_exist_typed_child(Unpitched)
+ event = musicexp.NoteEvent()
+ event.pitch = unpitched.to_lily_object()
+ return event
+
+ def initialize_rest_event(self, convert_rest_positions=True):
+ # rests can have display-octave and display-step, which are
+ # treated like an ordinary note pitch
+ rest = self.get_maybe_exist_typed_child(Rest)
+ event = musicexp.RestEvent()
+ if convert_rest_positions:
+ pitch = rest.to_lily_object()
+ event.pitch = pitch
+ return event
+
+ def initialize_drum_event(self):
+ event = musicexp.NoteEvent()
+ drum_type = self.drumtype_dict.get(self.instrument_name)
+ if drum_type:
+ event.drum_type = drum_type
+ else:
+ self.message(
+ _("drum %s type unknown, please add to instrument_drumtype_dict")
+ % n.instrument_name)
+ event.drum_type = 'acousticsnare'
+ return event
+
+ def to_lily_object(self,
+ convert_stem_directions=True,
+ convert_rest_positions=True):
+ pitch = None
+ duration = None
+ event = None
+
+ if self.get_maybe_exist_typed_child(Pitch):
+ event = self.initialize_pitched_event()
+ elif self.get_maybe_exist_typed_child(Unpitched):
+ event = self.initialize_unpitched_event()
+ elif self.get_maybe_exist_typed_child(Rest):
+ event = self.initialize_rest_event(convert_rest_positions)
+ elif self.instrument_name:
+ event = self.initialize_drum_event()
+ else:
+ self.message(_("cannot find suitable event"))
+
+ if event:
+ event.duration = self.initialize_duration()