I have extracted notes, chords, rests and time signatures from parsed MIDI file. Storing them and again playing them back, I still cannot get the original speed and mix of sounds. What am I doing wrong? What am I forgetting?

temp_name = 'Chopin.midi'#any example of MIDI song
temp_score = converter.parse(temp_name)
flat = temp_score.flat
all_elements = []
# Iterate over the elements in the flattened stream
for el in flat:
    if isinstance(el, music21.note.Note):
        pitch = el.pitch
        note_name = pitch.nameWithOctave
        new_note_c = note.Note(note_name)
        new_note_c.duration = el.duration
        dur = float(el.duration.quarterLength)
        all_elements.append((str(note_name), dur))
    elif isinstance(el, music21.chord.Chord):
        chord_pitches = []
        for p in el.pitches:
            #note_name = p.pitch
            #note_name_oct = note_name.nameWithOctave
            new_note_c = note.Note(p.nameWithOctave)
            #new_note_c.duration = el.duration
            dur = float(el.duration.quarterLength)
        chord_pitches = ".".join([i for i in chord_pitches])
    #elif isinstance(el, note.Rest):
    #    rest_duration = el.duration.quarterLength
    #    temp_str = 'REST'
    #    all_elements.append((temp_str, rest_duration))
    elif isinstance(el, music21.meter.TimeSignature):
        current_time_signature = el.ratioString
        all_elements.append(('TIME_SIGNATURE', current_time_signature))

Here, extracting the rests resulted in unnecessary rests in the output and I have no idea how it is possible. The code to run back these sequences is as follows:

def get_music_midi_filename_from_chords(input_chords, initial_ts, initial_tempo):
    midi_stream = stream.Stream()
    new_tempo = tempo.MetronomeMark(number=initial_tempo)
    for note_pattern, duration_pattern in input_chords:
        if 'TIME_SIGNATURE' in note_pattern:
            ts_numerator, ts_denominator = duration_pattern.split('/')
            new_ts = meter.TimeSignature(f'{ts_numerator}/{ts_denominator}')

        if '.' in note_pattern:
            notes_in_chord = note_pattern.split('.')
            chord_notes = []
            for current_note in notes_in_chord:
                new_note = note.Note(current_note)
                new_note.duration = duration.Duration(duration_pattern)
                new_note.storedInstrument = instrument.Piano()
            new_chord = chord.Chord(chord_notes)
        elif 'REST' in note_pattern:
            rest_ = note.Rest()
            rest_.duration = duration.Duration(duration_pattern)
            if is_valid_pitch(note_pattern):
                note_single = note.Note(note_pattern)
                note_single.duration = duration.Duration(duration_pattern)
                note_single.storedInstrument = instrument.Piano()

    midi_stream = midi_stream.chordify()
    timestr = time.strftime("%Y%m%d-%H%M%S")
    new_file = 'output-' + timestr + '.mid'
    return midi_stream.write('midi', fp=new_file

Here, initial tempo is taken as initial_tempo = temp_score.flat.getElementsByClass('MetronomeMark')[0].number and initial time signature is taken as initial_ts = temp_score.recurse().getElementsByClass(music21.meter.TimeSignature)[0]

The function is_valid_pitch() is :

def is_valid_pitch(note_pattern):
        p = music21.pitch.Pitch(note_pattern)
        return True
        return False

I am addressing time signatures and tempo as well from the song. But again, the timing duration is differed from the original. When I include the rests from the MIDI flat, why am I getting unusual lengths of rests and the duration is increased way too much? How can I improve this code? What am I missing? I am quite lost in it now.

I need to be able to store all the required features under an array, basically trying to create an audio dataset, and then after training, I will be producing the music. But before training, I am not able to even replay back the same MIDI I have parsed in the original way.

  • 1
    Can you combine your code into a single example that will run by itself? It takes some work to combine your various code snippets to test your code. Also, right now, your example code is missing a function "is_valid_pitch" that it needs to run.
    – Bavi_H
    Feb 14, 2023 at 16:55
  • 1
    Can you provide a simple MIDI file you are having a problem with?
    – Bavi_H
    Feb 14, 2023 at 16:55
  • 1
    Just out of curiosity, can you tell more about what kind of MIDI file analysis or conversion you eventually want to accomplish?
    – Bavi_H
    Feb 14, 2023 at 17:26
  • I answered some of you r queries and added the code snippets in my question as well. I want to just play back the original MIDI back by taking the features. After that, I may be able to train.
    – ROOT31415
    Feb 15, 2023 at 7:44


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.