Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/master/C5 - Sequence Models/Week 1/Jazz improvisation with LSTM/preprocess.py
Views: 4819
'''1Author: Ji-Sung Kim2Project: deepjazz3Purpose: Parse, cleanup and process data.45Code adapted from Evan Chow's jazzml, https://github.com/evancchow/jazzml with6express permission.7'''89from __future__ import print_function1011from music21 import *12from collections import defaultdict, OrderedDict13from itertools import groupby, zip_longest1415from grammar import *1617from grammar import parse_melody18from music_utils import *1920#----------------------------HELPER FUNCTIONS----------------------------------#2122''' Helper function to parse a MIDI file into its measures and chords '''23def __parse_midi(data_fn):24# Parse the MIDI data for separate melody and accompaniment parts.25midi_data = converter.parse(data_fn)26# Get melody part, compress into single voice.27melody_stream = midi_data[5] # For Metheny piece, Melody is Part #5.28melody1, melody2 = melody_stream.getElementsByClass(stream.Voice)29for j in melody2:30melody1.insert(j.offset, j)31melody_voice = melody13233for i in melody_voice:34if i.quarterLength == 0.0:35i.quarterLength = 0.253637# Change key signature to adhere to comp_stream (1 sharp, mode = major).38# Also add Electric Guitar.39melody_voice.insert(0, instrument.ElectricGuitar())40melody_voice.insert(0, key.KeySignature(sharps=1))4142# The accompaniment parts. Take only the best subset of parts from43# the original data. Maybe add more parts, hand-add valid instruments.44# Should add least add a string part (for sparse solos).45# Verified are good parts: 0, 1, 6, 7 '''46partIndices = [0, 1, 6, 7]47comp_stream = stream.Voice()48comp_stream.append([j.flat for i, j in enumerate(midi_data)49if i in partIndices])5051# Full stream containing both the melody and the accompaniment.52# All parts are flattened.53full_stream = stream.Voice()54for i in range(len(comp_stream)):55full_stream.append(comp_stream[i])56full_stream.append(melody_voice)5758# Extract solo stream, assuming you know the positions ..ByOffset(i, j).59# Note that for different instruments (with stream.flat), you NEED to use60# stream.Part(), not stream.Voice().61# Accompanied solo is in range [478, 548)62solo_stream = stream.Voice()63for part in full_stream:64curr_part = stream.Part()65curr_part.append(part.getElementsByClass(instrument.Instrument))66curr_part.append(part.getElementsByClass(tempo.MetronomeMark))67curr_part.append(part.getElementsByClass(key.KeySignature))68curr_part.append(part.getElementsByClass(meter.TimeSignature))69curr_part.append(part.getElementsByOffset(476, 548,70includeEndBoundary=True))71cp = curr_part.flat72solo_stream.insert(cp)7374# Group by measure so you can classify.75# Note that measure 0 is for the time signature, metronome, etc. which have76# an offset of 0.0.77melody_stream = solo_stream[-1]78measures = OrderedDict()79offsetTuples = [(int(n.offset / 4), n) for n in melody_stream]80measureNum = 0 # for now, don't use real m. nums (119, 120)81for key_x, group in groupby(offsetTuples, lambda x: x[0]):82measures[measureNum] = [n[1] for n in group]83measureNum += 18485# Get the stream of chords.86# offsetTuples_chords: group chords by measure number.87chordStream = solo_stream[0]88chordStream.removeByClass(note.Rest)89chordStream.removeByClass(note.Note)90offsetTuples_chords = [(int(n.offset / 4), n) for n in chordStream]9192# Generate the chord structure. Use just track 1 (piano) since it is93# the only instrument that has chords.94# Group into 4s, just like before.95chords = OrderedDict()96measureNum = 097for key_x, group in groupby(offsetTuples_chords, lambda x: x[0]):98chords[measureNum] = [n[1] for n in group]99measureNum += 1100101# Fix for the below problem.102# 1) Find out why len(measures) != len(chords).103# ANSWER: resolves at end but melody ends 1/16 before last measure so doesn't104# actually show up, while the accompaniment's beat 1 right after does.105# Actually on second thought: melody/comp start on Ab, and resolve to106# the same key (Ab) so could actually just cut out last measure to loop.107# Decided: just cut out the last measure.108del chords[len(chords) - 1]109assert len(chords) == len(measures)110111return measures, chords112113''' Helper function to get the grammatical data from given musical data. '''114def __get_abstract_grammars(measures, chords):115# extract grammars116abstract_grammars = []117for ix in range(1, len(measures)):118m = stream.Voice()119for i in measures[ix]:120m.insert(i.offset, i)121c = stream.Voice()122for j in chords[ix]:123c.insert(j.offset, j)124parsed = parse_melody(m, c)125abstract_grammars.append(parsed)126127return abstract_grammars128129#----------------------------PUBLIC FUNCTIONS----------------------------------#130131''' Get musical data from a MIDI file '''132def get_musical_data(data_fn):133134measures, chords = __parse_midi(data_fn)135abstract_grammars = __get_abstract_grammars(measures, chords)136137return chords, abstract_grammars138139''' Get corpus data from grammatical data '''140def get_corpus_data(abstract_grammars):141corpus = [x for sublist in abstract_grammars for x in sublist.split(' ')]142values = set(corpus)143val_indices = dict((v, i) for i, v in enumerate(values))144indices_val = dict((i, v) for i, v in enumerate(values))145146return corpus, values, val_indices, indices_val147148'''149def load_music_utils():150chord_data, raw_music_data = get_musical_data('data/original_metheny.mid')151music_data, values, values_indices, indices_values = get_corpus_data(raw_music_data)152153X, Y = data_processing(music_data, values_indices, Tx = 20, step = 3)154return (X, Y)155'''156157158