def element_note(self, note, time_spine, events, meta_events, state): if note.find("./rest") is None and note.find("./grace") is None: duration = int(note.findtext("./duration") or "0") lyric = note.find("./lyric") if lyric != None: self.element_lyric(lyric, time_spine, events, meta_events, state) pitch = note.find("./pitch") pitch_name = pitch.findtext("./step") alter = int(pitch.findtext("./alter") or "0") octave = int(pitch.findtext("./octave") or "3") midi_number = int_range_check( pitch_names_to_semitones[pitch_name] + alter + (octave + 1) * 12, 0, MAX_7_BIT, "Note value", state.warnings) note_on = Element("NoteOn", Channel = str(state.channel), Note = str(midi_number), Velocity = str(state.dynamics)) events.append(make_event(note_on, time_spine, state.ticks_per_beat)) note_off = Element("NoteOff", Channel = str(state.channel), Note = str(midi_number), Velocity = "0") events.append( make_event(note_off, int(time_spine + max(0, self.convert_duration(duration, state.divisions) - 1)), state.ticks_per_beat))
def element_lyric(self, lyric, time_spine, events, meta_events, state): # NOTE: Lyric syllables from MusicXML -> MidiXML are pretty weak for obvious reasons syllable = lyric.findtext("./text") syllabic = lyric.findtext("./syllabic") if syllabic in ("begin", "middle"): syllable += "-" output = Element("Lyric") output.text = syllable events.append(make_event(output, time_spine, state.ticks_per_beat))
def make_control_change(self, number, value, time_spine, state): value = int_range_check(value, 0, MAX_7_BIT, "Controller %d" % number, state.warnings) control = Element("ControlChange", Channel = str(state.channel), Number = str(number), Value = str(value)) return make_event(control, time_spine, state.ticks_per_beat)
def element_midi_instrument(self, midi_inst, time_spine, events, meta_events, state): state.channel = midi_inst.findtext("./midi-channel") or state.channel name = midi_inst.findtext("./midi-name") if name != None: program_name = Element("ProgramName") program_name.text = name events.append(make_event(program_name, time_spine, state.ticks_per_beat)) bank = midi_inst.findtext("./midi-bank") if bank != None: self.make_control_change14(bank, BANK_SELECT_MSB, time_spine, state) program = midi_inst.findtext("./midi-program") if program != None: program_change = Element("ProgramChange", Channel = str(state.channel), Number = program) events.append(make_event(program_change, time_spine, state.ticks_per_beat))
def element_key(self, key, time_spine, events, meta_events, state): fifths = key.findtext("fifths") if fifths != None: fifths = int_range_check(fifths, -7, 7, "<fifths>", state.warnings) mode = key.findtext("mode") if m2m_modes.has_key(mode): mode = m2m_modes[mode] else: mode = 0 key_tag = Element("KeySignature", Fifths=str(fifths), Mode=str(mode)) meta_events.append(make_event(key_tag, time_spine, state.ticks_per_beat))
def element_time(self, time, time_spine, events, meta_events, state): numerator = int_range_check(time.findtext("./beats"), 0, MAX_7_BIT, "<time><beats>", state.warnings) beat_type = int_range_check(time.findtext("./beat-type"), 0, 256, "<time><beat-type>", state.warnings) denominator = int(log(beat_type) / log(2)) clocks_per_tick = int(state.ticks_per_beat * 4 / beat_type) thirty_seconds = int((float(state.ticks_per_beat) * 8.0) / 24.0) time_sig = Element("TimeSignature", Numerator = str(numerator), LogDenominator = str(denominator), MIDIClocksPerMetronomeClick = str(clocks_per_tick), ThirtySecondsPer24Clocks = str(thirty_seconds)) meta_events.append(make_event(time_sig, time_spine, state.ticks_per_beat))
def element_sound(self, sound, time_spine, events, meta_events, state): tempo = sound.get("tempo") if tempo != None: tempo = float(tempo) value = int_range_check((60.0 / tempo) * 1000000, 0, MAX_24_BIT, "Tempo value", state.warnings) tempo_tag = Element("SetTempo", Value=str(value)) meta_events.append(make_event(tempo_tag, time_spine, state.ticks_per_beat)) dynamics = sound.get("dynamics") if dynamics != None: state.dynamics = int_range_check(dynamics, 0, MAX_7_BIT, "<sound dynamics='x'>", state.warnings)
def convert(self, music_xml): state = self.State() state.ticks_per_beat = self._ticks_per_beat midi = Element("MIDIFile") state.format = config.get("midi_format") SubElement(midi, "Format").text = str(state.format) num_tracks = len(music_xml.findall("./part-list//score-part")) if num_tracks > 16: raise ValueError("Too many tracks to convert to MIDI (for now, at least).") # We always create a meta-track, so the number of tracks is actually len + 1 SubElement(midi, "TrackCount").text = str(num_tracks + 1) SubElement(midi, "TicksPerBeat").text = str(state.ticks_per_beat) SubElement(midi, "TimestampType").text = "Absolute" self.get_measure_lengths(music_xml, state) self.make_tracks(music_xml, midi, state) if self._warnings: for warning in state.warnings: print textwrap.fill("WARNING: " + warning) return midi
def make_event(subevent, time_spine, ticks_per_quarter_note): event = Element("Event") SubElement(event, "Absolute").text = str(int(time_spine)) event.time_spine = time_spine event.append(subevent) return event
def __call__(self, input, time_spine, events, meta_events, state): output = Element(self._name) output.text = input.text[:] events.append(make_event(output, time_spine, state.ticks_per_beat))
def element_creator(self, input, time_spine, events, meta_events, state): output = Element("TextEvent") output.text = input.get("type") + ": " + input.text meta_events.append(make_event(output, time_spine, state.ticks_per_beat))