I have parsed a midi file, and I've successfully gotten a dictionary of notes broken up by instrument. An abbreviated example of this is note_dict
below, truncated for the purposes of this question.
My end goal is to have a nested dictionary that provides me with the track name, then each possible note as a key, then a list of all possible "next" notes as values. The intent is to use this in as a Markov chain in Foxdot, a python interface for music generation.
It should look something like:
{'track1': {note: [note1, note2, note3], note2: [note1, note2, note3]}, 'track2': {note: [note1, note2, note3], note2: [note1, note2, note3]}
Here is an example of what I have:
import itertools
def pairwise(iterable):
a, b = itertools.tee(iterable)
next(b, None)
return list(zip(a, b))
note_dict = {'Vocal': [-2, -2, -1, -2], 'Guitar': [1, 1, 4, 1, -2, 1]}
note_dict_updated = { track: [{ n for n in notes }, pairwise(notes), notes] for track, notes in note_dict.items() }
print(note_dict_updated)
This gives me the following, where the first set is all distinct notes, the list of tuples is a pairing of (note, next note)
, and the last list is just a raw list of notes in order.
{'Vocal': [{-2, -1}, [(-2, -2), (-2, -1), (-1, -2)], [-2, -2, -1, -2]], 'Guitar': [{1, 4, -2}, [(1, 1), (1, 4), (4, 1), (1, -2), (-2, 1)], [1, 1, 4, 1, -2, 1]]}
I'd like the elements of the sets to act as keys, and when the first element of the tuple matches an element of the set, it is added to a list of values associated with the key.
My desired end result, based on note_dict
above is:
{'Vocal': {-2: [-2, -1], -1: [-2]}, 'Guitar': {1: [1, 4, -2], 4: [1], -2: [1]}}
All that said, I am not locked into the method where I need to work with note_dict_updated
. If there is a smarter way to get from note_dict
to my desired end result, I'd love to hear.
edit: I've updated my question a bit. The first answer worked for my initial example, but I believe there are issues when the list of notes in each value overlap. Hopefully, my updated desired end result will be more helpful.
The first loop creates an intermediary dictionary of dictionary with inner keys and the same unique sets. This is then cleaned with a second a for-loop as shown here:
Input:
Output:
Code: