#main.py
import glob
import numpy as np
from music21 import *
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, LSTM, Activation
from tensorflow.keras.models import load_model
#extract all notes composed in songs
notes = []
for file in glob.glob("midi_songs/*.mid"):
midi = converter.parse(file)
notes_to_parse = None
parts = instrument.partitionByInstrument(midi)
if parts: # file has instrument parts
notes_to_parse = parts.parts[0].recurse()
else: # file has notes in a flat structure
notes_to_parse = midi.flat.notes
for element in notes_to_parse:
if isinstance(element, note.Note):
notes.append(str(element.pitch))
elif isinstance(element, chord.Chord):
notes.append('.'.join(str(n) for n in element.normalOrder))
#print(notes)
#'A3', 'C4', 'D3', 'F3', 'G4', 'A3', 'C4'
sequence_length = 100
# remove mulitplication of notes, sort
pitchnames = sorted(set(item for item in notes))
#print(pitchnames)
n_vocab = len(pitchnames)
# create a dictionary to map pitches to integers
note_to_int = dict((note, number) for number, note in enumerate(pitchnames))
int_to_note = dict((number, note) for number, note in enumerate(pitchnames))
#print(note_to_int)
#there are 308 different notes
network_input = []
network_output = []
#100 notes in succession produce the 101st note,
#slide 100 notes block through music to generate input array,
#gather cosresponding output to each input block to form output array
# create input sequences and the corresponding outputs
for i in range(0, len(notes) - sequence_length, 1):
sequence_in = notes[i:i + sequence_length]
sequence_out = notes[i + sequence_length]
network_input.append([note_to_int[char] for char in sequence_in])
network_output.append(note_to_int[sequence_out])
n_patterns = len(network_input)
# reshape the input into a format compatible with LSTM layers
network_input = np.reshape(network_input, (n_patterns, sequence_length, 1))
# normalize input
network_input = network_input / float(n_vocab)
network_output = tf.keras.utils.to_categorical(network_output)
#print(network_input)
#print(network_output)
#print(network_input.shape)
#(43990, 100, 1)
#print(network_output.shape)
#(43990, 308)
# train on GPU
pysical_devices = tf.config.experimental.list_physical_devices('GPU')
# print("Num GPUs Available: ", len(pysical_devices))
tf.config.experimental.set_memory_growth(pysical_devices[0], True)
"""
model = Sequential()
model.add(LSTM(
256,
input_shape=(network_input.shape[1], network_input.shape[2]),
return_sequences=True
))
model.add(Dropout(0.3))
model.add(LSTM(512, return_sequences=True))
model.add(Dropout(0.3))
model.add(LSTM(256))
model.add(Dense(256))
model.add(Dropout(0.3))
model.add(Dense(n_vocab))
model.add(Activation('softmax'))
model.summary()
model.compile(loss='categorical_crossentropy', optimizer='adam')
model.fit(network_input, network_output, epochs=200, batch_size=64)
model.save('model.h5')
"""
#start generating music
#pick random note block as a start
#start = np.random.randint(0, len(network_input)-1)
start = 40000
pattern = network_input[start]
prediction_output = []
model = load_model('model.h5')
# generate 500 notes, use 100 notes as start to generate 101st note
# then use 1-101 to generate 102...
for note_index in range(500):
prediction_input = np.reshape(pattern, (1, len(pattern), 1))
prediction_input = prediction_input / float(n_vocab)
prediction = model.predict(prediction_input, verbose=0)
index = np.argmax(prediction)
result = int_to_note[index]
prediction_output.append(result)
pattern = np.append(pattern, index)
pattern = pattern[1:len(pattern)]
#music 21 translates
offset = 0
output_notes = []
# create note and chord objects based on the values generated by the model
for pattern in prediction_output:
# pattern is a chord
if ('.' in pattern) or pattern.isdigit():
notes_in_chord = pattern.split('.')
notes = []
for current_note in notes_in_chord:
new_note = note.Note(int(current_note))
new_note.storedInstrument = instrument.Piano()
notes.append(new_note)
new_chord = chord.Chord(notes)
new_chord.offset = offset
output_notes.append(new_chord)
# pattern is a note
else:
new_note = note.Note(pattern)
new_note.offset = offset
new_note.storedInstrument = instrument.Piano()
output_notes.append(new_note)
# increase offset each iteration so that notes do not stack
offset += 0.5
midi_stream = stream.Stream(output_notes)
midi_stream.write('midi', fp='test_output.mid')
reference:
How to Upload Audio to YouTube
No comments:
Post a Comment