diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..02036bd3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +data/* +config.txt +history +results/* \ No newline at end of file diff --git a/README.md b/README.md index 338023d1..c027352c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,58 @@ # Composer -Generates video game music using neural networks. -https://youtu.be/UWxfnNXlVy8 +Generate tunable music using neural networks. + +Repository to ["Generating Songs With Neural Networks (Neural Composer)"](https://youtu.be/UWxfnNXlVy8). + +## How to install + +* Install dependencies in python3 by running `pip install -r requirements.txt`. + +## How to run + +* Find some dataset to train on. More info on where to find datasets can be found in data/raw/README.md. A default bach dataset is included in the repository. +* Run preprocess_songs.py. This will load all midi files from your midi files folder data/raw/ into data/interim/samples.npy & lengths.npy. + You can point the script to a location using the --data_folder flag one or multiple times to make it include more paths to index midi files. +* Run train.py. This will train your network and store the progress from time to time (EPOCHS_TO_SAVE to change storing frequency). + Only stops if you interrupt it or after 2000 epochs. +* Run composer.py --model_path "e300" where "e300" indicates the folder the stored model is in. Look into the results/history folder to find your trained model folders. + +## Composer + +The Composer script will load your model trained on the midi files you provided +into the music generator. +Internally, the model tries to compress a song into only 120 numbers called the latent space. +Seen from the other perspective, the latent space numbers encode each song that the model +is trained on. Changing the latent numbers allows us to sample new, unknown songs. +To make the sampling more efficient, we use PCA, a way to extract the dimensions in which there is +most variations across all songs, to make the influence on the new songs strong. +The sliders in the composer adjust those numbers and are ordered from most +important/influential (left) to least important/influential (right). Just the +top 40 are shown on screen. For more details about how +this works and other fun projects, please check out my +YouTube channel 'CodeParade'. Have fun making music! + +========================================================= +``` +Composer Controls: + Right Click - Reset all sliders + 'R' - Random Song + 'T' - Randomize off-screen sliders + 'M' - Save song as .mid file + 'W' - Save song as .wav file + 'S' - Save slider values to text file + 'Space' - Play/Pause + 'Tab' - Seek to start of song + '1' - Square wave instrument + '2' - Sawtooth wave instrument + '3' - Triangle wave instrument + '4' - Sine wave instrument +``` + +## Pretrained models + +Below are some pretrained models for different datasets. To use the model, download the zip from the +link below and extract it into the results/history folder of your project. The zip should contain a folder +named e and some number, indicating the number of epochs the model was trained and some model.h5. +Pay attention when extracting the model not to override one of your own trained, most beloved models! + +* Bach dataset: https://drive.google.com/open?id=1P_hOF0v55m1Snzvri5OBVP5yy099Lzgx diff --git a/composer.py b/composer.py new file mode 100644 index 00000000..4cd9f685 --- /dev/null +++ b/composer.py @@ -0,0 +1,542 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Neural composer: Play and edit music generated by the trained model. +""" + +import argparse +import math +import wave + +import numpy as np +import pyaudio +import pygame + +import midi_utils + +import keras +from keras.models import Model, load_model +from keras import backend as K + +# User constants +dir_name = 'results/history/' +sub_dir_name = 'e1/' +sample_rate = 48000 +note_dt = 2000 # num samples +note_duration = 20000 # num samples +note_decay = 5.0 / sample_rate +num_params = 120 +num_measures = 16 +num_sigmas = 5.0 +note_threshold = 32 +use_pca = True +is_ae = True + +# colors +background_color = (210, 210, 210) +edge_color = (60, 60, 60) +slider_colors = [(90, 20, 20), (90, 90, 20), (20, 90, 20), (20, 90, 90), (20, 20, 90), (90, 20, 90)] + +note_w = 96 +note_h = 96 +note_pad = 2 + +notes_rows = int(num_measures / 8) +notes_cols = 8 + +slider_num = min(40, num_params) +slider_h = 200 +slider_pad = 5 +tick_pad = 4 + +control_w = 210 +control_h = 30 +control_pad = 5 +control_num = 3 +control_colors = [(255, 0, 0), (0, 255, 0), (0, 0, 255)] +control_inits = [0.75, 0.5, 0.5] + +# derived constants +notes_w = notes_cols * (note_w + note_pad * 2) +notes_h = notes_rows * (note_h + note_pad * 2) +sliders_w = notes_w +sliders_h = slider_h + slider_pad * 2 +controls_w = control_w * control_num +controls_h = control_h +window_w = notes_w +window_h = notes_h + sliders_h + controls_h +slider_w = int((window_w - slider_pad * 2) / slider_num) +notes_x = 0 +notes_y = sliders_h +sliders_x = slider_pad +sliders_y = slider_pad +controls_x = int((window_w - controls_w) / 2) +controls_y = notes_h + sliders_h + +# global variables +prev_mouse_pos = None +mouse_pressed = 0 +cur_slider_ix = 0 +cur_control_ix = 0 +volume = 3000 +instrument = 0 +needs_update = True +current_params = np.zeros((num_params,), dtype=np.float32) +current_notes = np.zeros((num_measures, note_h, note_w), dtype=np.uint8) +cur_controls = np.array(control_inits, dtype=np.float32) +songs_loaded = False + +# setup audio stream +audio = pyaudio.PyAudio() +audio_notes = [] +audio_time = 0 +note_time = 0 +note_time_dt = 0 +audio_reset = False +audio_pause = False + + +def audio_callback(in_data, frame_count, time_info, status): + """ + Audio call-back to influence playback of music with input. + :param in_data: + :param frame_count: + :param time_info: + :param status: + :return: + """ + global audio_time + global audio_notes + global audio_reset + global note_time + global note_time_dt + + # check if needs restart + if audio_reset: + audio_notes = [] + audio_time = 0 + note_time = 0 + note_time_dt = 0 + audio_reset = False + + # check if paused + if audio_pause and status is not None: + data = np.zeros((frame_count,), dtype=np.float32) + return data.tobytes(), pyaudio.paContinue + + # find and add any notes in this time window + cur_dt = note_dt + while note_time_dt < audio_time + frame_count: + measure_ix = int(note_time / note_h) + if measure_ix >= num_measures: + break + note_ix = note_time % note_h + notes = np.where(current_notes[measure_ix, note_ix] >= note_threshold)[0] + for note in notes: + freq = 2 * 38.89 * pow(2.0, note / 12.0) / sample_rate + audio_notes.append((note_time_dt, freq)) + note_time += 1 + note_time_dt += cur_dt + + # generate the tones + data = np.zeros((frame_count,), dtype=np.float32) + for t, f in audio_notes: + x = np.arange(audio_time - t, audio_time + frame_count - t) + x = np.maximum(x, 0) + + if instrument == 0: + w = np.sign(1 - np.mod(x * f, 2)) # Square + elif instrument == 1: + w = np.mod(x * f - 1, 2) - 1 # Sawtooth + elif instrument == 2: + w = 2 * np.abs(np.mod(x * f - 0.5, 2) - 1) - 1 # Triangle + elif instrument == 3: + w = np.sin(x * f * math.pi) # Sine + + # w = np.floor(w*8)/8 + w[x == 0] = 0 + w *= volume * np.exp(-x * note_decay) + data += w + data = np.clip(data, -32000, 32000).astype(np.int16) + + # remove notes that are too old + audio_time += frame_count + audio_notes = [(t, f) for t, f in audio_notes if audio_time < t + note_duration] + + # reset if loop occurs + if note_time / note_h >= num_measures: + audio_time = 0 + note_time = 0 + note_time_dt = 0 + audio_notes = [] + + # return the sound clip + return data.tobytes(), pyaudio.paContinue + + +def update_mouse_click(mouse_pos): + """ + Update control stated based on where the mouse clicked. + :param mouse_pos: + :return: + """ + global cur_slider_ix + global cur_control_ix + global mouse_pressed + x = (mouse_pos[0] - sliders_x) + y = (mouse_pos[1] - sliders_y) + + if 0 <= x < sliders_w and 0 <= y < sliders_h: + cur_slider_ix = int(x / slider_w) + mouse_pressed = 1 + + x = (mouse_pos[0] - controls_x) + y = (mouse_pos[1] - controls_y) + if 0 <= x < controls_w and 0 <= y < controls_h: + cur_control_ix = int(x / control_w) + mouse_pressed = 2 + + +def apply_controls(): + """ + Change parameters based on controls. + :return: + """ + global note_threshold + global note_dt + global volume + + note_threshold = (1.0 - cur_controls[0]) * 200 + 10 + note_dt = (1.0 - cur_controls[1]) * 1800 + 200 + volume = cur_controls[2] * 6000 + + +def update_mouse_move(mouse_pos): + """ + Update sliders/controls based on mouse input. + :param mouse_pos: + :return: + """ + global needs_update + + if mouse_pressed == 1: + # change sliders + y = (mouse_pos[1] - sliders_y) + if 0 <= y <= slider_h: + val = (float(y) / slider_h - 0.5) * (num_sigmas * 2) + current_params[int(cur_slider_ix)] = val + needs_update = True + elif mouse_pressed == 2: + # change controls + x = (mouse_pos[0] - (controls_x + cur_control_ix * control_w)) + if control_pad <= x <= control_w - control_pad: + val = float(x - control_pad) / (control_w - control_pad * 2) + cur_controls[int(cur_control_ix)] = val + apply_controls() + + +def draw_controls(screen): + """ + Draw volume and threshold controls to screen. + :param screen: + :return: + """ + for i in range(control_num): + x = controls_x + i * control_w + control_pad + y = controls_y + control_pad + w = control_w - control_pad * 2 + h = control_h - control_pad * 2 + col = control_colors[i] + + pygame.draw.rect(screen, col, (x, y, int(w * cur_controls[i]), h)) + pygame.draw.rect(screen, (0, 0, 0), (x, y, w, h), 1) + + +def draw_sliders(screen): + """ + Draw sliders to screen. + :param screen: + :return: + """ + for i in range(slider_num): + slider_color = slider_colors[i % len(slider_colors)] + x = sliders_x + i * slider_w + y = sliders_y + + cx = x + slider_w / 2 + cy_1 = y + cy_2 = y + slider_h + pygame.draw.line(screen, slider_color, (cx, cy_1), (cx, cy_2)) + + cx_1 = x + tick_pad + cx_2 = x + slider_w - tick_pad + for j in range(int(num_sigmas * 2 + 1)): + ly = y + slider_h / 2.0 + (j - num_sigmas) * slider_h / (num_sigmas * 2.0) + ly = int(ly) + col = (0, 0, 0) if j - num_sigmas == 0 else slider_color + pygame.draw.line(screen, col, (cx_1, ly), (cx_2, ly)) + + py = y + int((current_params[i] / (num_sigmas * 2) + 0.5) * slider_h) + pygame.draw.circle(screen, slider_color, (int(cx), int(py)), int((slider_w - tick_pad) / 2)) + + +def get_pianoroll_from_notes(notes): + """ + Draw piano roll of notes. + :param notes: + :return: + """ + + output = np.full((3, int(notes_h), int(notes_w)), 64, dtype=np.uint8) + + for i in range(notes_rows): + for j in range(notes_cols): + x = note_pad + j * (note_w + note_pad * 2) + y = note_pad + i * (note_h + note_pad * 2) + ix = i * notes_cols + j + + measure = np.rot90(notes[ix]) + played_only = np.where(measure >= note_threshold, 255, 0) + output[0, y:y + note_h, x:x + note_w] = np.minimum(measure * (255.0 / note_threshold), 255.0) + output[1, y:y + note_h, x:x + note_w] = played_only + output[2, y:y + note_h, x:x + note_w] = played_only + + return np.transpose(output, (2, 1, 0)) + + +def draw_notes(screen, notes_surface): + """ + Draw pianoroll notes to screen. + :param screen: + :param notes_surface: + :return: + """ + + pygame.surfarray.blit_array(notes_surface, get_pianoroll_from_notes(current_notes)) + + measure_ix = int(note_time / note_h) + note_ix = note_time % note_h + x = notes_x + note_pad + (measure_ix % notes_cols) * (note_w + note_pad * 2) + note_ix + y = notes_y + note_pad + int(measure_ix / notes_cols) * (note_h + note_pad * 2) + + pygame.draw.rect(screen, (255, 255, 0), (x, y, 4, note_h), 0) + + +def play(): + global mouse_pressed + global current_notes + global audio_pause + global needs_update + global current_params + global prev_mouse_pos + global audio_reset + global instrument + global songs_loaded + + print("Keras version: " + keras.__version__) + + K.set_image_data_format('channels_first') + + print("Loading encoder...") + model = load_model(dir_name + 'model.h5') + encoder = Model(inputs=model.input, outputs=model.get_layer('encoder').output) + decoder = K.function([model.get_layer('decoder').input, K.learning_phase()], + [model.layers[-1].output]) + + print("Loading gaussian/pca statistics...") + latent_means = np.load(dir_name + sub_dir_name + '/latent_means.npy') + latent_stds = np.load(dir_name + sub_dir_name + '/latent_stds.npy') + latent_pca_values = np.load(dir_name + sub_dir_name + '/latent_pca_values.npy') + latent_pca_vectors = np.load(dir_name + sub_dir_name + '/latent_pca_vectors.npy') + + # open a window + pygame.init() + pygame.font.init() + screen = pygame.display.set_mode((int(window_w), int(window_h))) + notes_surface = screen.subsurface((notes_x, notes_y, notes_w, notes_h)) + pygame.display.set_caption('Neural Composer') + + # start the audio stream + audio_stream = audio.open( + format=audio.get_format_from_width(2), + channels=1, + rate=sample_rate, + output=True, + stream_callback=audio_callback) + audio_stream.start_stream() + + # main loop + running = True + random_song_ix = 0 + cur_len = 0 + apply_controls() + while running: + # process events + for event in pygame.event.get(): + if event.type == pygame.QUIT: # QUIT BUTTON HIT + running = False + break + + elif event.type == pygame.MOUSEBUTTONDOWN: # MOUSE BUTTON DOWN + if pygame.mouse.get_pressed()[0]: + prev_mouse_pos = pygame.mouse.get_pos() + update_mouse_click(prev_mouse_pos) + update_mouse_move(prev_mouse_pos) + elif pygame.mouse.get_pressed()[2]: + current_params = np.zeros((num_params,), dtype=np.float32) + needs_update = True + + elif event.type == pygame.MOUSEBUTTONUP: # MOUSE BUTTON UP + mouse_pressed = 0 + prev_mouse_pos = None + + elif event.type == pygame.MOUSEMOTION and mouse_pressed > 0: # MOUSE MOTION WHILE PRESSED + update_mouse_move(pygame.mouse.get_pos()) + + elif event.type == pygame.KEYDOWN: + if event.key == pygame.K_r: # KEYDOWN R + # generate random song + current_params = np.clip(np.random.normal(0.0, 1.0, (num_params,)), -num_sigmas, num_sigmas) + needs_update = True + audio_reset = True + + if event.key == pygame.K_e: # KEYDOWN E + # generate random song with larger variance + current_params = np.clip(np.random.normal(0.0, 2.0, (num_params,)), -num_sigmas, num_sigmas) + needs_update = True + audio_reset = True + + if event.key == pygame.K_o: # KEYDOWN O + + if not songs_loaded: + print("Loading songs...") + try: + y_samples = np.load('data/interim/samples.npy') + y_lengths = np.load('data/interim/lengths.npy') + songs_loaded = True + except Exception as e: + print("This functionality is to check if the model training went well by reproducing an original song. " + "The composer could not load samples and lengths from model training. " + "If you have the midi files, the model was trained with, process them by using" + " the preprocess_songs.py to find the requested files in data/interim " + "(Load exception: {0}".format(e)) + + if songs_loaded: + # check how well the autoencoder can reconstruct a random song + print("Random Song Index: " + str(random_song_ix)) + if is_ae: + example_song = y_samples[cur_len:cur_len + num_measures] + current_notes = example_song * 255 + latent_x = encoder.predict(np.expand_dims(example_song, 0), batch_size=1)[0] + cur_len += y_lengths[random_song_ix] + random_song_ix += 1 + else: + random_song_ix = np.array([random_song_ix], dtype=np.int64) + latent_x = encoder.predict(random_song_ix, batch_size=1)[0] + random_song_ix = (random_song_ix + 1) % model.layers[0].input_dim + + if use_pca: + current_params = np.dot(latent_x - latent_means, latent_pca_vectors.T) / latent_pca_values + else: + current_params = (latent_x - latent_means) / latent_stds + + needs_update = True + audio_reset = True + + if event.key == pygame.K_m: # KEYDOWN M + # save song as midi + audio_pause = True + audio_reset = True + midi_utils.samples_to_midi(current_notes, 'results/live.mid', note_threshold) + audio_pause = False + + if event.key == pygame.K_w: # KEYDOWN W + # save song as wave + audio_pause = True + audio_reset = True + save_audio = b'' + while True: + save_audio += audio_callback(None, 1024, None, None)[0] + if audio_time == 0: + break + wave_output = wave.open('results/live.wav', 'w') + wave_output.setparams((1, 2, sample_rate, 0, 'NONE', 'not compressed')) + wave_output.writeframes(save_audio) + wave_output.close() + audio_pause = False + + if event.key == pygame.K_ESCAPE: # KEYDOWN ESCAPE + # exit application + running = False + break + + if event.key == pygame.K_SPACE: # KEYDOWN SPACE + # toggle pause/play audio + audio_pause = not audio_pause + + if event.key == pygame.K_TAB: # KEYDOWN TAB + # reset audio playing + audio_reset = True + + if event.key == pygame.K_1: # KEYDOWN 1 + # play instrument 0 + instrument = 0 + + if event.key == pygame.K_2: # KEYDOWN 2 + # play instrument 1 + instrument = 1 + + if event.key == pygame.K_3: # KEYDOWN 3 + # play instrument 2 + instrument = 2 + + if event.key == pygame.K_4: # KEYDOWN 4 + # play instrument 3 + instrument = 3 + + if event.key == pygame.K_c: # KEYDOWN C + # + y = np.expand_dims(np.where(current_notes > note_threshold, 1, 0), 0) + latent_x = encoder.predict(y)[0] + if use_pca: + current_params = np.dot(latent_x - latent_means, latent_pca_vectors.T) / latent_pca_values + else: + current_params = (latent_x - latent_means) / latent_stds + needs_update = True + + # check if params were changed so that a new song should be generated + if needs_update: + if use_pca: + latent_x = latent_means + np.dot(current_params * latent_pca_values, latent_pca_vectors) + else: + latent_x = latent_means + latent_stds * current_params + latent_x = np.expand_dims(latent_x, axis=0) + y = decoder([latent_x, 0])[0][0] + current_notes = (y * 255.0).astype(np.uint8) + needs_update = False + + # draw GUI to the screen + screen.fill(background_color) + draw_notes(screen, notes_surface) + draw_sliders(screen) + draw_controls(screen) + + # flip the screen buffer + pygame.display.flip() + pygame.time.wait(10) + + # if app is exited, close the audio stream + audio_stream.stop_stream() + audio_stream.close() + audio.terminate() + + +if __name__ == "__main__": + # configure parser and parse arguments + parser = argparse.ArgumentParser(description='Neural Composer: Play and edit music of a trained model.') + parser.add_argument('--model_path', type=str, help='The folder the model is stored in (e.g. a folder named e and a number located in results/history/).', required=True) + + args = parser.parse_args() + sub_dir_name = args.model_path + play() diff --git a/cpu.theanorc b/cpu.theanorc deleted file mode 100644 index 57841b4c..00000000 --- a/cpu.theanorc +++ /dev/null @@ -1,3 +0,0 @@ -[global] -floatX=float32 -device=cpu diff --git a/data/interim/.gitkeep b/data/interim/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/data/raw/README.md b/data/raw/README.md new file mode 100644 index 00000000..15d5f7f1 --- /dev/null +++ b/data/raw/README.md @@ -0,0 +1,11 @@ +How to get some midi data +------------------------- + +Get some midi files of music you are interested in to work with. + +Examples are: +* https://github.com/FlorianColombo/BachProp/tree/master/data (Bach midi files) +* https://mega.nz/#!Elg1TA7T!MXEZPzq9s9YObiUcMCoNQJmCbawZqzAkHzY4Ym6Gs_Q (Large pack of all genres of midi files) +* https://www.vgmusic.com/ (Scrape midi files from here) + +Place the midi files in this folder or any subfolder to use them as the training set. \ No newline at end of file diff --git a/data/raw/bach/bwv10.7.mid b/data/raw/bach/bwv10.7.mid new file mode 100644 index 00000000..3a9b5b44 Binary files /dev/null and b/data/raw/bach/bwv10.7.mid differ diff --git a/data/raw/bach/bwv101.7.mid b/data/raw/bach/bwv101.7.mid new file mode 100644 index 00000000..0f38a083 Binary files /dev/null and b/data/raw/bach/bwv101.7.mid differ diff --git a/data/raw/bach/bwv102.7.mid b/data/raw/bach/bwv102.7.mid new file mode 100644 index 00000000..4b31ecc8 Binary files /dev/null and b/data/raw/bach/bwv102.7.mid differ diff --git a/data/raw/bach/bwv103.6.mid b/data/raw/bach/bwv103.6.mid new file mode 100644 index 00000000..3503731b Binary files /dev/null and b/data/raw/bach/bwv103.6.mid differ diff --git a/data/raw/bach/bwv104.6.mid b/data/raw/bach/bwv104.6.mid new file mode 100644 index 00000000..2aa74f7f Binary files /dev/null and b/data/raw/bach/bwv104.6.mid differ diff --git a/data/raw/bach/bwv108.6.mid b/data/raw/bach/bwv108.6.mid new file mode 100644 index 00000000..20c50aea Binary files /dev/null and b/data/raw/bach/bwv108.6.mid differ diff --git a/data/raw/bach/bwv11.6.mid b/data/raw/bach/bwv11.6.mid new file mode 100644 index 00000000..abcad137 Binary files /dev/null and b/data/raw/bach/bwv11.6.mid differ diff --git a/data/raw/bach/bwv110.7.mid b/data/raw/bach/bwv110.7.mid new file mode 100644 index 00000000..53e707cc Binary files /dev/null and b/data/raw/bach/bwv110.7.mid differ diff --git a/data/raw/bach/bwv111.6.mid b/data/raw/bach/bwv111.6.mid new file mode 100644 index 00000000..13f7c771 Binary files /dev/null and b/data/raw/bach/bwv111.6.mid differ diff --git a/data/raw/bach/bwv112.5.mid b/data/raw/bach/bwv112.5.mid new file mode 100644 index 00000000..15dc20db Binary files /dev/null and b/data/raw/bach/bwv112.5.mid differ diff --git a/data/raw/bach/bwv113.8.mid b/data/raw/bach/bwv113.8.mid new file mode 100644 index 00000000..46341f08 Binary files /dev/null and b/data/raw/bach/bwv113.8.mid differ diff --git a/data/raw/bach/bwv114.7.mid b/data/raw/bach/bwv114.7.mid new file mode 100644 index 00000000..3dc190e2 Binary files /dev/null and b/data/raw/bach/bwv114.7.mid differ diff --git a/data/raw/bach/bwv115.6.mid b/data/raw/bach/bwv115.6.mid new file mode 100644 index 00000000..ea926d43 Binary files /dev/null and b/data/raw/bach/bwv115.6.mid differ diff --git a/data/raw/bach/bwv116.6.mid b/data/raw/bach/bwv116.6.mid new file mode 100644 index 00000000..e5254815 Binary files /dev/null and b/data/raw/bach/bwv116.6.mid differ diff --git a/data/raw/bach/bwv117.4.mid b/data/raw/bach/bwv117.4.mid new file mode 100644 index 00000000..59e3ae72 Binary files /dev/null and b/data/raw/bach/bwv117.4.mid differ diff --git a/data/raw/bach/bwv119.9.mid b/data/raw/bach/bwv119.9.mid new file mode 100644 index 00000000..644cc400 Binary files /dev/null and b/data/raw/bach/bwv119.9.mid differ diff --git a/data/raw/bach/bwv120.6.mid b/data/raw/bach/bwv120.6.mid new file mode 100644 index 00000000..0411c23d Binary files /dev/null and b/data/raw/bach/bwv120.6.mid differ diff --git a/data/raw/bach/bwv121.6.mid b/data/raw/bach/bwv121.6.mid new file mode 100644 index 00000000..f7d4220f Binary files /dev/null and b/data/raw/bach/bwv121.6.mid differ diff --git a/data/raw/bach/bwv122.6.mid b/data/raw/bach/bwv122.6.mid new file mode 100644 index 00000000..9192b246 Binary files /dev/null and b/data/raw/bach/bwv122.6.mid differ diff --git a/data/raw/bach/bwv123.6.mid b/data/raw/bach/bwv123.6.mid new file mode 100644 index 00000000..dcc0241e Binary files /dev/null and b/data/raw/bach/bwv123.6.mid differ diff --git a/data/raw/bach/bwv125.6.mid b/data/raw/bach/bwv125.6.mid new file mode 100644 index 00000000..2e660b60 Binary files /dev/null and b/data/raw/bach/bwv125.6.mid differ diff --git a/data/raw/bach/bwv126.6.mid b/data/raw/bach/bwv126.6.mid new file mode 100644 index 00000000..0281d6aa Binary files /dev/null and b/data/raw/bach/bwv126.6.mid differ diff --git a/data/raw/bach/bwv127.5.mid b/data/raw/bach/bwv127.5.mid new file mode 100644 index 00000000..6f73b789 Binary files /dev/null and b/data/raw/bach/bwv127.5.mid differ diff --git a/data/raw/bach/bwv13.6.mid b/data/raw/bach/bwv13.6.mid new file mode 100644 index 00000000..9886b436 Binary files /dev/null and b/data/raw/bach/bwv13.6.mid differ diff --git a/data/raw/bach/bwv133.6.mid b/data/raw/bach/bwv133.6.mid new file mode 100644 index 00000000..2c33e849 Binary files /dev/null and b/data/raw/bach/bwv133.6.mid differ diff --git a/data/raw/bach/bwv135.6.mid b/data/raw/bach/bwv135.6.mid new file mode 100644 index 00000000..94cff9d8 Binary files /dev/null and b/data/raw/bach/bwv135.6.mid differ diff --git a/data/raw/bach/bwv139.6.mid b/data/raw/bach/bwv139.6.mid new file mode 100644 index 00000000..9d9e592d Binary files /dev/null and b/data/raw/bach/bwv139.6.mid differ diff --git a/data/raw/bach/bwv14.5.mid b/data/raw/bach/bwv14.5.mid new file mode 100644 index 00000000..6077627c Binary files /dev/null and b/data/raw/bach/bwv14.5.mid differ diff --git a/data/raw/bach/bwv140.7.mid b/data/raw/bach/bwv140.7.mid new file mode 100644 index 00000000..a7ca236c Binary files /dev/null and b/data/raw/bach/bwv140.7.mid differ diff --git a/data/raw/bach/bwv144.3.mid b/data/raw/bach/bwv144.3.mid new file mode 100644 index 00000000..c5f15e78 Binary files /dev/null and b/data/raw/bach/bwv144.3.mid differ diff --git a/data/raw/bach/bwv144.6.mid b/data/raw/bach/bwv144.6.mid new file mode 100644 index 00000000..930f3a36 Binary files /dev/null and b/data/raw/bach/bwv144.6.mid differ diff --git a/data/raw/bach/bwv145-a.mid b/data/raw/bach/bwv145-a.mid new file mode 100644 index 00000000..56fbb6b7 Binary files /dev/null and b/data/raw/bach/bwv145-a.mid differ diff --git a/data/raw/bach/bwv145.5.mid b/data/raw/bach/bwv145.5.mid new file mode 100644 index 00000000..b8acedb2 Binary files /dev/null and b/data/raw/bach/bwv145.5.mid differ diff --git a/data/raw/bach/bwv146.8.mid b/data/raw/bach/bwv146.8.mid new file mode 100644 index 00000000..704e1be9 Binary files /dev/null and b/data/raw/bach/bwv146.8.mid differ diff --git a/data/raw/bach/bwv148.6.mid b/data/raw/bach/bwv148.6.mid new file mode 100644 index 00000000..ea691753 Binary files /dev/null and b/data/raw/bach/bwv148.6.mid differ diff --git a/data/raw/bach/bwv151.5.mid b/data/raw/bach/bwv151.5.mid new file mode 100644 index 00000000..b848d277 Binary files /dev/null and b/data/raw/bach/bwv151.5.mid differ diff --git a/data/raw/bach/bwv153.1.mid b/data/raw/bach/bwv153.1.mid new file mode 100644 index 00000000..d94d0686 Binary files /dev/null and b/data/raw/bach/bwv153.1.mid differ diff --git a/data/raw/bach/bwv153.5.mid b/data/raw/bach/bwv153.5.mid new file mode 100644 index 00000000..a5cf8603 Binary files /dev/null and b/data/raw/bach/bwv153.5.mid differ diff --git a/data/raw/bach/bwv153.9.mid b/data/raw/bach/bwv153.9.mid new file mode 100644 index 00000000..b75a0887 Binary files /dev/null and b/data/raw/bach/bwv153.9.mid differ diff --git a/data/raw/bach/bwv154.3.mid b/data/raw/bach/bwv154.3.mid new file mode 100644 index 00000000..154f0763 Binary files /dev/null and b/data/raw/bach/bwv154.3.mid differ diff --git a/data/raw/bach/bwv154.8.mid b/data/raw/bach/bwv154.8.mid new file mode 100644 index 00000000..99289a76 Binary files /dev/null and b/data/raw/bach/bwv154.8.mid differ diff --git a/data/raw/bach/bwv155.5.mid b/data/raw/bach/bwv155.5.mid new file mode 100644 index 00000000..85fb6599 Binary files /dev/null and b/data/raw/bach/bwv155.5.mid differ diff --git a/data/raw/bach/bwv156.6.mid b/data/raw/bach/bwv156.6.mid new file mode 100644 index 00000000..4ae3e386 Binary files /dev/null and b/data/raw/bach/bwv156.6.mid differ diff --git a/data/raw/bach/bwv157.5.mid b/data/raw/bach/bwv157.5.mid new file mode 100644 index 00000000..d9df2de5 Binary files /dev/null and b/data/raw/bach/bwv157.5.mid differ diff --git a/data/raw/bach/bwv158.4.mid b/data/raw/bach/bwv158.4.mid new file mode 100644 index 00000000..c33737c0 Binary files /dev/null and b/data/raw/bach/bwv158.4.mid differ diff --git a/data/raw/bach/bwv159.5.mid b/data/raw/bach/bwv159.5.mid new file mode 100644 index 00000000..d3e73d8c Binary files /dev/null and b/data/raw/bach/bwv159.5.mid differ diff --git a/data/raw/bach/bwv16.6.mid b/data/raw/bach/bwv16.6.mid new file mode 100644 index 00000000..85564d3c Binary files /dev/null and b/data/raw/bach/bwv16.6.mid differ diff --git a/data/raw/bach/bwv162.6-lpz.mid b/data/raw/bach/bwv162.6-lpz.mid new file mode 100644 index 00000000..2ca311a2 Binary files /dev/null and b/data/raw/bach/bwv162.6-lpz.mid differ diff --git a/data/raw/bach/bwv164.6.mid b/data/raw/bach/bwv164.6.mid new file mode 100644 index 00000000..c3a1c683 Binary files /dev/null and b/data/raw/bach/bwv164.6.mid differ diff --git a/data/raw/bach/bwv165.6.mid b/data/raw/bach/bwv165.6.mid new file mode 100644 index 00000000..0bce2ff7 Binary files /dev/null and b/data/raw/bach/bwv165.6.mid differ diff --git a/data/raw/bach/bwv166.6.mid b/data/raw/bach/bwv166.6.mid new file mode 100644 index 00000000..d48941c7 Binary files /dev/null and b/data/raw/bach/bwv166.6.mid differ diff --git a/data/raw/bach/bwv168.6.mid b/data/raw/bach/bwv168.6.mid new file mode 100644 index 00000000..cf47310f Binary files /dev/null and b/data/raw/bach/bwv168.6.mid differ diff --git a/data/raw/bach/bwv169.7.mid b/data/raw/bach/bwv169.7.mid new file mode 100644 index 00000000..f3ae9db0 Binary files /dev/null and b/data/raw/bach/bwv169.7.mid differ diff --git a/data/raw/bach/bwv17.7.mid b/data/raw/bach/bwv17.7.mid new file mode 100644 index 00000000..81c8bdcf Binary files /dev/null and b/data/raw/bach/bwv17.7.mid differ diff --git a/data/raw/bach/bwv174.5.mid b/data/raw/bach/bwv174.5.mid new file mode 100644 index 00000000..9edf3a20 Binary files /dev/null and b/data/raw/bach/bwv174.5.mid differ diff --git a/data/raw/bach/bwv176.6.mid b/data/raw/bach/bwv176.6.mid new file mode 100644 index 00000000..8f11c26f Binary files /dev/null and b/data/raw/bach/bwv176.6.mid differ diff --git a/data/raw/bach/bwv177.5.mid b/data/raw/bach/bwv177.5.mid new file mode 100644 index 00000000..6efae73d Binary files /dev/null and b/data/raw/bach/bwv177.5.mid differ diff --git a/data/raw/bach/bwv178.7.mid b/data/raw/bach/bwv178.7.mid new file mode 100644 index 00000000..1509e177 Binary files /dev/null and b/data/raw/bach/bwv178.7.mid differ diff --git a/data/raw/bach/bwv179.6.mid b/data/raw/bach/bwv179.6.mid new file mode 100644 index 00000000..c1e23c92 Binary files /dev/null and b/data/raw/bach/bwv179.6.mid differ diff --git a/data/raw/bach/bwv18.5-lz.mid b/data/raw/bach/bwv18.5-lz.mid new file mode 100644 index 00000000..e49705e9 Binary files /dev/null and b/data/raw/bach/bwv18.5-lz.mid differ diff --git a/data/raw/bach/bwv18.5-w.mid b/data/raw/bach/bwv18.5-w.mid new file mode 100644 index 00000000..f7edf620 Binary files /dev/null and b/data/raw/bach/bwv18.5-w.mid differ diff --git a/data/raw/bach/bwv180.7.mid b/data/raw/bach/bwv180.7.mid new file mode 100644 index 00000000..f0b369ed Binary files /dev/null and b/data/raw/bach/bwv180.7.mid differ diff --git a/data/raw/bach/bwv183.5.mid b/data/raw/bach/bwv183.5.mid new file mode 100644 index 00000000..df7872c0 Binary files /dev/null and b/data/raw/bach/bwv183.5.mid differ diff --git a/data/raw/bach/bwv184.5.mid b/data/raw/bach/bwv184.5.mid new file mode 100644 index 00000000..1536f874 Binary files /dev/null and b/data/raw/bach/bwv184.5.mid differ diff --git a/data/raw/bach/bwv187.7.mid b/data/raw/bach/bwv187.7.mid new file mode 100644 index 00000000..2c7f79b8 Binary files /dev/null and b/data/raw/bach/bwv187.7.mid differ diff --git a/data/raw/bach/bwv188.6.mid b/data/raw/bach/bwv188.6.mid new file mode 100644 index 00000000..d08d4fa7 Binary files /dev/null and b/data/raw/bach/bwv188.6.mid differ diff --git a/data/raw/bach/bwv190.7.mid b/data/raw/bach/bwv190.7.mid new file mode 100644 index 00000000..d9c942ce Binary files /dev/null and b/data/raw/bach/bwv190.7.mid differ diff --git a/data/raw/bach/bwv194.12.mid b/data/raw/bach/bwv194.12.mid new file mode 100644 index 00000000..0ff2fe21 Binary files /dev/null and b/data/raw/bach/bwv194.12.mid differ diff --git a/data/raw/bach/bwv194.6.mid b/data/raw/bach/bwv194.6.mid new file mode 100644 index 00000000..d0d1ffa9 Binary files /dev/null and b/data/raw/bach/bwv194.6.mid differ diff --git a/data/raw/bach/bwv197.10.mid b/data/raw/bach/bwv197.10.mid new file mode 100644 index 00000000..3c79af82 Binary files /dev/null and b/data/raw/bach/bwv197.10.mid differ diff --git a/data/raw/bach/bwv197.5.mid b/data/raw/bach/bwv197.5.mid new file mode 100644 index 00000000..a3094cd3 Binary files /dev/null and b/data/raw/bach/bwv197.5.mid differ diff --git a/data/raw/bach/bwv197.7-a.mid b/data/raw/bach/bwv197.7-a.mid new file mode 100644 index 00000000..7813a566 Binary files /dev/null and b/data/raw/bach/bwv197.7-a.mid differ diff --git a/data/raw/bach/bwv2.6.mid b/data/raw/bach/bwv2.6.mid new file mode 100644 index 00000000..3a897157 Binary files /dev/null and b/data/raw/bach/bwv2.6.mid differ diff --git a/data/raw/bach/bwv20.11.mid b/data/raw/bach/bwv20.11.mid new file mode 100644 index 00000000..24c0fe28 Binary files /dev/null and b/data/raw/bach/bwv20.11.mid differ diff --git a/data/raw/bach/bwv20.7.mid b/data/raw/bach/bwv20.7.mid new file mode 100644 index 00000000..24c0fe28 Binary files /dev/null and b/data/raw/bach/bwv20.7.mid differ diff --git a/data/raw/bach/bwv226.2.mid b/data/raw/bach/bwv226.2.mid new file mode 100644 index 00000000..e923e712 Binary files /dev/null and b/data/raw/bach/bwv226.2.mid differ diff --git a/data/raw/bach/bwv227.1.mid b/data/raw/bach/bwv227.1.mid new file mode 100644 index 00000000..6b596fef Binary files /dev/null and b/data/raw/bach/bwv227.1.mid differ diff --git a/data/raw/bach/bwv227.11.mid b/data/raw/bach/bwv227.11.mid new file mode 100644 index 00000000..52e3122e Binary files /dev/null and b/data/raw/bach/bwv227.11.mid differ diff --git a/data/raw/bach/bwv227.7.mid b/data/raw/bach/bwv227.7.mid new file mode 100644 index 00000000..54bf4e96 Binary files /dev/null and b/data/raw/bach/bwv227.7.mid differ diff --git a/data/raw/bach/bwv229.2.mid b/data/raw/bach/bwv229.2.mid new file mode 100644 index 00000000..17ffe04e Binary files /dev/null and b/data/raw/bach/bwv229.2.mid differ diff --git a/data/raw/bach/bwv244.10.mid b/data/raw/bach/bwv244.10.mid new file mode 100644 index 00000000..7ee5b640 Binary files /dev/null and b/data/raw/bach/bwv244.10.mid differ diff --git a/data/raw/bach/bwv244.15.mid b/data/raw/bach/bwv244.15.mid new file mode 100644 index 00000000..98716c1b Binary files /dev/null and b/data/raw/bach/bwv244.15.mid differ diff --git a/data/raw/bach/bwv244.17.mid b/data/raw/bach/bwv244.17.mid new file mode 100644 index 00000000..d76f6945 Binary files /dev/null and b/data/raw/bach/bwv244.17.mid differ diff --git a/data/raw/bach/bwv244.25.mid b/data/raw/bach/bwv244.25.mid new file mode 100644 index 00000000..d386b912 Binary files /dev/null and b/data/raw/bach/bwv244.25.mid differ diff --git a/data/raw/bach/bwv244.29-a.mid b/data/raw/bach/bwv244.29-a.mid new file mode 100644 index 00000000..4835e768 Binary files /dev/null and b/data/raw/bach/bwv244.29-a.mid differ diff --git a/data/raw/bach/bwv244.3.mid b/data/raw/bach/bwv244.3.mid new file mode 100644 index 00000000..14653517 Binary files /dev/null and b/data/raw/bach/bwv244.3.mid differ diff --git a/data/raw/bach/bwv244.32.mid b/data/raw/bach/bwv244.32.mid new file mode 100644 index 00000000..86b2f7f9 Binary files /dev/null and b/data/raw/bach/bwv244.32.mid differ diff --git a/data/raw/bach/bwv244.37.mid b/data/raw/bach/bwv244.37.mid new file mode 100644 index 00000000..ca88468e Binary files /dev/null and b/data/raw/bach/bwv244.37.mid differ diff --git a/data/raw/bach/bwv244.40.mid b/data/raw/bach/bwv244.40.mid new file mode 100644 index 00000000..0d010e54 Binary files /dev/null and b/data/raw/bach/bwv244.40.mid differ diff --git a/data/raw/bach/bwv244.44.mid b/data/raw/bach/bwv244.44.mid new file mode 100644 index 00000000..619bef3a Binary files /dev/null and b/data/raw/bach/bwv244.44.mid differ diff --git a/data/raw/bach/bwv244.46.mid b/data/raw/bach/bwv244.46.mid new file mode 100644 index 00000000..aa25b7a0 Binary files /dev/null and b/data/raw/bach/bwv244.46.mid differ diff --git a/data/raw/bach/bwv244.54.mid b/data/raw/bach/bwv244.54.mid new file mode 100644 index 00000000..03ed0efb Binary files /dev/null and b/data/raw/bach/bwv244.54.mid differ diff --git a/data/raw/bach/bwv244.62.mid b/data/raw/bach/bwv244.62.mid new file mode 100644 index 00000000..5fae1572 Binary files /dev/null and b/data/raw/bach/bwv244.62.mid differ diff --git a/data/raw/bach/bwv245.11.mid b/data/raw/bach/bwv245.11.mid new file mode 100644 index 00000000..e0ebf167 Binary files /dev/null and b/data/raw/bach/bwv245.11.mid differ diff --git a/data/raw/bach/bwv245.14.mid b/data/raw/bach/bwv245.14.mid new file mode 100644 index 00000000..359fe0e8 Binary files /dev/null and b/data/raw/bach/bwv245.14.mid differ diff --git a/data/raw/bach/bwv245.15.mid b/data/raw/bach/bwv245.15.mid new file mode 100644 index 00000000..f9ebda25 Binary files /dev/null and b/data/raw/bach/bwv245.15.mid differ diff --git a/data/raw/bach/bwv245.17.mid b/data/raw/bach/bwv245.17.mid new file mode 100644 index 00000000..b633a0d1 Binary files /dev/null and b/data/raw/bach/bwv245.17.mid differ diff --git a/data/raw/bach/bwv245.22.mid b/data/raw/bach/bwv245.22.mid new file mode 100644 index 00000000..14f707a0 Binary files /dev/null and b/data/raw/bach/bwv245.22.mid differ diff --git a/data/raw/bach/bwv245.26.mid b/data/raw/bach/bwv245.26.mid new file mode 100644 index 00000000..5c3d4454 Binary files /dev/null and b/data/raw/bach/bwv245.26.mid differ diff --git a/data/raw/bach/bwv245.28.mid b/data/raw/bach/bwv245.28.mid new file mode 100644 index 00000000..e9aef43f Binary files /dev/null and b/data/raw/bach/bwv245.28.mid differ diff --git a/data/raw/bach/bwv245.3.mid b/data/raw/bach/bwv245.3.mid new file mode 100644 index 00000000..b6588cbe Binary files /dev/null and b/data/raw/bach/bwv245.3.mid differ diff --git a/data/raw/bach/bwv245.37.mid b/data/raw/bach/bwv245.37.mid new file mode 100644 index 00000000..8241e0e1 Binary files /dev/null and b/data/raw/bach/bwv245.37.mid differ diff --git a/data/raw/bach/bwv245.40.mid b/data/raw/bach/bwv245.40.mid new file mode 100644 index 00000000..31bbe3ea Binary files /dev/null and b/data/raw/bach/bwv245.40.mid differ diff --git a/data/raw/bach/bwv245.5.mid b/data/raw/bach/bwv245.5.mid new file mode 100644 index 00000000..19d7b625 Binary files /dev/null and b/data/raw/bach/bwv245.5.mid differ diff --git a/data/raw/bach/bwv248.12-2.mid b/data/raw/bach/bwv248.12-2.mid new file mode 100644 index 00000000..6b1ae15e Binary files /dev/null and b/data/raw/bach/bwv248.12-2.mid differ diff --git a/data/raw/bach/bwv248.23-s.mid b/data/raw/bach/bwv248.23-s.mid new file mode 100644 index 00000000..66f10936 Binary files /dev/null and b/data/raw/bach/bwv248.23-s.mid differ diff --git a/data/raw/bach/bwv248.28.mid b/data/raw/bach/bwv248.28.mid new file mode 100644 index 00000000..fdbb4b06 Binary files /dev/null and b/data/raw/bach/bwv248.28.mid differ diff --git a/data/raw/bach/bwv248.33-3.mid b/data/raw/bach/bwv248.33-3.mid new file mode 100644 index 00000000..a03912c1 Binary files /dev/null and b/data/raw/bach/bwv248.33-3.mid differ diff --git a/data/raw/bach/bwv248.35-3.mid b/data/raw/bach/bwv248.35-3.mid new file mode 100644 index 00000000..5a6aea5c Binary files /dev/null and b/data/raw/bach/bwv248.35-3.mid differ diff --git a/data/raw/bach/bwv248.42-s.mid b/data/raw/bach/bwv248.42-s.mid new file mode 100644 index 00000000..96c54bf8 Binary files /dev/null and b/data/raw/bach/bwv248.42-s.mid differ diff --git a/data/raw/bach/bwv248.46-5.mid b/data/raw/bach/bwv248.46-5.mid new file mode 100644 index 00000000..e5837113 Binary files /dev/null and b/data/raw/bach/bwv248.46-5.mid differ diff --git a/data/raw/bach/bwv248.5.mid b/data/raw/bach/bwv248.5.mid new file mode 100644 index 00000000..f8062907 Binary files /dev/null and b/data/raw/bach/bwv248.5.mid differ diff --git a/data/raw/bach/bwv248.53-5.mid b/data/raw/bach/bwv248.53-5.mid new file mode 100644 index 00000000..506fa367 Binary files /dev/null and b/data/raw/bach/bwv248.53-5.mid differ diff --git a/data/raw/bach/bwv248.64-s.mid b/data/raw/bach/bwv248.64-s.mid new file mode 100644 index 00000000..35fa6197 Binary files /dev/null and b/data/raw/bach/bwv248.64-s.mid differ diff --git a/data/raw/bach/bwv25.6.mid b/data/raw/bach/bwv25.6.mid new file mode 100644 index 00000000..87747e0e Binary files /dev/null and b/data/raw/bach/bwv25.6.mid differ diff --git a/data/raw/bach/bwv253.mid b/data/raw/bach/bwv253.mid new file mode 100644 index 00000000..83012eff Binary files /dev/null and b/data/raw/bach/bwv253.mid differ diff --git a/data/raw/bach/bwv254.mid b/data/raw/bach/bwv254.mid new file mode 100644 index 00000000..2d91e01a Binary files /dev/null and b/data/raw/bach/bwv254.mid differ diff --git a/data/raw/bach/bwv255.mid b/data/raw/bach/bwv255.mid new file mode 100644 index 00000000..3b2f5b70 Binary files /dev/null and b/data/raw/bach/bwv255.mid differ diff --git a/data/raw/bach/bwv256.mid b/data/raw/bach/bwv256.mid new file mode 100644 index 00000000..1073f151 Binary files /dev/null and b/data/raw/bach/bwv256.mid differ diff --git a/data/raw/bach/bwv257.mid b/data/raw/bach/bwv257.mid new file mode 100644 index 00000000..802affc2 Binary files /dev/null and b/data/raw/bach/bwv257.mid differ diff --git a/data/raw/bach/bwv258.mid b/data/raw/bach/bwv258.mid new file mode 100644 index 00000000..c4ba96a1 Binary files /dev/null and b/data/raw/bach/bwv258.mid differ diff --git a/data/raw/bach/bwv259.mid b/data/raw/bach/bwv259.mid new file mode 100644 index 00000000..c145bfa0 Binary files /dev/null and b/data/raw/bach/bwv259.mid differ diff --git a/data/raw/bach/bwv26.6.mid b/data/raw/bach/bwv26.6.mid new file mode 100644 index 00000000..c8f86f95 Binary files /dev/null and b/data/raw/bach/bwv26.6.mid differ diff --git a/data/raw/bach/bwv260.mid b/data/raw/bach/bwv260.mid new file mode 100644 index 00000000..2bc32f1b Binary files /dev/null and b/data/raw/bach/bwv260.mid differ diff --git a/data/raw/bach/bwv261.mid b/data/raw/bach/bwv261.mid new file mode 100644 index 00000000..e11840ea Binary files /dev/null and b/data/raw/bach/bwv261.mid differ diff --git a/data/raw/bach/bwv262.mid b/data/raw/bach/bwv262.mid new file mode 100644 index 00000000..70b7b187 Binary files /dev/null and b/data/raw/bach/bwv262.mid differ diff --git a/data/raw/bach/bwv263.mid b/data/raw/bach/bwv263.mid new file mode 100644 index 00000000..58a9eb34 Binary files /dev/null and b/data/raw/bach/bwv263.mid differ diff --git a/data/raw/bach/bwv264.mid b/data/raw/bach/bwv264.mid new file mode 100644 index 00000000..2b1af0b9 Binary files /dev/null and b/data/raw/bach/bwv264.mid differ diff --git a/data/raw/bach/bwv265.mid b/data/raw/bach/bwv265.mid new file mode 100644 index 00000000..9b4bc103 Binary files /dev/null and b/data/raw/bach/bwv265.mid differ diff --git a/data/raw/bach/bwv266.mid b/data/raw/bach/bwv266.mid new file mode 100644 index 00000000..2c0bf338 Binary files /dev/null and b/data/raw/bach/bwv266.mid differ diff --git a/data/raw/bach/bwv267.mid b/data/raw/bach/bwv267.mid new file mode 100644 index 00000000..27b90417 Binary files /dev/null and b/data/raw/bach/bwv267.mid differ diff --git a/data/raw/bach/bwv268.mid b/data/raw/bach/bwv268.mid new file mode 100644 index 00000000..27fe193c Binary files /dev/null and b/data/raw/bach/bwv268.mid differ diff --git a/data/raw/bach/bwv269.mid b/data/raw/bach/bwv269.mid new file mode 100644 index 00000000..ee0c15e0 Binary files /dev/null and b/data/raw/bach/bwv269.mid differ diff --git a/data/raw/bach/bwv270.mid b/data/raw/bach/bwv270.mid new file mode 100644 index 00000000..9545d002 Binary files /dev/null and b/data/raw/bach/bwv270.mid differ diff --git a/data/raw/bach/bwv271.mid b/data/raw/bach/bwv271.mid new file mode 100644 index 00000000..ac263de4 Binary files /dev/null and b/data/raw/bach/bwv271.mid differ diff --git a/data/raw/bach/bwv272.mid b/data/raw/bach/bwv272.mid new file mode 100644 index 00000000..6dc8f65a Binary files /dev/null and b/data/raw/bach/bwv272.mid differ diff --git a/data/raw/bach/bwv273.mid b/data/raw/bach/bwv273.mid new file mode 100644 index 00000000..1fb357e3 Binary files /dev/null and b/data/raw/bach/bwv273.mid differ diff --git a/data/raw/bach/bwv276.mid b/data/raw/bach/bwv276.mid new file mode 100644 index 00000000..6ed56af6 Binary files /dev/null and b/data/raw/bach/bwv276.mid differ diff --git a/data/raw/bach/bwv277.mid b/data/raw/bach/bwv277.mid new file mode 100644 index 00000000..196137ff Binary files /dev/null and b/data/raw/bach/bwv277.mid differ diff --git a/data/raw/bach/bwv278.mid b/data/raw/bach/bwv278.mid new file mode 100644 index 00000000..389dcb34 Binary files /dev/null and b/data/raw/bach/bwv278.mid differ diff --git a/data/raw/bach/bwv279.mid b/data/raw/bach/bwv279.mid new file mode 100644 index 00000000..96efbf37 Binary files /dev/null and b/data/raw/bach/bwv279.mid differ diff --git a/data/raw/bach/bwv28.6.mid b/data/raw/bach/bwv28.6.mid new file mode 100644 index 00000000..ea865f01 Binary files /dev/null and b/data/raw/bach/bwv28.6.mid differ diff --git a/data/raw/bach/bwv280.mid b/data/raw/bach/bwv280.mid new file mode 100644 index 00000000..54d621fc Binary files /dev/null and b/data/raw/bach/bwv280.mid differ diff --git a/data/raw/bach/bwv281.mid b/data/raw/bach/bwv281.mid new file mode 100644 index 00000000..6fbd7d5c Binary files /dev/null and b/data/raw/bach/bwv281.mid differ diff --git a/data/raw/bach/bwv282.mid b/data/raw/bach/bwv282.mid new file mode 100644 index 00000000..483193b2 Binary files /dev/null and b/data/raw/bach/bwv282.mid differ diff --git a/data/raw/bach/bwv283.mid b/data/raw/bach/bwv283.mid new file mode 100644 index 00000000..fda55550 Binary files /dev/null and b/data/raw/bach/bwv283.mid differ diff --git a/data/raw/bach/bwv284.mid b/data/raw/bach/bwv284.mid new file mode 100644 index 00000000..6a6acf6c Binary files /dev/null and b/data/raw/bach/bwv284.mid differ diff --git a/data/raw/bach/bwv285.mid b/data/raw/bach/bwv285.mid new file mode 100644 index 00000000..7e81c2ae Binary files /dev/null and b/data/raw/bach/bwv285.mid differ diff --git a/data/raw/bach/bwv286.mid b/data/raw/bach/bwv286.mid new file mode 100644 index 00000000..46337f84 Binary files /dev/null and b/data/raw/bach/bwv286.mid differ diff --git a/data/raw/bach/bwv287.mid b/data/raw/bach/bwv287.mid new file mode 100644 index 00000000..9308eee5 Binary files /dev/null and b/data/raw/bach/bwv287.mid differ diff --git a/data/raw/bach/bwv288.mid b/data/raw/bach/bwv288.mid new file mode 100644 index 00000000..5d13879a Binary files /dev/null and b/data/raw/bach/bwv288.mid differ diff --git a/data/raw/bach/bwv289.mid b/data/raw/bach/bwv289.mid new file mode 100644 index 00000000..b4114c61 Binary files /dev/null and b/data/raw/bach/bwv289.mid differ diff --git a/data/raw/bach/bwv290.mid b/data/raw/bach/bwv290.mid new file mode 100644 index 00000000..049ec87d Binary files /dev/null and b/data/raw/bach/bwv290.mid differ diff --git a/data/raw/bach/bwv291.mid b/data/raw/bach/bwv291.mid new file mode 100644 index 00000000..69048084 Binary files /dev/null and b/data/raw/bach/bwv291.mid differ diff --git a/data/raw/bach/bwv292.mid b/data/raw/bach/bwv292.mid new file mode 100644 index 00000000..14bed88c Binary files /dev/null and b/data/raw/bach/bwv292.mid differ diff --git a/data/raw/bach/bwv293.mid b/data/raw/bach/bwv293.mid new file mode 100644 index 00000000..b85b8028 Binary files /dev/null and b/data/raw/bach/bwv293.mid differ diff --git a/data/raw/bach/bwv294.mid b/data/raw/bach/bwv294.mid new file mode 100644 index 00000000..f36cedc1 Binary files /dev/null and b/data/raw/bach/bwv294.mid differ diff --git a/data/raw/bach/bwv295.mid b/data/raw/bach/bwv295.mid new file mode 100644 index 00000000..b9f02e82 Binary files /dev/null and b/data/raw/bach/bwv295.mid differ diff --git a/data/raw/bach/bwv296.mid b/data/raw/bach/bwv296.mid new file mode 100644 index 00000000..e14f7189 Binary files /dev/null and b/data/raw/bach/bwv296.mid differ diff --git a/data/raw/bach/bwv297.mid b/data/raw/bach/bwv297.mid new file mode 100644 index 00000000..dcb788a0 Binary files /dev/null and b/data/raw/bach/bwv297.mid differ diff --git a/data/raw/bach/bwv298.mid b/data/raw/bach/bwv298.mid new file mode 100644 index 00000000..133fa04c Binary files /dev/null and b/data/raw/bach/bwv298.mid differ diff --git a/data/raw/bach/bwv299.mid b/data/raw/bach/bwv299.mid new file mode 100644 index 00000000..489d43b4 Binary files /dev/null and b/data/raw/bach/bwv299.mid differ diff --git a/data/raw/bach/bwv3.6.mid b/data/raw/bach/bwv3.6.mid new file mode 100644 index 00000000..2ee18660 Binary files /dev/null and b/data/raw/bach/bwv3.6.mid differ diff --git a/data/raw/bach/bwv30.6.mid b/data/raw/bach/bwv30.6.mid new file mode 100644 index 00000000..9f06fc65 Binary files /dev/null and b/data/raw/bach/bwv30.6.mid differ diff --git a/data/raw/bach/bwv300.mid b/data/raw/bach/bwv300.mid new file mode 100644 index 00000000..58e1ae0e Binary files /dev/null and b/data/raw/bach/bwv300.mid differ diff --git a/data/raw/bach/bwv301.mid b/data/raw/bach/bwv301.mid new file mode 100644 index 00000000..63aaebb3 Binary files /dev/null and b/data/raw/bach/bwv301.mid differ diff --git a/data/raw/bach/bwv302.mid b/data/raw/bach/bwv302.mid new file mode 100644 index 00000000..667aa418 Binary files /dev/null and b/data/raw/bach/bwv302.mid differ diff --git a/data/raw/bach/bwv303.mid b/data/raw/bach/bwv303.mid new file mode 100644 index 00000000..2d2f3839 Binary files /dev/null and b/data/raw/bach/bwv303.mid differ diff --git a/data/raw/bach/bwv304.mid b/data/raw/bach/bwv304.mid new file mode 100644 index 00000000..b1cf375b Binary files /dev/null and b/data/raw/bach/bwv304.mid differ diff --git a/data/raw/bach/bwv305.mid b/data/raw/bach/bwv305.mid new file mode 100644 index 00000000..3bb51469 Binary files /dev/null and b/data/raw/bach/bwv305.mid differ diff --git a/data/raw/bach/bwv306.mid b/data/raw/bach/bwv306.mid new file mode 100644 index 00000000..af26057c Binary files /dev/null and b/data/raw/bach/bwv306.mid differ diff --git a/data/raw/bach/bwv307.mid b/data/raw/bach/bwv307.mid new file mode 100644 index 00000000..99e5b0eb Binary files /dev/null and b/data/raw/bach/bwv307.mid differ diff --git a/data/raw/bach/bwv308.mid b/data/raw/bach/bwv308.mid new file mode 100644 index 00000000..12fc8a69 Binary files /dev/null and b/data/raw/bach/bwv308.mid differ diff --git a/data/raw/bach/bwv309.mid b/data/raw/bach/bwv309.mid new file mode 100644 index 00000000..d1c9b71b Binary files /dev/null and b/data/raw/bach/bwv309.mid differ diff --git a/data/raw/bach/bwv310.mid b/data/raw/bach/bwv310.mid new file mode 100644 index 00000000..0a871830 Binary files /dev/null and b/data/raw/bach/bwv310.mid differ diff --git a/data/raw/bach/bwv311.mid b/data/raw/bach/bwv311.mid new file mode 100644 index 00000000..e9370413 Binary files /dev/null and b/data/raw/bach/bwv311.mid differ diff --git a/data/raw/bach/bwv312.mid b/data/raw/bach/bwv312.mid new file mode 100644 index 00000000..ad766e58 Binary files /dev/null and b/data/raw/bach/bwv312.mid differ diff --git a/data/raw/bach/bwv313.mid b/data/raw/bach/bwv313.mid new file mode 100644 index 00000000..229952ab Binary files /dev/null and b/data/raw/bach/bwv313.mid differ diff --git a/data/raw/bach/bwv314.mid b/data/raw/bach/bwv314.mid new file mode 100644 index 00000000..7528954b Binary files /dev/null and b/data/raw/bach/bwv314.mid differ diff --git a/data/raw/bach/bwv315.mid b/data/raw/bach/bwv315.mid new file mode 100644 index 00000000..e1c038d1 Binary files /dev/null and b/data/raw/bach/bwv315.mid differ diff --git a/data/raw/bach/bwv316.mid b/data/raw/bach/bwv316.mid new file mode 100644 index 00000000..ff85c60b Binary files /dev/null and b/data/raw/bach/bwv316.mid differ diff --git a/data/raw/bach/bwv317.mid b/data/raw/bach/bwv317.mid new file mode 100644 index 00000000..1556f457 Binary files /dev/null and b/data/raw/bach/bwv317.mid differ diff --git a/data/raw/bach/bwv318.mid b/data/raw/bach/bwv318.mid new file mode 100644 index 00000000..650da22b Binary files /dev/null and b/data/raw/bach/bwv318.mid differ diff --git a/data/raw/bach/bwv319.mid b/data/raw/bach/bwv319.mid new file mode 100644 index 00000000..ce4b58ac Binary files /dev/null and b/data/raw/bach/bwv319.mid differ diff --git a/data/raw/bach/bwv32.6.mid b/data/raw/bach/bwv32.6.mid new file mode 100644 index 00000000..aa6e94c4 Binary files /dev/null and b/data/raw/bach/bwv32.6.mid differ diff --git a/data/raw/bach/bwv320.mid b/data/raw/bach/bwv320.mid new file mode 100644 index 00000000..d0461aec Binary files /dev/null and b/data/raw/bach/bwv320.mid differ diff --git a/data/raw/bach/bwv321.mid b/data/raw/bach/bwv321.mid new file mode 100644 index 00000000..0ce3dc8b Binary files /dev/null and b/data/raw/bach/bwv321.mid differ diff --git a/data/raw/bach/bwv322.mid b/data/raw/bach/bwv322.mid new file mode 100644 index 00000000..358ef451 Binary files /dev/null and b/data/raw/bach/bwv322.mid differ diff --git a/data/raw/bach/bwv323.mid b/data/raw/bach/bwv323.mid new file mode 100644 index 00000000..d3128722 Binary files /dev/null and b/data/raw/bach/bwv323.mid differ diff --git a/data/raw/bach/bwv324.mid b/data/raw/bach/bwv324.mid new file mode 100644 index 00000000..a0b838d0 Binary files /dev/null and b/data/raw/bach/bwv324.mid differ diff --git a/data/raw/bach/bwv325.mid b/data/raw/bach/bwv325.mid new file mode 100644 index 00000000..bd1b7da9 Binary files /dev/null and b/data/raw/bach/bwv325.mid differ diff --git a/data/raw/bach/bwv326.mid b/data/raw/bach/bwv326.mid new file mode 100644 index 00000000..310a2e94 Binary files /dev/null and b/data/raw/bach/bwv326.mid differ diff --git a/data/raw/bach/bwv327.mid b/data/raw/bach/bwv327.mid new file mode 100644 index 00000000..ecd22cea Binary files /dev/null and b/data/raw/bach/bwv327.mid differ diff --git a/data/raw/bach/bwv328.mid b/data/raw/bach/bwv328.mid new file mode 100644 index 00000000..62a113dc Binary files /dev/null and b/data/raw/bach/bwv328.mid differ diff --git a/data/raw/bach/bwv329.mid b/data/raw/bach/bwv329.mid new file mode 100644 index 00000000..2ccb8ccf Binary files /dev/null and b/data/raw/bach/bwv329.mid differ diff --git a/data/raw/bach/bwv33.6.mid b/data/raw/bach/bwv33.6.mid new file mode 100644 index 00000000..ba7057ce Binary files /dev/null and b/data/raw/bach/bwv33.6.mid differ diff --git a/data/raw/bach/bwv330.mid b/data/raw/bach/bwv330.mid new file mode 100644 index 00000000..19e696d2 Binary files /dev/null and b/data/raw/bach/bwv330.mid differ diff --git a/data/raw/bach/bwv331.mid b/data/raw/bach/bwv331.mid new file mode 100644 index 00000000..215e0bb0 Binary files /dev/null and b/data/raw/bach/bwv331.mid differ diff --git a/data/raw/bach/bwv332.mid b/data/raw/bach/bwv332.mid new file mode 100644 index 00000000..7f0fe5a4 Binary files /dev/null and b/data/raw/bach/bwv332.mid differ diff --git a/data/raw/bach/bwv333.mid b/data/raw/bach/bwv333.mid new file mode 100644 index 00000000..45a12c02 Binary files /dev/null and b/data/raw/bach/bwv333.mid differ diff --git a/data/raw/bach/bwv334.mid b/data/raw/bach/bwv334.mid new file mode 100644 index 00000000..470cdfdc Binary files /dev/null and b/data/raw/bach/bwv334.mid differ diff --git a/data/raw/bach/bwv335.mid b/data/raw/bach/bwv335.mid new file mode 100644 index 00000000..9eea1b6b Binary files /dev/null and b/data/raw/bach/bwv335.mid differ diff --git a/data/raw/bach/bwv336.mid b/data/raw/bach/bwv336.mid new file mode 100644 index 00000000..7568b129 Binary files /dev/null and b/data/raw/bach/bwv336.mid differ diff --git a/data/raw/bach/bwv337.mid b/data/raw/bach/bwv337.mid new file mode 100644 index 00000000..e8113f7b Binary files /dev/null and b/data/raw/bach/bwv337.mid differ diff --git a/data/raw/bach/bwv338.mid b/data/raw/bach/bwv338.mid new file mode 100644 index 00000000..dbfc341c Binary files /dev/null and b/data/raw/bach/bwv338.mid differ diff --git a/data/raw/bach/bwv339.mid b/data/raw/bach/bwv339.mid new file mode 100644 index 00000000..ccb3478e Binary files /dev/null and b/data/raw/bach/bwv339.mid differ diff --git a/data/raw/bach/bwv340.mid b/data/raw/bach/bwv340.mid new file mode 100644 index 00000000..14b24c0e Binary files /dev/null and b/data/raw/bach/bwv340.mid differ diff --git a/data/raw/bach/bwv341.mid b/data/raw/bach/bwv341.mid new file mode 100644 index 00000000..1aca7aed Binary files /dev/null and b/data/raw/bach/bwv341.mid differ diff --git a/data/raw/bach/bwv342.mid b/data/raw/bach/bwv342.mid new file mode 100644 index 00000000..0b4342eb Binary files /dev/null and b/data/raw/bach/bwv342.mid differ diff --git a/data/raw/bach/bwv343.mid b/data/raw/bach/bwv343.mid new file mode 100644 index 00000000..c6befbff Binary files /dev/null and b/data/raw/bach/bwv343.mid differ diff --git a/data/raw/bach/bwv344.mid b/data/raw/bach/bwv344.mid new file mode 100644 index 00000000..e7f3d232 Binary files /dev/null and b/data/raw/bach/bwv344.mid differ diff --git a/data/raw/bach/bwv345.mid b/data/raw/bach/bwv345.mid new file mode 100644 index 00000000..aaef9a5a Binary files /dev/null and b/data/raw/bach/bwv345.mid differ diff --git a/data/raw/bach/bwv346.mid b/data/raw/bach/bwv346.mid new file mode 100644 index 00000000..31d65c6d Binary files /dev/null and b/data/raw/bach/bwv346.mid differ diff --git a/data/raw/bach/bwv347.mid b/data/raw/bach/bwv347.mid new file mode 100644 index 00000000..59288d43 Binary files /dev/null and b/data/raw/bach/bwv347.mid differ diff --git a/data/raw/bach/bwv348.mid b/data/raw/bach/bwv348.mid new file mode 100644 index 00000000..9a5118d6 Binary files /dev/null and b/data/raw/bach/bwv348.mid differ diff --git a/data/raw/bach/bwv349.mid b/data/raw/bach/bwv349.mid new file mode 100644 index 00000000..6ae005ff Binary files /dev/null and b/data/raw/bach/bwv349.mid differ diff --git a/data/raw/bach/bwv350.mid b/data/raw/bach/bwv350.mid new file mode 100644 index 00000000..c099edc0 Binary files /dev/null and b/data/raw/bach/bwv350.mid differ diff --git a/data/raw/bach/bwv351.mid b/data/raw/bach/bwv351.mid new file mode 100644 index 00000000..5344c0b3 Binary files /dev/null and b/data/raw/bach/bwv351.mid differ diff --git a/data/raw/bach/bwv352.mid b/data/raw/bach/bwv352.mid new file mode 100644 index 00000000..c6e237f1 Binary files /dev/null and b/data/raw/bach/bwv352.mid differ diff --git a/data/raw/bach/bwv353.mid b/data/raw/bach/bwv353.mid new file mode 100644 index 00000000..949cef13 Binary files /dev/null and b/data/raw/bach/bwv353.mid differ diff --git a/data/raw/bach/bwv354.mid b/data/raw/bach/bwv354.mid new file mode 100644 index 00000000..46d335e3 Binary files /dev/null and b/data/raw/bach/bwv354.mid differ diff --git a/data/raw/bach/bwv355.mid b/data/raw/bach/bwv355.mid new file mode 100644 index 00000000..8058f6d8 Binary files /dev/null and b/data/raw/bach/bwv355.mid differ diff --git a/data/raw/bach/bwv356.mid b/data/raw/bach/bwv356.mid new file mode 100644 index 00000000..8373c754 Binary files /dev/null and b/data/raw/bach/bwv356.mid differ diff --git a/data/raw/bach/bwv357.mid b/data/raw/bach/bwv357.mid new file mode 100644 index 00000000..0a070317 Binary files /dev/null and b/data/raw/bach/bwv357.mid differ diff --git a/data/raw/bach/bwv358.mid b/data/raw/bach/bwv358.mid new file mode 100644 index 00000000..4b8f135f Binary files /dev/null and b/data/raw/bach/bwv358.mid differ diff --git a/data/raw/bach/bwv359.mid b/data/raw/bach/bwv359.mid new file mode 100644 index 00000000..084ad4f5 Binary files /dev/null and b/data/raw/bach/bwv359.mid differ diff --git a/data/raw/bach/bwv36.4-2.mid b/data/raw/bach/bwv36.4-2.mid new file mode 100644 index 00000000..cd75c74b Binary files /dev/null and b/data/raw/bach/bwv36.4-2.mid differ diff --git a/data/raw/bach/bwv36.8-2.mid b/data/raw/bach/bwv36.8-2.mid new file mode 100644 index 00000000..bdc4c20a Binary files /dev/null and b/data/raw/bach/bwv36.8-2.mid differ diff --git a/data/raw/bach/bwv360.mid b/data/raw/bach/bwv360.mid new file mode 100644 index 00000000..b4159a1c Binary files /dev/null and b/data/raw/bach/bwv360.mid differ diff --git a/data/raw/bach/bwv361.mid b/data/raw/bach/bwv361.mid new file mode 100644 index 00000000..b3ac7c02 Binary files /dev/null and b/data/raw/bach/bwv361.mid differ diff --git a/data/raw/bach/bwv362.mid b/data/raw/bach/bwv362.mid new file mode 100644 index 00000000..5b7df32a Binary files /dev/null and b/data/raw/bach/bwv362.mid differ diff --git a/data/raw/bach/bwv363.mid b/data/raw/bach/bwv363.mid new file mode 100644 index 00000000..ff7def1f Binary files /dev/null and b/data/raw/bach/bwv363.mid differ diff --git a/data/raw/bach/bwv364.mid b/data/raw/bach/bwv364.mid new file mode 100644 index 00000000..6b54aa5d Binary files /dev/null and b/data/raw/bach/bwv364.mid differ diff --git a/data/raw/bach/bwv365.mid b/data/raw/bach/bwv365.mid new file mode 100644 index 00000000..b5001fa7 Binary files /dev/null and b/data/raw/bach/bwv365.mid differ diff --git a/data/raw/bach/bwv366.mid b/data/raw/bach/bwv366.mid new file mode 100644 index 00000000..f41ef8f1 Binary files /dev/null and b/data/raw/bach/bwv366.mid differ diff --git a/data/raw/bach/bwv367.mid b/data/raw/bach/bwv367.mid new file mode 100644 index 00000000..1a032763 Binary files /dev/null and b/data/raw/bach/bwv367.mid differ diff --git a/data/raw/bach/bwv368.mid b/data/raw/bach/bwv368.mid new file mode 100644 index 00000000..758569c8 Binary files /dev/null and b/data/raw/bach/bwv368.mid differ diff --git a/data/raw/bach/bwv369.mid b/data/raw/bach/bwv369.mid new file mode 100644 index 00000000..d6bb7a0a Binary files /dev/null and b/data/raw/bach/bwv369.mid differ diff --git a/data/raw/bach/bwv37.6.mid b/data/raw/bach/bwv37.6.mid new file mode 100644 index 00000000..b2e800a9 Binary files /dev/null and b/data/raw/bach/bwv37.6.mid differ diff --git a/data/raw/bach/bwv370.mid b/data/raw/bach/bwv370.mid new file mode 100644 index 00000000..02aa0830 Binary files /dev/null and b/data/raw/bach/bwv370.mid differ diff --git a/data/raw/bach/bwv371.mid b/data/raw/bach/bwv371.mid new file mode 100644 index 00000000..c77711a9 Binary files /dev/null and b/data/raw/bach/bwv371.mid differ diff --git a/data/raw/bach/bwv372.mid b/data/raw/bach/bwv372.mid new file mode 100644 index 00000000..d825ec78 Binary files /dev/null and b/data/raw/bach/bwv372.mid differ diff --git a/data/raw/bach/bwv373.mid b/data/raw/bach/bwv373.mid new file mode 100644 index 00000000..53cd0807 Binary files /dev/null and b/data/raw/bach/bwv373.mid differ diff --git a/data/raw/bach/bwv374.mid b/data/raw/bach/bwv374.mid new file mode 100644 index 00000000..0f1ef3da Binary files /dev/null and b/data/raw/bach/bwv374.mid differ diff --git a/data/raw/bach/bwv375.mid b/data/raw/bach/bwv375.mid new file mode 100644 index 00000000..b795c2b5 Binary files /dev/null and b/data/raw/bach/bwv375.mid differ diff --git a/data/raw/bach/bwv376.mid b/data/raw/bach/bwv376.mid new file mode 100644 index 00000000..bb91d2bf Binary files /dev/null and b/data/raw/bach/bwv376.mid differ diff --git a/data/raw/bach/bwv377.mid b/data/raw/bach/bwv377.mid new file mode 100644 index 00000000..0bc4d64e Binary files /dev/null and b/data/raw/bach/bwv377.mid differ diff --git a/data/raw/bach/bwv378.mid b/data/raw/bach/bwv378.mid new file mode 100644 index 00000000..27be1fd5 Binary files /dev/null and b/data/raw/bach/bwv378.mid differ diff --git a/data/raw/bach/bwv379.mid b/data/raw/bach/bwv379.mid new file mode 100644 index 00000000..4676c34f Binary files /dev/null and b/data/raw/bach/bwv379.mid differ diff --git a/data/raw/bach/bwv38.6.mid b/data/raw/bach/bwv38.6.mid new file mode 100644 index 00000000..1ff2dadd Binary files /dev/null and b/data/raw/bach/bwv38.6.mid differ diff --git a/data/raw/bach/bwv380.mid b/data/raw/bach/bwv380.mid new file mode 100644 index 00000000..b2864530 Binary files /dev/null and b/data/raw/bach/bwv380.mid differ diff --git a/data/raw/bach/bwv381.mid b/data/raw/bach/bwv381.mid new file mode 100644 index 00000000..cd97fe6a Binary files /dev/null and b/data/raw/bach/bwv381.mid differ diff --git a/data/raw/bach/bwv382.mid b/data/raw/bach/bwv382.mid new file mode 100644 index 00000000..161ed823 Binary files /dev/null and b/data/raw/bach/bwv382.mid differ diff --git a/data/raw/bach/bwv383.mid b/data/raw/bach/bwv383.mid new file mode 100644 index 00000000..8a3eb609 Binary files /dev/null and b/data/raw/bach/bwv383.mid differ diff --git a/data/raw/bach/bwv384.mid b/data/raw/bach/bwv384.mid new file mode 100644 index 00000000..3f3cc301 Binary files /dev/null and b/data/raw/bach/bwv384.mid differ diff --git a/data/raw/bach/bwv385.mid b/data/raw/bach/bwv385.mid new file mode 100644 index 00000000..1aae5122 Binary files /dev/null and b/data/raw/bach/bwv385.mid differ diff --git a/data/raw/bach/bwv386.mid b/data/raw/bach/bwv386.mid new file mode 100644 index 00000000..5436efe2 Binary files /dev/null and b/data/raw/bach/bwv386.mid differ diff --git a/data/raw/bach/bwv387.mid b/data/raw/bach/bwv387.mid new file mode 100644 index 00000000..5d14b255 Binary files /dev/null and b/data/raw/bach/bwv387.mid differ diff --git a/data/raw/bach/bwv388.mid b/data/raw/bach/bwv388.mid new file mode 100644 index 00000000..bbb21460 Binary files /dev/null and b/data/raw/bach/bwv388.mid differ diff --git a/data/raw/bach/bwv389.mid b/data/raw/bach/bwv389.mid new file mode 100644 index 00000000..4ab18c7a Binary files /dev/null and b/data/raw/bach/bwv389.mid differ diff --git a/data/raw/bach/bwv39.7.mid b/data/raw/bach/bwv39.7.mid new file mode 100644 index 00000000..28ef5b1d Binary files /dev/null and b/data/raw/bach/bwv39.7.mid differ diff --git a/data/raw/bach/bwv390.mid b/data/raw/bach/bwv390.mid new file mode 100644 index 00000000..b2b76f41 Binary files /dev/null and b/data/raw/bach/bwv390.mid differ diff --git a/data/raw/bach/bwv391.mid b/data/raw/bach/bwv391.mid new file mode 100644 index 00000000..58c66d49 Binary files /dev/null and b/data/raw/bach/bwv391.mid differ diff --git a/data/raw/bach/bwv392.mid b/data/raw/bach/bwv392.mid new file mode 100644 index 00000000..99ab8cc7 Binary files /dev/null and b/data/raw/bach/bwv392.mid differ diff --git a/data/raw/bach/bwv393.mid b/data/raw/bach/bwv393.mid new file mode 100644 index 00000000..b6db41fa Binary files /dev/null and b/data/raw/bach/bwv393.mid differ diff --git a/data/raw/bach/bwv394.mid b/data/raw/bach/bwv394.mid new file mode 100644 index 00000000..0e550f6f Binary files /dev/null and b/data/raw/bach/bwv394.mid differ diff --git a/data/raw/bach/bwv395.mid b/data/raw/bach/bwv395.mid new file mode 100644 index 00000000..d44c4ab6 Binary files /dev/null and b/data/raw/bach/bwv395.mid differ diff --git a/data/raw/bach/bwv396.mid b/data/raw/bach/bwv396.mid new file mode 100644 index 00000000..8fe92ae1 Binary files /dev/null and b/data/raw/bach/bwv396.mid differ diff --git a/data/raw/bach/bwv397.mid b/data/raw/bach/bwv397.mid new file mode 100644 index 00000000..c207e63e Binary files /dev/null and b/data/raw/bach/bwv397.mid differ diff --git a/data/raw/bach/bwv398.mid b/data/raw/bach/bwv398.mid new file mode 100644 index 00000000..7813a566 Binary files /dev/null and b/data/raw/bach/bwv398.mid differ diff --git a/data/raw/bach/bwv399.mid b/data/raw/bach/bwv399.mid new file mode 100644 index 00000000..9ea99c45 Binary files /dev/null and b/data/raw/bach/bwv399.mid differ diff --git a/data/raw/bach/bwv4.8.mid b/data/raw/bach/bwv4.8.mid new file mode 100644 index 00000000..2584165b Binary files /dev/null and b/data/raw/bach/bwv4.8.mid differ diff --git a/data/raw/bach/bwv40.3.mid b/data/raw/bach/bwv40.3.mid new file mode 100644 index 00000000..7b1d4067 Binary files /dev/null and b/data/raw/bach/bwv40.3.mid differ diff --git a/data/raw/bach/bwv40.6.mid b/data/raw/bach/bwv40.6.mid new file mode 100644 index 00000000..58711356 Binary files /dev/null and b/data/raw/bach/bwv40.6.mid differ diff --git a/data/raw/bach/bwv40.8.mid b/data/raw/bach/bwv40.8.mid new file mode 100644 index 00000000..c7ee0fc4 Binary files /dev/null and b/data/raw/bach/bwv40.8.mid differ diff --git a/data/raw/bach/bwv400.mid b/data/raw/bach/bwv400.mid new file mode 100644 index 00000000..a37ecf9d Binary files /dev/null and b/data/raw/bach/bwv400.mid differ diff --git a/data/raw/bach/bwv401.mid b/data/raw/bach/bwv401.mid new file mode 100644 index 00000000..ceb5bd9e Binary files /dev/null and b/data/raw/bach/bwv401.mid differ diff --git a/data/raw/bach/bwv402.mid b/data/raw/bach/bwv402.mid new file mode 100644 index 00000000..0b5eeea5 Binary files /dev/null and b/data/raw/bach/bwv402.mid differ diff --git a/data/raw/bach/bwv403.mid b/data/raw/bach/bwv403.mid new file mode 100644 index 00000000..2b7559e2 Binary files /dev/null and b/data/raw/bach/bwv403.mid differ diff --git a/data/raw/bach/bwv404.mid b/data/raw/bach/bwv404.mid new file mode 100644 index 00000000..6199841d Binary files /dev/null and b/data/raw/bach/bwv404.mid differ diff --git a/data/raw/bach/bwv405.mid b/data/raw/bach/bwv405.mid new file mode 100644 index 00000000..5fab0ee2 Binary files /dev/null and b/data/raw/bach/bwv405.mid differ diff --git a/data/raw/bach/bwv406.mid b/data/raw/bach/bwv406.mid new file mode 100644 index 00000000..ae3f3dfd Binary files /dev/null and b/data/raw/bach/bwv406.mid differ diff --git a/data/raw/bach/bwv407.mid b/data/raw/bach/bwv407.mid new file mode 100644 index 00000000..982ee82d Binary files /dev/null and b/data/raw/bach/bwv407.mid differ diff --git a/data/raw/bach/bwv408.mid b/data/raw/bach/bwv408.mid new file mode 100644 index 00000000..1ddb3d67 Binary files /dev/null and b/data/raw/bach/bwv408.mid differ diff --git a/data/raw/bach/bwv410.mid b/data/raw/bach/bwv410.mid new file mode 100644 index 00000000..04854130 Binary files /dev/null and b/data/raw/bach/bwv410.mid differ diff --git a/data/raw/bach/bwv411.mid b/data/raw/bach/bwv411.mid new file mode 100644 index 00000000..41421d44 Binary files /dev/null and b/data/raw/bach/bwv411.mid differ diff --git a/data/raw/bach/bwv412.mid b/data/raw/bach/bwv412.mid new file mode 100644 index 00000000..991972f4 Binary files /dev/null and b/data/raw/bach/bwv412.mid differ diff --git a/data/raw/bach/bwv413.mid b/data/raw/bach/bwv413.mid new file mode 100644 index 00000000..341c5ba8 Binary files /dev/null and b/data/raw/bach/bwv413.mid differ diff --git a/data/raw/bach/bwv414.mid b/data/raw/bach/bwv414.mid new file mode 100644 index 00000000..19971505 Binary files /dev/null and b/data/raw/bach/bwv414.mid differ diff --git a/data/raw/bach/bwv415.mid b/data/raw/bach/bwv415.mid new file mode 100644 index 00000000..3e3da2a5 Binary files /dev/null and b/data/raw/bach/bwv415.mid differ diff --git a/data/raw/bach/bwv416.mid b/data/raw/bach/bwv416.mid new file mode 100644 index 00000000..4511bf2f Binary files /dev/null and b/data/raw/bach/bwv416.mid differ diff --git a/data/raw/bach/bwv417.mid b/data/raw/bach/bwv417.mid new file mode 100644 index 00000000..6e62f9e0 Binary files /dev/null and b/data/raw/bach/bwv417.mid differ diff --git a/data/raw/bach/bwv418.mid b/data/raw/bach/bwv418.mid new file mode 100644 index 00000000..1827d8a6 Binary files /dev/null and b/data/raw/bach/bwv418.mid differ diff --git a/data/raw/bach/bwv419.mid b/data/raw/bach/bwv419.mid new file mode 100644 index 00000000..d01ab839 Binary files /dev/null and b/data/raw/bach/bwv419.mid differ diff --git a/data/raw/bach/bwv42.7.mid b/data/raw/bach/bwv42.7.mid new file mode 100644 index 00000000..028907a3 Binary files /dev/null and b/data/raw/bach/bwv42.7.mid differ diff --git a/data/raw/bach/bwv420.mid b/data/raw/bach/bwv420.mid new file mode 100644 index 00000000..1bc7adf9 Binary files /dev/null and b/data/raw/bach/bwv420.mid differ diff --git a/data/raw/bach/bwv421.mid b/data/raw/bach/bwv421.mid new file mode 100644 index 00000000..7350581b Binary files /dev/null and b/data/raw/bach/bwv421.mid differ diff --git a/data/raw/bach/bwv422.mid b/data/raw/bach/bwv422.mid new file mode 100644 index 00000000..e34103f8 Binary files /dev/null and b/data/raw/bach/bwv422.mid differ diff --git a/data/raw/bach/bwv423.mid b/data/raw/bach/bwv423.mid new file mode 100644 index 00000000..a079cb21 Binary files /dev/null and b/data/raw/bach/bwv423.mid differ diff --git a/data/raw/bach/bwv424.mid b/data/raw/bach/bwv424.mid new file mode 100644 index 00000000..def36af0 Binary files /dev/null and b/data/raw/bach/bwv424.mid differ diff --git a/data/raw/bach/bwv425.mid b/data/raw/bach/bwv425.mid new file mode 100644 index 00000000..690ad316 Binary files /dev/null and b/data/raw/bach/bwv425.mid differ diff --git a/data/raw/bach/bwv426.mid b/data/raw/bach/bwv426.mid new file mode 100644 index 00000000..1a681966 Binary files /dev/null and b/data/raw/bach/bwv426.mid differ diff --git a/data/raw/bach/bwv427.mid b/data/raw/bach/bwv427.mid new file mode 100644 index 00000000..83dcf178 Binary files /dev/null and b/data/raw/bach/bwv427.mid differ diff --git a/data/raw/bach/bwv428.mid b/data/raw/bach/bwv428.mid new file mode 100644 index 00000000..6e2e4358 Binary files /dev/null and b/data/raw/bach/bwv428.mid differ diff --git a/data/raw/bach/bwv429.mid b/data/raw/bach/bwv429.mid new file mode 100644 index 00000000..8edfdf95 Binary files /dev/null and b/data/raw/bach/bwv429.mid differ diff --git a/data/raw/bach/bwv43.11.mid b/data/raw/bach/bwv43.11.mid new file mode 100644 index 00000000..ef5f091e Binary files /dev/null and b/data/raw/bach/bwv43.11.mid differ diff --git a/data/raw/bach/bwv430.mid b/data/raw/bach/bwv430.mid new file mode 100644 index 00000000..2fc4e9bb Binary files /dev/null and b/data/raw/bach/bwv430.mid differ diff --git a/data/raw/bach/bwv431.mid b/data/raw/bach/bwv431.mid new file mode 100644 index 00000000..34717d6c Binary files /dev/null and b/data/raw/bach/bwv431.mid differ diff --git a/data/raw/bach/bwv432.mid b/data/raw/bach/bwv432.mid new file mode 100644 index 00000000..86801eef Binary files /dev/null and b/data/raw/bach/bwv432.mid differ diff --git a/data/raw/bach/bwv433.mid b/data/raw/bach/bwv433.mid new file mode 100644 index 00000000..0c4cf66a Binary files /dev/null and b/data/raw/bach/bwv433.mid differ diff --git a/data/raw/bach/bwv434.mid b/data/raw/bach/bwv434.mid new file mode 100644 index 00000000..cb7c46ed Binary files /dev/null and b/data/raw/bach/bwv434.mid differ diff --git a/data/raw/bach/bwv435.mid b/data/raw/bach/bwv435.mid new file mode 100644 index 00000000..a765c2d7 Binary files /dev/null and b/data/raw/bach/bwv435.mid differ diff --git a/data/raw/bach/bwv436.mid b/data/raw/bach/bwv436.mid new file mode 100644 index 00000000..3a71ec08 Binary files /dev/null and b/data/raw/bach/bwv436.mid differ diff --git a/data/raw/bach/bwv437.mid b/data/raw/bach/bwv437.mid new file mode 100644 index 00000000..3bc5de8f Binary files /dev/null and b/data/raw/bach/bwv437.mid differ diff --git a/data/raw/bach/bwv438.mid b/data/raw/bach/bwv438.mid new file mode 100644 index 00000000..9b901ad5 Binary files /dev/null and b/data/raw/bach/bwv438.mid differ diff --git a/data/raw/bach/bwv44.7.mid b/data/raw/bach/bwv44.7.mid new file mode 100644 index 00000000..57a381f6 Binary files /dev/null and b/data/raw/bach/bwv44.7.mid differ diff --git a/data/raw/bach/bwv45.7.mid b/data/raw/bach/bwv45.7.mid new file mode 100644 index 00000000..2924a140 Binary files /dev/null and b/data/raw/bach/bwv45.7.mid differ diff --git a/data/raw/bach/bwv47.5.mid b/data/raw/bach/bwv47.5.mid new file mode 100644 index 00000000..d676d0df Binary files /dev/null and b/data/raw/bach/bwv47.5.mid differ diff --git a/data/raw/bach/bwv48.3.mid b/data/raw/bach/bwv48.3.mid new file mode 100644 index 00000000..b6cd41e2 Binary files /dev/null and b/data/raw/bach/bwv48.3.mid differ diff --git a/data/raw/bach/bwv48.7.mid b/data/raw/bach/bwv48.7.mid new file mode 100644 index 00000000..af1fd3ca Binary files /dev/null and b/data/raw/bach/bwv48.7.mid differ diff --git a/data/raw/bach/bwv5.7.mid b/data/raw/bach/bwv5.7.mid new file mode 100644 index 00000000..864a920e Binary files /dev/null and b/data/raw/bach/bwv5.7.mid differ diff --git a/data/raw/bach/bwv55.5.mid b/data/raw/bach/bwv55.5.mid new file mode 100644 index 00000000..a1126c8b Binary files /dev/null and b/data/raw/bach/bwv55.5.mid differ diff --git a/data/raw/bach/bwv56.5.mid b/data/raw/bach/bwv56.5.mid new file mode 100644 index 00000000..9ccc7a94 Binary files /dev/null and b/data/raw/bach/bwv56.5.mid differ diff --git a/data/raw/bach/bwv57.8.mid b/data/raw/bach/bwv57.8.mid new file mode 100644 index 00000000..55d00f2f Binary files /dev/null and b/data/raw/bach/bwv57.8.mid differ diff --git a/data/raw/bach/bwv6.6.mid b/data/raw/bach/bwv6.6.mid new file mode 100644 index 00000000..b71f43be Binary files /dev/null and b/data/raw/bach/bwv6.6.mid differ diff --git a/data/raw/bach/bwv60.5.mid b/data/raw/bach/bwv60.5.mid new file mode 100644 index 00000000..a152a19a Binary files /dev/null and b/data/raw/bach/bwv60.5.mid differ diff --git a/data/raw/bach/bwv64.2.mid b/data/raw/bach/bwv64.2.mid new file mode 100644 index 00000000..583503b7 Binary files /dev/null and b/data/raw/bach/bwv64.2.mid differ diff --git a/data/raw/bach/bwv64.8.mid b/data/raw/bach/bwv64.8.mid new file mode 100644 index 00000000..a3d520e1 Binary files /dev/null and b/data/raw/bach/bwv64.8.mid differ diff --git a/data/raw/bach/bwv65.2.mid b/data/raw/bach/bwv65.2.mid new file mode 100644 index 00000000..02b9539d Binary files /dev/null and b/data/raw/bach/bwv65.2.mid differ diff --git a/data/raw/bach/bwv65.7.mid b/data/raw/bach/bwv65.7.mid new file mode 100644 index 00000000..ee9faf08 Binary files /dev/null and b/data/raw/bach/bwv65.7.mid differ diff --git a/data/raw/bach/bwv66.6.mid b/data/raw/bach/bwv66.6.mid new file mode 100644 index 00000000..59eaf70d Binary files /dev/null and b/data/raw/bach/bwv66.6.mid differ diff --git a/data/raw/bach/bwv67.4.mid b/data/raw/bach/bwv67.4.mid new file mode 100644 index 00000000..d0fc2bfc Binary files /dev/null and b/data/raw/bach/bwv67.4.mid differ diff --git a/data/raw/bach/bwv67.7.mid b/data/raw/bach/bwv67.7.mid new file mode 100644 index 00000000..6e01d08a Binary files /dev/null and b/data/raw/bach/bwv67.7.mid differ diff --git a/data/raw/bach/bwv69.6-a.mid b/data/raw/bach/bwv69.6-a.mid new file mode 100644 index 00000000..2e02e608 Binary files /dev/null and b/data/raw/bach/bwv69.6-a.mid differ diff --git a/data/raw/bach/bwv7.7.mid b/data/raw/bach/bwv7.7.mid new file mode 100644 index 00000000..e39e0799 Binary files /dev/null and b/data/raw/bach/bwv7.7.mid differ diff --git a/data/raw/bach/bwv70.7.mid b/data/raw/bach/bwv70.7.mid new file mode 100644 index 00000000..97e8d989 Binary files /dev/null and b/data/raw/bach/bwv70.7.mid differ diff --git a/data/raw/bach/bwv72.6.mid b/data/raw/bach/bwv72.6.mid new file mode 100644 index 00000000..789bda41 Binary files /dev/null and b/data/raw/bach/bwv72.6.mid differ diff --git a/data/raw/bach/bwv73.5.mid b/data/raw/bach/bwv73.5.mid new file mode 100644 index 00000000..d8796bfd Binary files /dev/null and b/data/raw/bach/bwv73.5.mid differ diff --git a/data/raw/bach/bwv74.8.mid b/data/raw/bach/bwv74.8.mid new file mode 100644 index 00000000..179ae0ed Binary files /dev/null and b/data/raw/bach/bwv74.8.mid differ diff --git a/data/raw/bach/bwv77.6.mid b/data/raw/bach/bwv77.6.mid new file mode 100644 index 00000000..07e016ea Binary files /dev/null and b/data/raw/bach/bwv77.6.mid differ diff --git a/data/raw/bach/bwv78.7.mid b/data/raw/bach/bwv78.7.mid new file mode 100644 index 00000000..6211b5f4 Binary files /dev/null and b/data/raw/bach/bwv78.7.mid differ diff --git a/data/raw/bach/bwv80.8.mid b/data/raw/bach/bwv80.8.mid new file mode 100644 index 00000000..573ff7c3 Binary files /dev/null and b/data/raw/bach/bwv80.8.mid differ diff --git a/data/raw/bach/bwv81.7.mid b/data/raw/bach/bwv81.7.mid new file mode 100644 index 00000000..33b9131b Binary files /dev/null and b/data/raw/bach/bwv81.7.mid differ diff --git a/data/raw/bach/bwv83.5.mid b/data/raw/bach/bwv83.5.mid new file mode 100644 index 00000000..ba38bab6 Binary files /dev/null and b/data/raw/bach/bwv83.5.mid differ diff --git a/data/raw/bach/bwv84.5.mid b/data/raw/bach/bwv84.5.mid new file mode 100644 index 00000000..faca02b6 Binary files /dev/null and b/data/raw/bach/bwv84.5.mid differ diff --git a/data/raw/bach/bwv85.6.mid b/data/raw/bach/bwv85.6.mid new file mode 100644 index 00000000..922cafc2 Binary files /dev/null and b/data/raw/bach/bwv85.6.mid differ diff --git a/data/raw/bach/bwv86.6.mid b/data/raw/bach/bwv86.6.mid new file mode 100644 index 00000000..060417eb Binary files /dev/null and b/data/raw/bach/bwv86.6.mid differ diff --git a/data/raw/bach/bwv87.7.mid b/data/raw/bach/bwv87.7.mid new file mode 100644 index 00000000..a0c30fd2 Binary files /dev/null and b/data/raw/bach/bwv87.7.mid differ diff --git a/data/raw/bach/bwv88.7.mid b/data/raw/bach/bwv88.7.mid new file mode 100644 index 00000000..bc25222e Binary files /dev/null and b/data/raw/bach/bwv88.7.mid differ diff --git a/data/raw/bach/bwv89.6.mid b/data/raw/bach/bwv89.6.mid new file mode 100644 index 00000000..edd4b230 Binary files /dev/null and b/data/raw/bach/bwv89.6.mid differ diff --git a/data/raw/bach/bwv9.7.mid b/data/raw/bach/bwv9.7.mid new file mode 100644 index 00000000..5c4fd474 Binary files /dev/null and b/data/raw/bach/bwv9.7.mid differ diff --git a/data/raw/bach/bwv90.5.mid b/data/raw/bach/bwv90.5.mid new file mode 100644 index 00000000..eae07ad1 Binary files /dev/null and b/data/raw/bach/bwv90.5.mid differ diff --git a/data/raw/bach/bwv92.9.mid b/data/raw/bach/bwv92.9.mid new file mode 100644 index 00000000..dfc34820 Binary files /dev/null and b/data/raw/bach/bwv92.9.mid differ diff --git a/data/raw/bach/bwv93.7.mid b/data/raw/bach/bwv93.7.mid new file mode 100644 index 00000000..889cf9a2 Binary files /dev/null and b/data/raw/bach/bwv93.7.mid differ diff --git a/data/raw/bach/bwv94.8.mid b/data/raw/bach/bwv94.8.mid new file mode 100644 index 00000000..f77116f6 Binary files /dev/null and b/data/raw/bach/bwv94.8.mid differ diff --git a/data/raw/bach/bwv96.6.mid b/data/raw/bach/bwv96.6.mid new file mode 100644 index 00000000..1b90dc29 Binary files /dev/null and b/data/raw/bach/bwv96.6.mid differ diff --git a/data/raw/bach/bwv99.6.mid b/data/raw/bach/bwv99.6.mid new file mode 100644 index 00000000..6b97a635 Binary files /dev/null and b/data/raw/bach/bwv99.6.mid differ diff --git a/gpu.theanorc b/gpu.theanorc deleted file mode 100644 index 53921a38..00000000 --- a/gpu.theanorc +++ /dev/null @@ -1,11 +0,0 @@ -[global] -floatX=float32 -device=cuda - -[nvcc] -compiler_bindir=C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin - -[dnn] -enabled=True -include_path=C:\CUDA\v8.0\include -library_path=C:\CUDA\v8.0\lib\x64 diff --git a/live_edit.py b/live_edit.py deleted file mode 100644 index 05055fef..00000000 --- a/live_edit.py +++ /dev/null @@ -1,427 +0,0 @@ -import pygame -import random, math -import numpy as np -import cv2 -import pyaudio -import midi -import wave - -#User constants -device = "cpu" -dir_name = 'History/' -sub_dir_name = 'e2000/' -sample_rate = 48000 -note_dt = 2000 #Num Samples -note_duration = 20000 #Num Samples -note_decay = 5.0 / sample_rate -num_params = 120 -num_measures = 16 -num_sigmas = 5.0 -note_thresh = 32 -use_pca = True -is_ae = True - -background_color = (210, 210, 210) -edge_color = (60, 60, 60) -slider_colors = [(90, 20, 20), (90, 90, 20), (20, 90, 20), (20, 90, 90), (20, 20, 90), (90, 20, 90)] - -note_w = 96 -note_h = 96 -note_pad = 2 - -notes_rows = num_measures / 8 -notes_cols = 8 - -slider_num = min(40, num_params) -slider_h = 200 -slider_pad = 5 -tick_pad = 4 - -control_w = 210 -control_h = 30 -control_pad = 5 -control_num = 3 -control_colors = [(255,0,0), (0,255,0), (0,0,255)] -control_inits = [0.75, 0.5, 0.5] - -#Derived constants -notes_w = notes_cols * (note_w + note_pad*2) -notes_h = notes_rows * (note_h + note_pad*2) -sliders_w = notes_w -sliders_h = slider_h + slider_pad*2 -controls_w = control_w * control_num -controls_h = control_h -window_w = notes_w -window_h = notes_h + sliders_h + controls_h -slider_w = (window_w - slider_pad*2) / slider_num -notes_x = 0 -notes_y = sliders_h -sliders_x = slider_pad -sliders_y = slider_pad -controls_x = (window_w - controls_w) / 2 -controls_y = notes_h + sliders_h - -#Global variables -prev_mouse_pos = None -mouse_pressed = 0 -cur_slider_ix = 0 -cur_control_ix = 0 -volume = 3000 -instrument = 0 -needs_update = True -cur_params = np.zeros((num_params,), dtype=np.float32) -cur_notes = np.zeros((num_measures, note_h, note_w), dtype=np.uint8) -cur_controls = np.array(control_inits, dtype=np.float32) - -#Setup audio stream -audio = pyaudio.PyAudio() -audio_notes = [] -audio_time = 0 -note_time = 0 -note_time_dt = 0 -audio_reset = False -audio_pause = False -def audio_callback(in_data, frame_count, time_info, status): - global audio_time - global audio_notes - global audio_reset - global note_time - global note_time_dt - - #Check if needs restart - if audio_reset: - audio_notes = [] - audio_time = 0 - note_time = 0 - note_time_dt = 0 - audio_reset = False - - #Check if paused - if audio_pause and status is not None: - data = np.zeros((frame_count,), dtype=np.float32) - return (data.tobytes(), pyaudio.paContinue) - - #Find and add any notes in this time window - cur_dt = note_dt - while note_time_dt < audio_time + frame_count: - measure_ix = note_time / note_h - if measure_ix >= num_measures: - break - note_ix = note_time % note_h - notes = np.where(cur_notes[measure_ix, note_ix] >= note_thresh)[0] - for note in notes: - freq = 2 * 38.89 * pow(2.0, note / 12.0) / sample_rate - audio_notes.append((note_time_dt, freq)) - note_time += 1 - note_time_dt += cur_dt - - #Generate the tones - data = np.zeros((frame_count,), dtype=np.float32) - for t,f in audio_notes: - x = np.arange(audio_time - t, audio_time + frame_count - t) - x = np.maximum(x, 0) - - if instrument == 0: - w = np.sign(1 - np.mod(x * f, 2)) #Square - elif instrument == 1: - w = np.mod(x * f - 1, 2) - 1 #Sawtooth - elif instrument == 2: - w = 2*np.abs(np.mod(x * f - 0.5, 2) - 1) - 1 #Triangle - elif instrument == 3: - w = np.sin(x * f * math.pi) #Sine - - #w = np.floor(w*8)/8 - w[x == 0] = 0 - w *= volume * np.exp(-x*note_decay) - data += w - data = np.clip(data, -32000, 32000).astype(np.int16) - - #Remove notes that are too old - audio_time += frame_count - audio_notes = [(t,f) for t,f in audio_notes if audio_time < t + note_duration] - - #Reset if loop occurs - if note_time / note_h >= num_measures: - audio_time = 0 - note_time = 0 - note_time_dt = 0 - audio_notes = [] - - #Return the sound clip - return (data.tobytes(), pyaudio.paContinue) - -#Keras -print "Loading Keras..." -import os -os.environ['THEANORC'] = "./" + device + ".theanorc" -os.environ['KERAS_BACKEND'] = "theano" -import theano -print "Theano Version: " + theano.__version__ -import keras -print "Keras Version: " + keras.__version__ -from keras.models import Model, Sequential, load_model -from keras.layers import Dense, Activation, Dropout, Flatten, Reshape -from keras.layers.convolutional import Conv2D, Conv2DTranspose, ZeroPadding2D -from keras.layers.pooling import MaxPooling2D -from keras.layers.noise import GaussianNoise -from keras.layers.local import LocallyConnected2D -from keras.optimizers import Adam, RMSprop, SGD -from keras.regularizers import l2 -from keras.losses import binary_crossentropy -from keras.layers.advanced_activations import ELU -from keras.preprocessing.image import ImageDataGenerator -from keras.utils import plot_model -from keras import backend as K -K.set_image_data_format('channels_first') - -print "Loading Encoder..." -model = load_model(dir_name + 'model.h5') -enc = K.function([model.get_layer('encoder').input, K.learning_phase()], - [model.layers[-1].output]) -enc_model = Model(inputs=model.input, outputs=model.get_layer('pre_encoder').output) - -print "Loading Statistics..." -means = np.load(dir_name + sub_dir_name + 'means.npy') -evals = np.load(dir_name + sub_dir_name + 'evals.npy') -evecs = np.load(dir_name + sub_dir_name + 'evecs.npy') -stds = np.load(dir_name + sub_dir_name + 'stds.npy') - -print "Loading Songs..." -y_samples = np.load('samples.npy') -y_lengths = np.load('lengths.npy') - -#Open a window -pygame.init() -pygame.font.init() -screen = pygame.display.set_mode((window_w, window_h)) -notes_surface = screen.subsurface((notes_x, notes_y, notes_w, notes_h)) -pygame.display.set_caption('MusicEdit') -font = pygame.font.SysFont("monospace", 15) - -#Start the audio stream -audio_stream = audio.open( - format=audio.get_format_from_width(2), - channels=1, - rate=sample_rate, - output=True, - stream_callback=audio_callback) -audio_stream.start_stream() - -def update_mouse_click(mouse_pos): - global cur_slider_ix - global cur_control_ix - global mouse_pressed - x = (mouse_pos[0] - sliders_x) - y = (mouse_pos[1] - sliders_y) - - if x >= 0 and y >= 0 and x < sliders_w and y < sliders_h: - cur_slider_ix = x / slider_w - mouse_pressed = 1 - - x = (mouse_pos[0] - controls_x) - y = (mouse_pos[1] - controls_y) - if x >= 0 and y >= 0 and x < controls_w and y < controls_h: - cur_control_ix = x / control_w - mouse_pressed = 2 - -def apply_controls(): - global note_thresh - global note_dt - global volume - - note_thresh = (1.0 - cur_controls[0]) * 200 + 10 - note_dt = (1.0 - cur_controls[1]) * 1800 + 200 - volume = cur_controls[2] * 6000 - -def update_mouse_move(mouse_pos): - global needs_update - - if mouse_pressed == 1: - y = (mouse_pos[1] - sliders_y) - if y >= 0 and y <= slider_h: - val = (float(y) / slider_h - 0.5) * (num_sigmas * 2) - cur_params[cur_slider_ix] = val - needs_update = True - elif mouse_pressed == 2: - x = (mouse_pos[0] - (controls_x + cur_control_ix*control_w)) - if x >= control_pad and x <= control_w - control_pad: - val = float(x - control_pad) / (control_w - control_pad*2) - cur_controls[cur_control_ix] = val - apply_controls() - -def draw_controls(): - for i in xrange(control_num): - x = controls_x + i * control_w + control_pad - y = controls_y + control_pad - w = control_w - control_pad*2 - h = control_h - control_pad*2 - col = control_colors[i] - - pygame.draw.rect(screen, col, (x, y, int(w*cur_controls[i]), h)) - pygame.draw.rect(screen, (0,0,0), (x, y, w, h), 1) - -def draw_sliders(): - for i in xrange(slider_num): - slider_color = slider_colors[i % len(slider_colors)] - x = sliders_x + i * slider_w - y = sliders_y - - cx = x + slider_w / 2 - cy_1 = y - cy_2 = y + slider_h - pygame.draw.line(screen, slider_color, (cx, cy_1), (cx, cy_2)) - - cx_1 = x + tick_pad - cx_2 = x + slider_w - tick_pad - for j in xrange(int(num_sigmas * 2 + 1)): - ly = y + slider_h/2.0 + (j-num_sigmas)*slider_h/(num_sigmas*2.0) - ly = int(ly) - col = (0,0,0) if j - num_sigmas == 0 else slider_color - pygame.draw.line(screen, col, (cx_1, ly), (cx_2, ly)) - - py = y + int((cur_params[i] / (num_sigmas * 2) + 0.5) * slider_h) - pygame.draw.circle(screen, slider_color, (cx, py), (slider_w - tick_pad)/2) - -def notes_to_img(notes): - output = np.full((3, notes_h, notes_w), 64, dtype=np.uint8) - - for i in xrange(notes_rows): - for j in xrange(notes_cols): - x = note_pad + j*(note_w + note_pad*2) - y = note_pad + i*(note_h + note_pad*2) - ix = i*notes_cols + j - - measure = np.rot90(notes[ix]) - played_only = np.where(measure >= note_thresh, 255, 0) - output[0,y:y+note_h,x:x+note_w] = np.minimum(measure * (255.0 / note_thresh), 255.0) - output[1,y:y+note_h,x:x+note_w] = played_only - output[2,y:y+note_h,x:x+note_w] = played_only - - return np.transpose(output, (2, 1, 0)) - -def draw_notes(): - pygame.surfarray.blit_array(notes_surface, notes_to_img(cur_notes)) - - measure_ix = note_time / note_h - note_ix = note_time % note_h - x = notes_x + note_pad + (measure_ix % notes_cols) * (note_w + note_pad*2) + note_ix - y = notes_y +note_pad + (measure_ix / notes_cols) * (note_h + note_pad*2) - pygame.draw.rect(screen, (255,255,0), (x, y, 4, note_h), 0) - -#Main loop -running = True -rand_ix = 0 -cur_len = 0 -apply_controls() -while running: - #Process events - for event in pygame.event.get(): - if event.type == pygame.QUIT: - running = False - break - elif event.type == pygame.MOUSEBUTTONDOWN: - if pygame.mouse.get_pressed()[0]: - prev_mouse_pos = pygame.mouse.get_pos() - update_mouse_click(prev_mouse_pos) - update_mouse_move(prev_mouse_pos) - elif pygame.mouse.get_pressed()[2]: - cur_params = np.zeros((num_params,), dtype=np.float32) - needs_update = True - elif event.type == pygame.MOUSEBUTTONUP: - mouse_pressed = 0 - prev_mouse_pos = None - elif event.type == pygame.MOUSEMOTION and mouse_pressed > 0: - update_mouse_move(pygame.mouse.get_pos()) - elif event.type == pygame.KEYDOWN: - if event.key == pygame.K_r: - cur_params = np.clip(np.random.normal(0.0, 1.0, (num_params,)), -num_sigmas, num_sigmas) - needs_update = True - audio_reset = True - if event.key == pygame.K_e: - cur_params = np.clip(np.random.normal(0.0, 2.0, (num_params,)), -num_sigmas, num_sigmas) - needs_update = True - audio_reset = True - if event.key == pygame.K_o: - print "RandIx: " + str(rand_ix) - if is_ae: - example_song = y_samples[cur_len:cur_len + num_measures] - cur_notes = example_song * 255 - x = enc_model.predict(np.expand_dims(example_song, 0), batch_size=1)[0] - cur_len += y_lengths[rand_ix] - rand_ix += 1 - else: - rand_ix = np.array([rand_ix], dtype=np.int64) - x = enc_model.predict(rand_ix, batch_size=1)[0] - rand_ix = (rand_ix + 1) % model.layers[0].input_dim - - if use_pca: - cur_params = np.dot(x - means, evecs.T) / evals - else: - cur_params = (x - means) / stds - - needs_update = True - audio_reset = True - if event.key == pygame.K_g: - audio_pause = True - audio_reset = True - midi.samples_to_midi(cur_notes, 'live.mid', 16, note_thresh) - save_audio = '' - while True: - save_audio += audio_callback(None, 1024, None, None)[0] - if audio_time == 0: - break - wave_output = wave.open('live.wav', 'w') - wave_output.setparams((1, 2, sample_rate, 0, 'NONE', 'not compressed')) - wave_output.writeframes(save_audio) - wave_output.close() - audio_pause = False - if event.key == pygame.K_ESCAPE: - running = False - break - if event.key == pygame.K_SPACE: - audio_pause = not audio_pause - if event.key == pygame.K_TAB: - audio_reset = True - if event.key == pygame.K_1: - instrument = 0 - if event.key == pygame.K_2: - instrument = 1 - if event.key == pygame.K_3: - instrument = 2 - if event.key == pygame.K_4: - instrument = 3 - if event.key == pygame.K_c: - y = np.expand_dims(np.where(cur_notes > note_thresh, 1, 0), 0) - x = enc_model.predict(y)[0] - if use_pca: - cur_params = np.dot(x - means, evecs.T) / evals - else: - cur_params = (x - means) / stds - needs_update = True - - #Check if we need an update - if needs_update: - if use_pca: - x = means + np.dot(cur_params * evals, evecs) - else: - x = means + stds * cur_params - x = np.expand_dims(x, axis=0) - y = enc([x, 0])[0][0] - cur_notes = (y * 255.0).astype(np.uint8) - needs_update = False - - #Draw to the screen - screen.fill(background_color) - draw_notes() - draw_sliders() - draw_controls() - - #Flip the screen buffer - pygame.display.flip() - pygame.time.wait(10) - -#Close the audio stream -audio_stream.stop_stream() -audio_stream.close() -audio.terminate() - diff --git a/load_songs.py b/load_songs.py deleted file mode 100644 index 48bde9f1..00000000 --- a/load_songs.py +++ /dev/null @@ -1,35 +0,0 @@ -import midi -import os -import util -import numpy as np - -patterns = {} -dirs = ["Music", "download", "rag", "pop", "misc"] -all_samples = [] -all_lens = [] -print "Loading Songs..." -for dir in dirs: - for root, subdirs, files in os.walk(dir): - for file in files: - path = root + "\\" + file - if not (path.endswith('.mid') or path.endswith('.midi')): - continue - try: - samples = midi.midi_to_samples(path) - except: - print "ERROR ", path - continue - if len(samples) < 8: - continue - - samples, lens = util.generate_add_centered_transpose(samples) - all_samples += samples - all_lens += lens - -assert(sum(all_lens) == len(all_samples)) -print "Saving " + str(len(all_samples)) + " samples..." -all_samples = np.array(all_samples, dtype=np.uint8) -all_lens = np.array(all_lens, dtype=np.uint32) -np.save('samples.npy', all_samples) -np.save('lengths.npy', all_lens) -print "Done" diff --git a/midi.py b/midi.py deleted file mode 100644 index 404e6731..00000000 --- a/midi.py +++ /dev/null @@ -1,93 +0,0 @@ -from mido import MidiFile, MidiTrack, Message -import numpy as np - -num_notes = 96 -samples_per_measure = 96 - -def midi_to_samples(fname): - has_time_sig = False - flag_warning = False - mid = MidiFile(fname) - ticks_per_beat = mid.ticks_per_beat - ticks_per_measure = 4 * ticks_per_beat - - for i, track in enumerate(mid.tracks): - for msg in track: - if msg.type == 'time_signature': - new_tpm = msg.numerator * ticks_per_beat * 4 / msg.denominator - if has_time_sig and new_tpm != ticks_per_measure: - flag_warning = True - ticks_per_measure = new_tpm - has_time_sig = True - if flag_warning: - print " ^^^^^^ WARNING ^^^^^^" - print " " + fname - print " Detected multiple distinct time signatures." - print " ^^^^^^ WARNING ^^^^^^" - return [] - - all_notes = {} - for i, track in enumerate(mid.tracks): - abs_time = 0 - for msg in track: - abs_time += msg.time - if msg.type == 'note_on': - if msg.velocity == 0: - continue - note = msg.note - (128 - num_notes)/2 - assert(note >= 0 and note < num_notes) - if note not in all_notes: - all_notes[note] = [] - else: - single_note = all_notes[note][-1] - if len(single_note) == 1: - single_note.append(single_note[0] + 1) - all_notes[note].append([abs_time * samples_per_measure / ticks_per_measure]) - elif msg.type == 'note_off': - if len(all_notes[note][-1]) != 1: - continue - all_notes[note][-1].append(abs_time * samples_per_measure / ticks_per_measure) - for note in all_notes: - for start_end in all_notes[note]: - if len(start_end) == 1: - start_end.append(start_end[0] + 1) - samples = [] - for note in all_notes: - for start, end in all_notes[note]: - sample_ix = start / samples_per_measure - while len(samples) <= sample_ix: - samples.append(np.zeros((samples_per_measure, num_notes), dtype=np.uint8)) - sample = samples[sample_ix] - start_ix = start - sample_ix * samples_per_measure - if False: - end_ix = min(end - sample_ix * samples_per_measure, samples_per_measure) - while start_ix < end_ix: - sample[start_ix, note] = 1 - start_ix += 1 - else: - sample[start_ix, note] = 1 - return samples - -def samples_to_midi(samples, fname, ticks_per_sample, thresh=0.5): - mid = MidiFile() - track = MidiTrack() - mid.tracks.append(track) - ticks_per_beat = mid.ticks_per_beat - ticks_per_measure = 4 * ticks_per_beat - ticks_per_sample = ticks_per_measure / samples_per_measure - abs_time = 0 - last_time = 0 - for sample in samples: - for y in xrange(sample.shape[0]): - abs_time += ticks_per_sample - for x in xrange(sample.shape[1]): - note = x + (128 - num_notes)/2 - if sample[y,x] >= thresh and (y == 0 or sample[y-1,x] < thresh): - delta_time = abs_time - last_time - track.append(Message('note_on', note=note, velocity=127, time=delta_time)) - last_time = abs_time - if sample[y,x] >= thresh and (y == sample.shape[0]-1 or sample[y+1,x] < thresh): - delta_time = abs_time - last_time - track.append(Message('note_off', note=note, velocity=127, time=delta_time)) - last_time = abs_time - mid.save(fname) diff --git a/midi_utils.py b/midi_utils.py new file mode 100644 index 00000000..ab44d2f8 --- /dev/null +++ b/midi_utils.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Utils to read and write midi. +""" + +from mido import MidiFile, MidiTrack, Message +import numpy as np + + +def midi_to_samples(file_name, encode_length=False, num_notes=96, samples_per_measure=96): + """ + Turn a midi file into a sample. + :param file_name: + :param encode_length: + :param num_notes: + :param samples_per_measure: + :return: + """ + has_time_sig = False + mid = MidiFile(file_name) + + ticks_per_beat = mid.ticks_per_beat # get ticks per beat + ticks_per_measure = 4 * ticks_per_beat # get ticks per measure + + # detect the time signature of the midi + for track in mid.tracks: + for msg in track: + if msg.type == 'time_signature': + new_tpm = ticks_per_measure * msg.numerator / msg.denominator # adapt ticks per measure of this specific song + + # skip if we find multiple time signatures in the song + if has_time_sig and new_tpm != ticks_per_measure: + raise NotImplementedError('Multiple time signatures not supported') + + ticks_per_measure = new_tpm + has_time_sig = True + + # turn tracks into pianoroll representation + all_notes = {} + for track in mid.tracks: + + abs_time = 0 + for msg in track: + abs_time += msg.time # step time forward + + # we skip programs 0x70-0x7F which are percussion and sound effects + if msg.type == 'program_change' and msg.program >= 0x70: + break + + # if a note starts + if msg.type == 'note_on': + + # we skip notes without a velocity (basically how strong a note is played to make it sound human) + if msg.velocity == 0: + continue + + # transform the notes into the 96 heights + note = msg.note - (128 - num_notes) / 2 + if note < 0 or note >= num_notes: # ignore a note that is outside of that range + print('Ignoring', file_name, 'note is outside 0-%d range' % (num_notes - 1)) + return [] + + # count the number of played notes per pitch + if note not in all_notes: + all_notes[note] = [] + else: + single_note = all_notes[note][-1] + if len(single_note) == 1: + single_note.append(single_note[0] + 1) + + # store the time a note has been played + all_notes[note].append([abs_time * samples_per_measure / ticks_per_measure]) + + # if a note ends + elif msg.type == 'note_off': + + # if the note has already ended before (note_on, note_off, note_off), we skip the event + if len(all_notes[note][-1]) != 1: + continue + # store the time a note stops playing + all_notes[note][-1].append(abs_time * samples_per_measure / ticks_per_measure) + + # any note did not end playing, we end it one time tick later + for note in all_notes: + for start_end in all_notes[note]: + if len(start_end) == 1: + start_end.append(start_end[0] + 1) + + # put the notes into their respective sample/measure panel (96 x 96) + samples = [] + for note in all_notes: + for start, end in all_notes[note]: + sample_ix = int(start / samples_per_measure) # find the sample/measure this belongs into + assert (sample_ix < 1024 * 1024) + + # fill in silence until the appropriate sample/measure is reached + while len(samples) <= sample_ix: + samples.append(np.zeros((samples_per_measure, num_notes), dtype=np.uint8)) + + # get sample and find its start to encode the start of the note + sample = samples[sample_ix] + start_ix = int(start - sample_ix * samples_per_measure) + sample[start_ix, int(note)] = 1 + + # play note until it ends if we encode length + if encode_length: + end_ix = min(end - sample_ix * samples_per_measure, samples_per_measure) + while start_ix < end_ix: + sample[start_ix, int(note)] = 1 + start_ix += 1 + + return samples + + +def samples_to_midi(samples, file_name, threshold=0.5, num_notes=96, samples_per_measure=96): + """ + Turn the samples/measures back into midi. + :param samples: + :param file_name: + :param threshold: + :param num_notes: + :param samples_per_measure: + :return: + """ + # TODO: Encode the certainties of the notes into the volume of the midi for the notes that are above threshold + + mid = MidiFile() + track = MidiTrack() + mid.tracks.append(track) + + ticks_per_beat = mid.ticks_per_beat + ticks_per_measure = 4 * ticks_per_beat + ticks_per_sample = ticks_per_measure / samples_per_measure + + # add instrument for track + # https://en.wikipedia.org/wiki/General_MIDI#Program_change_events + piano = 1 + honky_tonk_piano = 4 + xylophone = 14 + program_message = Message('program_change', program=piano, time=0, channel=0) + track.append(program_message) + + abs_time = 0 + last_time = 0 + for sample in samples: + for y in range(sample.shape[0]): + abs_time += ticks_per_sample + for x in range(sample.shape[1]): + note = x + (128 - num_notes) / 2 + + if sample[y, x] >= threshold and (y == 0 or sample[y - 1, x] < threshold): + delta_time = abs_time - last_time + track.append(Message('note_on', note=int(note), velocity=127, time=int(delta_time))) + last_time = abs_time + + if sample[y, x] >= threshold and (y == sample.shape[0] - 1 or sample[y + 1, x] < threshold): + delta_time = abs_time - last_time + track.append(Message('note_off', note=int(note), velocity=127, time=int(delta_time))) + last_time = abs_time + mid.save(file_name) diff --git a/models.py b/models.py new file mode 100644 index 00000000..2e9a94f5 --- /dev/null +++ b/models.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +The models used for music generation. +""" + +from keras import backend as K +from keras.layers import Input, Dense, Activation, Dropout, Flatten, Reshape, TimeDistributed, Lambda +from keras.layers.embeddings import Embedding +from keras.layers.normalization import BatchNormalization +from keras.models import Model + + +def vae_sampling(args): + z_mean, z_log_sigma_sq, vae_b1 = args + epsilon = K.random_normal(shape=K.shape(z_mean), mean=0.0, stddev=vae_b1) + return z_mean + K.exp(z_log_sigma_sq * 0.5) * epsilon + + +def create_autoencoder_model(input_shape, latent_space_size, dropout_rate, max_windows, batchnorm_momentum, use_vae=False, vae_b1=0.02, use_embedding=False, embedding_input_shape=None, embedding_shape=None): + """ + Create larger autoencoder with the options of making it variational and embedding. + :param input_shape: + :param latent_space_size: + :param dropout_rate: + :param max_windows: + :param batchnorm_momentum: + :param use_vae: + :param vae_b1: + :param use_embedding: + :param embedding_input_shape: + :param embedding_shape: + :return: + """ + if use_embedding: + x_in = Input(shape=embedding_input_shape) + print((None,) + embedding_input_shape) + + x = Embedding(embedding_shape, latent_space_size, input_length=1)(x_in) + x = Flatten(name='encoder')(x) + else: + x_in = Input(shape=input_shape) + print((None,) + input_shape) + + x = Reshape((input_shape[0], -1))(x_in) + print(K.int_shape(x)) + + x = TimeDistributed(Dense(2000, activation='relu'))(x) + print(K.int_shape(x)) + + x = TimeDistributed(Dense(200, activation='relu'))(x) + print(K.int_shape(x)) + + x = Flatten()(x) + print(K.int_shape(x)) + + x = Dense(1600, activation='relu')(x) + print(K.int_shape(x)) + + if use_vae: + z_mean = Dense(latent_space_size)(x) + z_log_sigma_sq = Dense(latent_space_size)(x) + x = Lambda(vae_sampling, output_shape=(latent_space_size,), name='encoder')([z_mean, z_log_sigma_sq, vae_b1]) + else: + x = Dense(latent_space_size)(x) + x = BatchNormalization(momentum=batchnorm_momentum, name='encoder')(x) + print(K.int_shape(x)) + + # LATENT SPACE + + x = Dense(1600, name='decoder')(x) + x = BatchNormalization(momentum=batchnorm_momentum)(x) + x = Activation('relu')(x) + if dropout_rate > 0: + x = Dropout(dropout_rate)(x) + print(K.int_shape(x)) + + x = Dense(max_windows * 200)(x) + print(K.int_shape(x)) + x = Reshape((max_windows, 200))(x) + x = TimeDistributed(BatchNormalization(momentum=batchnorm_momentum))(x) + x = Activation('relu')(x) + if dropout_rate > 0: + x = Dropout(dropout_rate)(x) + print(K.int_shape(x)) + + x = TimeDistributed(Dense(2000))(x) + x = TimeDistributed(BatchNormalization(momentum=batchnorm_momentum))(x) + x = Activation('relu')(x) + if dropout_rate > 0: + x = Dropout(dropout_rate)(x) + print(K.int_shape(x)) + + x = TimeDistributed(Dense(input_shape[1] * input_shape[2], activation='sigmoid'))(x) + print(K.int_shape(x)) + x = Reshape((input_shape[0], input_shape[1], input_shape[2]))(x) + print(K.int_shape(x)) + + model = Model(x_in, x) + + return model diff --git a/music_utils.py b/music_utils.py new file mode 100644 index 00000000..ab6ced68 --- /dev/null +++ b/music_utils.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Utils to edit music. +""" + +import numpy as np + + +def find_sample_range(samples): + """ + Find sample range. + :param samples: + :return: + """ + + # merge all samples + merged_sample = np.zeros_like(samples[0]) + for sample in samples: + merged_sample = np.maximum(merged_sample, sample) + + # get all pitches being played + merged_sample = np.amax(merged_sample, axis=0) + + # get min and max note + min_note = np.argmax(merged_sample) + max_note = merged_sample.shape[0] - np.argmax(merged_sample[::-1]) + return min_note, max_note + + +def generate_centered_transpose(samples): + """ + Center samples towards the middle of the pitch range. + :param samples: + :return: + """ + num_notes = samples[0].shape[1] + min_note, max_note = find_sample_range(samples) + + # find deviation from pitch center + center_deviation = num_notes / 2 - (max_note + min_note) / 2 + out_samples = samples + out_lengths = [len(samples), len(samples)] + + # center every sample by moving it by center_deviation + for i in range(len(samples)): + out_sample = np.zeros_like(samples[i]) + out_sample[:, min_note + int(center_deviation):max_note + int(center_deviation)] = samples[i][:, min_note:max_note] + out_samples.append(out_sample) + return out_samples, out_lengths diff --git a/plot_utils.py b/plot_utils.py new file mode 100644 index 00000000..7f9520f8 --- /dev/null +++ b/plot_utils.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Plot utility functions. +""" + +import os +import cv2 +import numpy as np + + +def plot_sample(file_name, sample, threshold=None): + if threshold is not None: + inverted = np.where(sample > threshold, 0, 1) + else: + inverted = 1.0 - sample + cv2.imwrite(file_name, inverted * 255) + + +def plot_samples(folder, samples, threshold=None): + if not os.path.exists(folder): + os.makedirs(folder) + + for i in range(samples.shape[0]): + plot_sample(folder + '/s' + str(i) + '.png', samples[i], threshold) diff --git a/preprocess_songs.py b/preprocess_songs.py new file mode 100644 index 00000000..7000bdbd --- /dev/null +++ b/preprocess_songs.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Load songs from midi, preprocess and save them in numpy format. +""" + +import midi_utils +import os +import music_utils +import numpy as np +import argparse + + +def preprocess_songs(data_folders): + """ + Load and preprocess the songs from the data folders and turn them into a dataset of samples/pitches and lengths of the tones. + :param data_folders: + :return: + """ + + all_samples = [] + all_lengths = [] + + # keep some statistics + succeeded = 0 + failed = 0 + ignored = 0 + + # load songs + print("Loading songs...") + # walk folders and look for midi files + for folder in data_folders: + for root, _, files in os.walk(folder): + for file in files: + path = os.path.join(root, file) + if not (path.endswith('.mid') or path.endswith('.midi')): + continue + + # turn midi into samples + try: + samples = midi_utils.midi_to_samples(path) + except Exception as e: + print("ERROR ", path) + print(e) + failed += 1 + continue + + # if the midi does not produce the minimal number of sample/measures, we skip it + if len(samples) < 16: + print('WARN', path, 'Sample too short, unused') + ignored += 1 + continue + + # transpose samples (center them in full range to get more training samples for the same tones) + samples, lengths = music_utils.generate_centered_transpose(samples) + all_samples += samples + all_lengths += lengths + print('SUCCESS', path, len(samples), 'samples') + succeeded += 1 + + assert (sum(all_lengths) == len(all_samples)) # assert equal number of samples and lengths + + # save all to disk + print("Saving " + str(len(all_samples)) + " samples...") + all_samples = np.array(all_samples, dtype=np.uint8) # reduce size when saving + all_lengths = np.array(all_lengths, dtype=np.uint32) + np.save('data/interim/samples.npy', all_samples) + np.save('data/interim/lengths.npy', all_lengths) + print('Done: ', succeeded, 'succeded,', ignored, 'ignored,', failed, 'failed of', succeeded + ignored + failed, 'in total') + + +if __name__ == "__main__": + # configure parser and parse arguments + parser = argparse.ArgumentParser(description='Load songs, preprocess them and put them into a dataset.') + parser.add_argument('--data_folder', default=["data/raw"], type=str, help='The path to the midi data', action='append') + + args = parser.parse_args() + preprocess_songs(args.data_folder) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..730f2daf --- /dev/null +++ b/requirements.txt @@ -0,0 +1,13 @@ +matplotlib==3.0.2 +pygame==1.9.6 +pyaudio==0.2.11 + +pydot==1.4.1 +keras==2.2.4 +tensorflow==1.14.0 +pyaudio==0.2.11 +numpy==1.16.4 + +mido==1.2.9 + +argparse==1.4.0 \ No newline at end of file diff --git a/results/.gitkeep b/results/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/run_pipeline.ipynb b/run_pipeline.ipynb new file mode 100644 index 00000000..33dbc8bf --- /dev/null +++ b/run_pipeline.ipynb @@ -0,0 +1,79 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Run the full pipeline to train a composer model" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Uncomment the line below and run this cell to get your data from github into colab (only runnable in colab, not ordinary jupyter notebook):\n", + "! git clone https://github.com/benelot/Composer.git && mv Composer/* . && rm Composer -r" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from load_songs import load_songs\n", + "\n", + "data_folder = 'data/raw'\n", + "load_songs(data_folder)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from train import train\n", + "\n", + "train()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from live_edit import play\n", + "\n", + "sub_dir_name = 'e1/'\n", + "play()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 2", + "language": "python", + "name": "python2" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/train.py b/train.py index 232d63ed..49971fcd 100644 --- a/train.py +++ b/train.py @@ -1,346 +1,374 @@ -import sys, random, os +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +Train an autoencoder model to learn to encode songs. +""" + +import random + import numpy as np from matplotlib import pyplot as plt -import pydot -import cv2 -import util -import midi -NUM_EPOCHS = 2000 -LR = 0.001 +import midi_utils +import plot_utils +import models + +import argparse + +# Load Keras +print("Loading keras...") +import os +import keras + +print("Keras version: " + keras.__version__) + +from keras.models import Model, load_model +from keras.utils import plot_model +from keras import backend as K +from keras.losses import binary_crossentropy +from keras.optimizers import Adam, RMSprop + +EPOCHS_QTY = 2000 +EPOCHS_TO_SAVE = [1, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 120, 140, 160, 180, 200, 250, 300, 350, 400, 450] +LEARNING_RATE = 0.001 # learning rate CONTINUE_TRAIN = False -PLAY_ONLY = False -USE_EMBEDDING = False -USE_VAE = False +GENERATE_ONLY = False + WRITE_HISTORY = True NUM_RAND_SONGS = 10 -DO_RATE = 0.1 -BN_M = 0.9 + +# network params +DROPOUT_RATE = 0.1 +BATCHNORM_MOMENTUM = 0.9 # weighted normalization with the past +USE_EMBEDDING = False +USE_VAE = False VAE_B1 = 0.02 VAE_B2 = 0.1 BATCH_SIZE = 350 -MAX_LENGTH = 16 -PARAM_SIZE = 120 +MAX_WINDOWS = 16 # the maximal number of measures a song can have +LATENT_SPACE_SIZE = 120 NUM_OFFSETS = 16 if USE_EMBEDDING else 1 -def plotScores(scores, fname, on_top=True): - plt.clf() - ax = plt.gca() - ax.yaxis.tick_right() - ax.yaxis.set_ticks_position('both') - ax.yaxis.grid(True) - plt.plot(scores) - plt.ylim([0.0, 0.009]) - plt.xlabel('Epoch') - loc = ('upper right' if on_top else 'lower right') - plt.draw() - plt.savefig(fname) - -def save_config(): - with open('config.txt', 'w') as fout: - fout.write('LR: ' + str(LR) + '\n') - fout.write('BN_M: ' + str(BN_M) + '\n') - fout.write('BATCH_SIZE: ' + str(BATCH_SIZE) + '\n') - fout.write('NUM_OFFSETS: ' + str(NUM_OFFSETS) + '\n') - fout.write('DO_RATE: ' + str(DO_RATE) + '\n') - fout.write('num_songs: ' + str(num_songs) + '\n') - fout.write('optimizer: ' + type(model.optimizer).__name__ + '\n') - -################################### -# Load Keras -################################### -print "Loading Keras..." -import os, math -os.environ['THEANORC'] = "./gpu.theanorc" -os.environ['KERAS_BACKEND'] = "theano" -import theano -print "Theano Version: " + theano.__version__ - -import keras -print "Keras Version: " + keras.__version__ -from keras.layers import Input, Dense, Activation, Dropout, Flatten, Reshape, Permute, RepeatVector, ActivityRegularization, TimeDistributed, Lambda, SpatialDropout1D -from keras.layers.convolutional import Conv1D, Conv2D, Conv2DTranspose, UpSampling2D, ZeroPadding2D -from keras.layers.embeddings import Embedding -from keras.layers.local import LocallyConnected2D -from keras.layers.pooling import MaxPooling2D, AveragePooling2D -from keras.layers.noise import GaussianNoise -from keras.layers.normalization import BatchNormalization -from keras.layers.recurrent import LSTM, SimpleRNN -from keras.initializers import RandomNormal -from keras.losses import binary_crossentropy -from keras.models import Model, Sequential, load_model -from keras.optimizers import Adam, RMSprop, SGD -from keras.preprocessing.image import ImageDataGenerator -from keras.regularizers import l2 -from keras.utils import plot_model -from keras import backend as K -from keras import regularizers -from keras.engine.topology import Layer K.set_image_data_format('channels_first') -#Fix the random seed so that training comparisons are easier to make +# Fix the random seed so that training comparisons are easier to make np.random.seed(0) random.seed(0) -if WRITE_HISTORY: - #Create folder to save models into - if not os.path.exists('History'): - os.makedirs('History') - -################################### -# Load Dataset -################################### -print "Loading Data..." -y_samples = np.load('samples.npy') -y_lengths = np.load('lengths.npy') -num_samples = y_samples.shape[0] -num_songs = y_lengths.shape[0] -print "Loaded " + str(num_samples) + " samples from " + str(num_songs) + " songs." -print np.sum(y_lengths) -assert(np.sum(y_lengths) == num_samples) - -print "Padding Songs..." -x_shape = (num_songs * NUM_OFFSETS, 1) -y_shape = (num_songs * NUM_OFFSETS, MAX_LENGTH) + y_samples.shape[1:] -x_orig = np.expand_dims(np.arange(x_shape[0]), axis=-1) -y_orig = np.zeros(y_shape, dtype=y_samples.dtype) -cur_ix = 0 -for i in xrange(num_songs): - for ofs in xrange(NUM_OFFSETS): - ix = i*NUM_OFFSETS + ofs - end_ix = cur_ix + y_lengths[i] - for j in xrange(MAX_LENGTH): - k = (j + ofs) % (end_ix - cur_ix) - y_orig[ix,j] = y_samples[cur_ix + k] - cur_ix = end_ix -assert(end_ix == num_samples) -x_train = np.copy(x_orig) -y_train = np.copy(y_orig) - -def to_song(encoded_output): - return np.squeeze(decoder([np.round(encoded_output), 0])[0]) - -def reg_mean_std(x): - s = K.log(K.sum(x * x)) - return s*s - -def vae_sampling(args): - z_mean, z_log_sigma_sq = args - epsilon = K.random_normal(shape=K.shape(z_mean), mean=0.0, stddev=VAE_B1) - return z_mean + K.exp(z_log_sigma_sq * 0.5) * epsilon - -def vae_loss(x, x_decoded_mean): - xent_loss = binary_crossentropy(x, x_decoded_mean) - kl_loss = VAE_B2 * K.mean(1 + z_log_sigma_sq - K.square(z_mean) - K.exp(z_log_sigma_sq), axis=None) - return xent_loss - kl_loss - -test_ix = 0 -y_test_song = np.copy(y_train[test_ix:test_ix+1]) -x_test_song = np.copy(x_train[test_ix:test_ix+1]) -midi.samples_to_midi(y_test_song[0], 'gt.mid', 16) - -################################### -# Create Model -################################### -if CONTINUE_TRAIN or PLAY_ONLY: - print "Loading Model..." - model = load_model('model.h5', custom_objects=custom_objects) -else: - print "Building Model..." - - if USE_EMBEDDING: - x_in = Input(shape=x_shape[1:]) - print (None,) + x_shape[1:] - x = Embedding(x_train.shape[0], PARAM_SIZE, input_length=1)(x_in) - x = Flatten(name='pre_encoder')(x) - else: - x_in = Input(shape=y_shape[1:]) - print (None,) + y_shape[1:] - x = Reshape((y_shape[1], -1))(x_in) - print K.int_shape(x) - - x = TimeDistributed(Dense(2000, activation='relu'))(x) - print K.int_shape(x) - - x = TimeDistributed(Dense(200, activation='relu'))(x) - print K.int_shape(x) - - x = Flatten()(x) - print K.int_shape(x) - - x = Dense(1600, activation='relu')(x) - print K.int_shape(x) - - if USE_VAE: - z_mean = Dense(PARAM_SIZE)(x) - z_log_sigma_sq = Dense(PARAM_SIZE)(x) - x = Lambda(vae_sampling, output_shape=(PARAM_SIZE,), name='pre_encoder')([z_mean, z_log_sigma_sq]) - else: - x = Dense(PARAM_SIZE)(x) - x = BatchNormalization(momentum=BN_M, name='pre_encoder')(x) - print K.int_shape(x) - - x = Dense(1600, name='encoder')(x) - x = BatchNormalization(momentum=BN_M)(x) - x = Activation('relu')(x) - if DO_RATE > 0: - x = Dropout(DO_RATE)(x) - print K.int_shape(x) - - x = Dense(MAX_LENGTH * 200)(x) - print K.int_shape(x) - x = Reshape((MAX_LENGTH, 200))(x) - x = TimeDistributed(BatchNormalization(momentum=BN_M))(x) - x = Activation('relu')(x) - if DO_RATE > 0: - x = Dropout(DO_RATE)(x) - print K.int_shape(x) - - x = TimeDistributed(Dense(2000))(x) - x = TimeDistributed(BatchNormalization(momentum=BN_M))(x) - x = Activation('relu')(x) - if DO_RATE > 0: - x = Dropout(DO_RATE)(x) - print K.int_shape(x) - - x = TimeDistributed(Dense(y_shape[2] * y_shape[3], activation='sigmoid'))(x) - print K.int_shape(x) - x = Reshape((y_shape[1], y_shape[2], y_shape[3]))(x) - print K.int_shape(x) - - if USE_VAE: - model = Model(x_in, x) - model.compile(optimizer=Adam(lr=LR), loss=vae_loss) - else: - model = Model(x_in, x) - model.compile(optimizer=RMSprop(lr=LR), loss='binary_crossentropy') - - plot_model(model, to_file='model.png', show_shapes=True) - -################################### -# Train -################################### -print "Compiling SubModels..." -func = K.function([model.get_layer('encoder').input, K.learning_phase()], - [model.layers[-1].output]) -enc = Model(inputs=model.input, outputs=model.get_layer('pre_encoder').output) - -rand_vecs = np.random.normal(0.0, 1.0, (NUM_RAND_SONGS, PARAM_SIZE)) -np.save('rand.npy', rand_vecs) - -def make_rand_songs(write_dir, rand_vecs): - for i in xrange(rand_vecs.shape[0]): - x_rand = rand_vecs[i:i+1] - y_song = func([x_rand, 0])[0] - midi.samples_to_midi(y_song[0], write_dir + 'rand' + str(i) + '.mid', 16, 0.25) - -def make_rand_songs_normalized(write_dir, rand_vecs): - if USE_EMBEDDING: - x_enc = np.squeeze(enc.predict(x_orig)) - else: - x_enc = np.squeeze(enc.predict(y_orig)) - - x_mean = np.mean(x_enc, axis=0) - x_stds = np.std(x_enc, axis=0) - x_cov = np.cov((x_enc - x_mean).T) - u, s, v = np.linalg.svd(x_cov) - e = np.sqrt(s) - - print "Means: ", x_mean[:6] - print "Evals: ", e[:6] - - np.save(write_dir + 'means.npy', x_mean) - np.save(write_dir + 'stds.npy', x_stds) - np.save(write_dir + 'evals.npy', e) - np.save(write_dir + 'evecs.npy', v) - - x_vecs = x_mean + np.dot(rand_vecs * e, v) - make_rand_songs(write_dir, x_vecs) - - title = '' - if '/' in write_dir: - title = 'Epoch: ' + write_dir.split('/')[-2][1:] - - plt.clf() - e[::-1].sort() - plt.title(title) - plt.bar(np.arange(e.shape[0]), e, align='center') - plt.draw() - plt.savefig(write_dir + 'evals.png') - - plt.clf() - plt.title(title) - plt.bar(np.arange(e.shape[0]), x_mean, align='center') - plt.draw() - plt.savefig(write_dir + 'means.png') - - plt.clf() - plt.title(title) - plt.bar(np.arange(e.shape[0]), x_stds, align='center') - plt.draw() - plt.savefig(write_dir + 'stds.png') - -if PLAY_ONLY: - print "Generating Songs..." - make_rand_songs_normalized('', rand_vecs) - for i in xrange(20): - x_test_song = x_train[i:i+1] - y_song = model.predict(x_test_song, batch_size=BATCH_SIZE)[0] - midi.samples_to_midi(y_song, 'gt' + str(i) + '.mid', 16) - exit(0) - -print "Training..." -save_config() -train_loss = [] -ofs = 0 - -for iter in xrange(NUM_EPOCHS): - if USE_EMBEDDING: - history = model.fit(x_train, y_train, batch_size=BATCH_SIZE, epochs=1) - else: - cur_ix = 0 - for i in xrange(num_songs): - end_ix = cur_ix + y_lengths[i] - for j in xrange(MAX_LENGTH): - k = (j + ofs) % (end_ix - cur_ix) - y_train[i,j] = y_samples[cur_ix + k] - cur_ix = end_ix - assert(end_ix == num_samples) - ofs += 1 - - history = model.fit(y_train, y_train, batch_size=BATCH_SIZE, epochs=1) - - loss = history.history["loss"][-1] - train_loss.append(loss) - print "Train Loss: " + str(train_loss[-1]) - - if WRITE_HISTORY: - plotScores(train_loss, 'History/Scores.png', True) - else: - plotScores(train_loss, 'Scores.png', True) - - i = iter + 1 - if i in [1, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 120, 140, 160, 180, 200, 250, 300, 350, 400, 450] or (i % 100 == 0): - write_dir = '' - if WRITE_HISTORY: - #Create folder to save models into - write_dir = 'History/e' + str(i) - if not os.path.exists(write_dir): - os.makedirs(write_dir) - write_dir += '/' - model.save('History/model.h5') - else: - model.save('model.h5') - print "Saved" - - if USE_EMBEDDING: - y_song = model.predict(x_test_song, batch_size=BATCH_SIZE)[0] - else: - y_song = model.predict(y_test_song, batch_size=BATCH_SIZE)[0] - util.samples_to_pics(write_dir + 'test', y_song) - midi.samples_to_midi(y_song, write_dir + 'test.mid', 16) - - make_rand_songs_normalized(write_dir, rand_vecs) - -print "Done" + +def vae_loss(x, x_decoded_mean, z_log_sigma_sq, z_mean): + """ + Variational autoencoder loss function. + :param x: + :param x_decoded_mean: + :param z_log_sigma_sq: + :param z_mean: + :return: + """ + xent_loss = binary_crossentropy(x, x_decoded_mean) + kl_loss = VAE_B2 * K.mean(1 + z_log_sigma_sq - K.square(z_mean) - K.exp(z_log_sigma_sq), axis=None) + return xent_loss - kl_loss + + +def plot_losses(scores, f_name, on_top=True): + """ + Plot loss. + :param scores: + :param f_name: + :param on_top: + :return: + """ + plt.clf() + ax = plt.gca() + ax.yaxis.tick_right() + ax.yaxis.set_ticks_position('both') + ax.yaxis.grid(True) + plt.plot(scores) + plt.ylim([0.0, 0.009]) + plt.xlabel('Epoch') + loc = ('upper right' if on_top else 'lower right') + plt.draw() + plt.savefig(f_name) + + +def save_training_config(num_songs, model, learning_rate): + """ + Save configuration of training. + :param num_songs: + :param model: + :return: + """ + with open('results/config.txt', 'w') as file_out: + file_out.write('LEARNING_RATE: ' + str(learning_rate) + '\n') + file_out.write('BATCHNORM_MOMENTUM: ' + str(BATCHNORM_MOMENTUM) + '\n') + file_out.write('BATCH_SIZE: ' + str(BATCH_SIZE) + '\n') + file_out.write('NUM_OFFSETS: ' + str(NUM_OFFSETS) + '\n') + file_out.write('DROPOUT_RATE: ' + str(DROPOUT_RATE) + '\n') + file_out.write('num_songs: ' + str(num_songs) + '\n') + file_out.write('optimizer: ' + type(model.optimizer).__name__ + '\n') + + +def generate_random_songs(decoder, write_dir, random_vectors): + """ + Generate random songs using random latent vectors. + :param decoder: + :param write_dir: + :param random_vectors: + :return: + """ + for i in range(random_vectors.shape[0]): + random_latent_x = random_vectors[i:i + 1] + y_song = decoder([random_latent_x, 0])[0] + midi_utils.samples_to_midi(y_song[0], write_dir + 'random_vectors' + str(i) + '.mid', 32) + + +def calculate_and_store_pca_statistics(encoder, x_orig, y_orig, write_dir): + """ + Calculate means, stddevs, covariance singular values (pca values), covariance singular vectors (pca vectors) + to more efficiently navigate/find configurations in the latent space. + :param encoder: + :param x_orig: + :param y_orig: + :param write_dir: + :return: + """ + if USE_EMBEDDING: + latent_x = np.squeeze(encoder.predict(x_orig)) + else: + latent_x = np.squeeze(encoder.predict(y_orig)) + + latent_mean = np.mean(latent_x, axis=0) + latent_stds = np.std(latent_x, axis=0) + latent_cov = np.cov((latent_x - latent_mean).T) + _, latent_pca_values, latent_pca_vectors = np.linalg.svd(latent_cov) + latent_pca_values = np.sqrt(latent_pca_values) + + print("Latent Mean values: ", latent_mean[:6]) + print("Latent PCA values: ", latent_pca_values[:6]) + + np.save(write_dir + 'latent_means.npy', latent_mean) + np.save(write_dir + 'latent_stds.npy', latent_stds) + np.save(write_dir + 'latent_pca_values.npy', latent_pca_values) + np.save(write_dir + 'latent_pca_vectors.npy', latent_pca_vectors) + return latent_mean, latent_stds, latent_pca_values, latent_pca_vectors + + +def generate_normalized_random_songs(x_orig, y_orig, encoder, decoder, random_vectors, write_dir): + """ + Generate a number of random songs from some normal latent vector samples. + :param encoder: + :param x_orig: + :param y_orig: + :param decoder: + :param write_dir: + :param random_vectors: + :return: + """ + latent_mean, latent_stds, pca_values, pca_vectors = calculate_and_store_pca_statistics(encoder, x_orig, y_orig, write_dir) + + latent_vectors = latent_mean + np.dot(random_vectors * pca_values, pca_vectors) + generate_random_songs(decoder, write_dir, latent_vectors) + + title = '' + if '/' in write_dir: + title = 'Epoch: ' + write_dir.split('/')[-2][1:] + + plt.clf() + pca_values[::-1].sort() + plt.title(title) + plt.bar(np.arange(pca_values.shape[0]), pca_values, align='center') + plt.draw() + plt.savefig(write_dir + 'latent_pca_values.png') + + plt.clf() + plt.title(title) + plt.bar(np.arange(pca_values.shape[0]), latent_mean, align='center') + plt.draw() + plt.savefig(write_dir + 'latent_means.png') + + plt.clf() + plt.title(title) + plt.bar(np.arange(pca_values.shape[0]), latent_stds, align='center') + plt.draw() + plt.savefig(write_dir + 'latent_stds.png') + + +def train(samples_path='data/interim/samples.npy', lengths_path='data/interim/lengths.npy', epochs_qty=EPOCHS_QTY, learning_rate=LEARNING_RATE): + """ + Train model. + :return: + """ + + # Create folders to save models into + if not os.path.exists('results'): + os.makedirs('results') + if WRITE_HISTORY and not os.path.exists('results/history'): + os.makedirs('results/history') + + # Load dataset into memory + print("Loading Data...") + if not os.path.exists(samples_path) or not os.path.exists(lengths_path): + print('No input data found, run preprocess_songs.py first.') + exit(1) + + y_samples = np.load(samples_path) + y_lengths = np.load(lengths_path) + + samples_qty = y_samples.shape[0] + songs_qty = y_lengths.shape[0] + print("Loaded " + str(samples_qty) + " samples from " + str(songs_qty) + " songs.") + print(np.sum(y_lengths)) + assert (np.sum(y_lengths) == samples_qty) + + print("Preparing song samples, padding songs...") + x_shape = (songs_qty * NUM_OFFSETS, 1) # for embedding + x_orig = np.expand_dims(np.arange(x_shape[0]), axis=-1) + + y_shape = (songs_qty * NUM_OFFSETS, MAX_WINDOWS) + y_samples.shape[1:] # (songs_qty, max number of windows, window pitch qty, window beats per measure) + y_orig = np.zeros(y_shape, dtype=y_samples.dtype) # prepare dataset array + + # fill in measure of songs into input windows for network + song_start_ix = 0 + song_end_ix = y_lengths[0] + for song_ix in range(songs_qty): + for offset in range(NUM_OFFSETS): + ix = song_ix * NUM_OFFSETS + offset # calculate the index of the song with its offset + song_end_ix = song_start_ix + y_lengths[song_ix] # get song end ix + for window_ix in range(MAX_WINDOWS): # get a maximum number of measures from a song + song_measure_ix = (window_ix + offset) % y_lengths[song_ix] # chosen measure of song to be placed in window (modulo song length) + y_orig[ix, window_ix] = y_samples[song_start_ix + song_measure_ix] # move measure into window + song_start_ix = song_end_ix # new song start index is previous song end index + assert (song_end_ix == samples_qty) + x_train = np.copy(x_orig) + y_train = np.copy(y_orig) + + # copy some song from the samples and write it to midi again + test_ix = 0 + y_test_song = np.copy(y_train[test_ix: test_ix + 1]) + x_test_song = np.copy(x_train[test_ix: test_ix + 1]) + midi_utils.samples_to_midi(y_test_song[0], 'data/interim/gt.mid') + + # create model + if CONTINUE_TRAIN or GENERATE_ONLY: + print("Loading model...") + model = load_model('results/model.h5') + else: + print("Building model...") + + model = models.create_autoencoder_model(input_shape=y_shape[1:], + latent_space_size=LATENT_SPACE_SIZE, + dropout_rate=DROPOUT_RATE, + max_windows=MAX_WINDOWS, + batchnorm_momentum=BATCHNORM_MOMENTUM, + use_vae=USE_VAE, + vae_b1=VAE_B1, + use_embedding=USE_EMBEDDING, + embedding_input_shape=x_shape[1:], + embedding_shape=x_train.shape[0]) + + if USE_VAE: + model.compile(optimizer=Adam(lr=learning_rate), loss=vae_loss) + else: + model.compile(optimizer=RMSprop(lr=learning_rate), loss='binary_crossentropy') + + # plot model with graphvis if installed + try: + plot_model(model, to_file='results/model.png', show_shapes=True) + except OSError as e: + print(e) + + # train + print("Referencing sub-models...") + decoder = K.function([model.get_layer('decoder').input, K.learning_phase()], [model.layers[-1].output]) + encoder = Model(inputs=model.input, outputs=model.get_layer('encoder').output) + + random_vectors = np.random.normal(0.0, 1.0, (NUM_RAND_SONGS, LATENT_SPACE_SIZE)) + np.save('data/interim/random_vectors.npy', random_vectors) + + if GENERATE_ONLY: + print("Generating songs...") + generate_normalized_random_songs(x_orig, y_orig, encoder, decoder, random_vectors, 'results/') + for save_epoch in range(20): + x_test_song = x_train[save_epoch:save_epoch + 1] + y_song = model.predict(x_test_song, batch_size=BATCH_SIZE)[0] + midi_utils.samples_to_midi(y_song, 'results/gt' + str(save_epoch) + '.mid') + exit(0) + + save_training_config(songs_qty, model, learning_rate) + print("Training model...") + train_loss = [] + offset = 0 + + for epoch in range(epochs_qty): + print("Training epoch: ", epoch, "of", epochs_qty) + if USE_EMBEDDING: + history = model.fit(x_train, y_train, batch_size=BATCH_SIZE, epochs=1) + else: + # produce songs from its samples with a different starting point of the song each time + song_start_ix = 0 + for song_ix in range(songs_qty): + song_end_ix = song_start_ix + y_lengths[song_ix] + for window_ix in range(MAX_WINDOWS): + song_measure_ix = (window_ix + offset) % y_lengths[song_ix] + y_train[song_ix, window_ix] = y_samples[song_start_ix + song_measure_ix] + song_start_ix = song_end_ix + assert (song_end_ix == samples_qty) + offset += 1 + + history = model.fit(y_train, y_train, batch_size=BATCH_SIZE, epochs=1) # train model on reconstruction loss + + # store last loss + loss = history.history["loss"][-1] + train_loss.append(loss) + print("Train loss: " + str(train_loss[-1])) + + if WRITE_HISTORY: + plot_losses(train_loss, 'results/history/losses.png', True) + else: + plot_losses(train_loss, 'results/losses.png', True) + + # save model periodically + save_epoch = epoch + 1 + if save_epoch in EPOCHS_TO_SAVE or (save_epoch % 100 == 0) or save_epoch == epochs_qty: + write_dir = '' + if WRITE_HISTORY: + # Create folder to save models into + write_dir += 'results/history/e' + str(save_epoch) + if not os.path.exists(write_dir): + os.makedirs(write_dir) + write_dir += '/' + model.save('results/history/model.h5') + else: + model.save('results/model.h5') + + print("...Saved.") + + if USE_EMBEDDING: + y_song = model.predict(x_test_song, batch_size=BATCH_SIZE)[0] + else: + y_song = model.predict(y_test_song, batch_size=BATCH_SIZE)[0] + + plot_utils.plot_samples(write_dir + 'test', y_song) + midi_utils.samples_to_midi(y_song, write_dir + 'test.mid') + + generate_normalized_random_songs(x_orig, y_orig, encoder, decoder, random_vectors, write_dir) + + print("...Done.") + + +if __name__ == "__main__": + # configure parser and parse arguments + parser = argparse.ArgumentParser(description='Train to reconstruct midi in autoencoder.') + parser.add_argument('--samples_path', default='data/interim/samples.npy', type=str, help='Path to samples numpy array.') + parser.add_argument('--lengths_path', default='data/interim/lengths.npy', type=str, help='Path to sample lengths numpy array.') + parser.add_argument('--epochs_qty', default=EPOCHS_QTY, type=int, help='The number of epochs to be trained.') + parser.add_argument('--learning_rate', default=LEARNING_RATE, type=float, help='The learning rate to train the model.') + + args = parser.parse_args() + epochs_qty = args.epochs_qty + learning_rate = args.learning_rate + samples_path = args.samples_path + lengths_path = args.lengths_path + train(samples_path, lengths_path, epochs_qty, learning_rate) diff --git a/util.py b/util.py deleted file mode 100644 index 39d65bb4..00000000 --- a/util.py +++ /dev/null @@ -1,104 +0,0 @@ -import numpy as np -import cv2 -import os - -def transpose_range(samples): - merged_sample = np.zeros_like(samples[0]) - for sample in samples: - merged_sample = np.maximum(merged_sample, sample) - merged_sample = np.amax(merged_sample, axis=0) - min_note = np.argmax(merged_sample) - max_note = merged_sample.shape[0] - np.argmax(merged_sample[::-1]) - return min_note, max_note - -def generate_add_centered_transpose(samples): - num_notes = samples[0].shape[1] - min_note, max_note = transpose_range(samples) - s = num_notes/2 - (max_note + min_note)/2 - out_samples = samples - out_lens = [len(samples), len(samples)] - for i in xrange(len(samples)): - out_sample = np.zeros_like(samples[i]) - out_sample[:,min_note+s:max_note+s] = samples[i][:,min_note:max_note] - out_samples.append(out_sample) - return out_samples, out_lens - -def generate_all_transpose(samples, radius=6): - num_notes = samples[0].shape[1] - min_note, max_note = transpose_range(samples) - min_shift = -min(radius, min_note) - max_shift = min(radius, num_notes - max_note) - out_samples = [] - out_lens = [] - for s in xrange(min_shift, max_shift): - for i in xrange(len(samples)): - out_sample = np.zeros_like(samples[i]) - out_sample[:,min_note+s:max_note+s] = samples[i][:,min_note:max_note] - out_samples.append(out_sample) - out_lens.append(len(samples)) - return out_samples, out_lens - -def sample_to_pic(fname, sample, thresh=None): - if thresh is not None: - inverted = np.where(sample > thresh, 0, 1) - else: - inverted = 1.0 - sample - cv2.imwrite(fname, inverted * 255) - -def samples_to_pics(dir, samples, thresh=None): - if not os.path.exists(dir): os.makedirs(dir) - for i in xrange(samples.shape[0]): - sample_to_pic(dir + '/s' + str(i) + '.png', samples[i], thresh) - -def pad_songs(y, y_lens, max_len): - y_shape = (y_lens.shape[0], max_len) + y.shape[1:] - y_train = np.zeros(y_shape, dtype=np.float32) - cur_ix = 0 - for i in xrange(y_lens.shape[0]): - end_ix = cur_ix + y_lens[i] - for j in xrange(max_len): - k = j % (end_ix - cur_ix) - y_train[i,j] = y[cur_ix + k] - cur_ix = end_ix - assert(end_ix == y.shape[0]) - return y_train - -def sample_to_pattern(sample, ix, size): - num_pats = 0 - pat_types = {} - pat_list = [] - num_samples = len(sample) if type(sample) is list else sample.shape[0] - for i in xrange(size): - j = (ix + i) % num_samples - measure = sample[j].tobytes() - if measure not in pat_types: - pat_types[measure] = num_pats - num_pats += 1 - pat_list.append(pat_types[measure]) - return str(pat_list), pat_types - -def embed_samples(samples): - note_dict = {} - n, m, p = samples.shape - samples.flags.writeable = False - e_samples = np.empty(samples.shape[:2], dtype=np.int32) - for i in xrange(n): - for j in xrange(m): - note = samples[i,j].data - if note not in note_dict: - note_dict[note] = len(note_dict) - e_samples[i,j] = note_dict[note] - samples.flags.writeable = True - lookup = np.empty((len(note_dict), p), dtype=np.float32) - for k in note_dict: - lookup[note_dict[k]] = k - return e_samples, note_dict, lookup - -def e_to_samples(e_samples, lookup): - samples = np.empty(e_samples.shape + lookup.shape[-1:], dtype=np.float32) - n, m = e_samples.shape - for i in xrange(n): - for j in xrange(m): - samples[i,j] = lookup[e_samples[i,j]] - return samples - \ No newline at end of file