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/data_utils.py
Views: 4819
from music_utils import *1from preprocess import *2from tensorflow.keras.utils import to_categorical34from collections import defaultdict5from mido import MidiFile6from pydub import AudioSegment7from pydub.generators import Sine8import math910#chords, abstract_grammars = get_musical_data('data/original_metheny.mid')11#corpus, tones, tones_indices, indices_tones = get_corpus_data(abstract_grammars)12#N_tones = len(set(corpus))13n_a = 6414x_initializer = np.zeros((1, 1, 90))15a_initializer = np.zeros((1, n_a))16c_initializer = np.zeros((1, n_a))1718def load_music_utils(file):19chords, abstract_grammars = get_musical_data(file)20corpus, tones, tones_indices, indices_tones = get_corpus_data(abstract_grammars)21N_tones = len(set(corpus))22X, Y, N_tones = data_processing(corpus, tones_indices, 60, 30)23return (X, Y, N_tones, indices_tones, chords)242526def generate_music(inference_model, indices_tones, chords, diversity = 0.5):27"""28Generates music using a model trained to learn musical patterns of a jazz soloist. Creates an audio stream29to save the music and play it.3031Arguments:32model -- Keras model Instance, output of djmodel()33indices_tones -- a python dictionary mapping indices (0-77) into their corresponding unique tone (ex: A,0.250,< m2,P-4 >)34temperature -- scalar value, defines how conservative/creative the model is when generating music3536Returns:37predicted_tones -- python list containing predicted tones38"""3940# set up audio stream41out_stream = stream.Stream()4243# Initialize chord variables44curr_offset = 0.0 # variable used to write sounds to the Stream.45num_chords = int(len(chords) / 3) # number of different set of chords4647print("Predicting new values for different set of chords.")48# Loop over all 18 set of chords. At each iteration generate a sequence of tones49# and use the current chords to convert it into actual sounds50for i in range(1, num_chords):5152# Retrieve current chord from stream53curr_chords = stream.Voice()5455# Loop over the chords of the current set of chords56for j in chords[i]:57# Add chord to the current chords with the adequate offset, no need to understand this58curr_chords.insert((j.offset % 4), j)5960# Generate a sequence of tones using the model61_, indices = predict_and_sample(inference_model)62indices = list(indices.squeeze())63pred = [indices_tones[p] for p in indices]6465predicted_tones = 'C,0.25 '66for k in range(len(pred) - 1):67predicted_tones += pred[k] + ' '6869predicted_tones += pred[-1]7071#### POST PROCESSING OF THE PREDICTED TONES ####72# We will consider "A" and "X" as "C" tones. It is a common choice.73predicted_tones = predicted_tones.replace(' A',' C').replace(' X',' C')7475# Pruning #1: smoothing measure76predicted_tones = prune_grammar(predicted_tones)7778# Use predicted tones and current chords to generate sounds79sounds = unparse_grammar(predicted_tones, curr_chords)8081# Pruning #2: removing repeated and too close together sounds82sounds = prune_notes(sounds)8384# Quality assurance: clean up sounds85sounds = clean_up_notes(sounds)8687# Print number of tones/notes in sounds88print('Generated %s sounds using the predicted values for the set of chords ("%s") and after pruning' % (len([k for k in sounds if isinstance(k, note.Note)]), i))8990# Insert sounds into the output stream91for m in sounds:92out_stream.insert(curr_offset + m.offset, m)93for mc in curr_chords:94out_stream.insert(curr_offset + mc.offset, mc)9596curr_offset += 4.09798# Initialize tempo of the output stream with 130 bit per minute99out_stream.insert(0.0, tempo.MetronomeMark(number=130))100101# Save audio stream to fine102mf = midi.translate.streamToMidiFile(out_stream)103mf.open("output/my_music.midi", 'wb')104mf.write()105print("Your generated music is saved in output/my_music.midi")106mf.close()107108# Play the final stream through output (see 'play' lambda function above)109# play = lambda x: midi.realtime.StreamPlayer(x).play()110# play(out_stream)111112return out_stream113114115def predict_and_sample(inference_model, x_initializer = x_initializer, a_initializer = a_initializer,116c_initializer = c_initializer):117"""118Predicts the next value of values using the inference model.119120Arguments:121inference_model -- Keras model instance for inference time122x_initializer -- numpy array of shape (1, 1, 78), one-hot vector initializing the values generation123a_initializer -- numpy array of shape (1, n_a), initializing the hidden state of the LSTM_cell124c_initializer -- numpy array of shape (1, n_a), initializing the cell state of the LSTM_cel125Ty -- length of the sequence you'd like to generate.126127Returns:128results -- numpy-array of shape (Ty, 78), matrix of one-hot vectors representing the values generated129indices -- numpy-array of shape (Ty, 1), matrix of indices representing the values generated130"""131132### START CODE HERE ###133pred = inference_model.predict([x_initializer, a_initializer, c_initializer])134indices = np.argmax(pred, axis = -1)135results = to_categorical(indices, num_classes=90)136### END CODE HERE ###137138return results, indices139140141def note_to_freq(note, concert_A=440.0):142'''143from wikipedia: http://en.wikipedia.org/wiki/MIDI_Tuning_Standard#Frequency_values144'''145return (2.0 ** ((note - 69) / 12.0)) * concert_A146147def ticks_to_ms(ticks, tempo, mid):148tick_ms = math.ceil((60000.0 / tempo) / mid.ticks_per_beat)149return ticks * tick_ms150151def mid2wav(file):152mid = MidiFile(file)153output = AudioSegment.silent(mid.length * 1000.0)154155tempo = 130 # bpm156157for track in mid.tracks:158# position of rendering in ms159current_pos = 0.0160current_notes = defaultdict(dict)161162for msg in track:163current_pos += ticks_to_ms(msg.time, tempo, mid)164if msg.type == 'note_on':165if msg.note in current_notes[msg.channel]:166current_notes[msg.channel][msg.note].append((current_pos, msg))167else:168current_notes[msg.channel][msg.note] = [(current_pos, msg)]169170171if msg.type == 'note_off':172start_pos, start_msg = current_notes[msg.channel][msg.note].pop()173174duration = math.ceil(current_pos - start_pos)175signal_generator = Sine(note_to_freq(msg.note, 500))176#print(duration)177rendered = signal_generator.to_audio_segment(duration=duration-50, volume=-20).fade_out(100).fade_in(30)178179output = output.overlay(rendered, start_pos)180181output.export("./output/rendered.wav", format="wav")182183