import settings import pypianoroll as roll import matplotlib.pyplot as plt import numpy as np import os from tqdm import tqdm from math import floor import sys from sklearn.preprocessing import MinMaxScaler midi_program = { 0 : 'Perc', 1 : 'Acoustic Grand Piano', 2 : 'Bright Acoustic Piano', 3 : 'Electric Grand Piano', 4 : 'Honky-tonk Piano', 5 : 'Electric Piano 1', 6 : 'Electric Piano 2', 7 : 'Harpsichord', 8 : 'Clavi', 9 : 'Celesta', 10 : 'Glockenspiel', 11 : 'Music Box', 12 : 'Vibraphone', 13 : 'Marimba', 14 : 'Xylophone', 15 : 'Tubular Bells', 16 : 'Dulcimer', 17 : 'Drawbar Organ', 18 : 'Percussive Organ', 19 : 'Rock Organ', 20 : 'Church Organ', 21 : 'Reed Organ', 22 : 'Accordion', 23 : 'Harmonica', 24 : 'Tango Accordion', 25 : 'Acoustic Guitar (nylon)', 26 : 'Acoustic Guitar (steel)', 27 : 'Electric Guitar (jazz)', 28 : 'Electric Guitar (clean)', 29 : 'Electric Guitar (muted)', 30 : 'Overdriven Guitar', 31 : 'Distortion Guitar', 32 : 'Guitar harmonics', 33 : 'Acoustic Bass', 34 : 'Electric Bass (finger)', 35 : 'Electric Bass (pick)', 36 : 'Fretless Bass', 37 : 'Slap Bass 1', 38 : 'Slap Bass 2', 39 : 'Synth Bass 1', 40 : 'Synth Bass 2', 41 : 'Violin', 42 : 'Viola', 43 : 'Cello', 44 : 'Contrabass', 45 : 'Tremolo Strings', 46 : 'Pizzicato Strings', 47 : 'Orchestral Harp', 48 : 'Timpani', 49 : 'String Ensemble 1', 50 : 'String Ensemble 2', 51 : 'SynthStrings 1', 52 : 'SynthStrings 2', 53 : 'Choir Aahs', 54 : 'Voice Oohs', 55 : 'Synth Voice', 56 : 'Orchestra Hit', 57 : 'Trumpet', 58 : 'Trombone', 59 : 'Tuba', 60 : 'Muted Trumpet', 61 : 'French Horn', 62 : 'Brass Section', 63 : 'SynthBrass 1', 64 : 'SynthBrass 2', 65 : 'Soprano Sax', 66 : 'Alto Sax', 67 : 'Tenor Sax', 68 : 'Baritone Sax', 69 : 'Oboe', 70 : 'English Horn', 71 : 'Bassoon', 72 : 'Clarinet', 73 : 'Piccolo', 74 : 'Flute', 75 : 'Recorder', 76 : 'Pan Flute', 77 : 'Blown Bottle', 78 : 'Shakuhachi', 79 : 'Whistle', 80 : 'Ocarina', 81 : 'Lead 1 (square)', 82 : 'Lead 2 (sawtooth)', 83 : 'Lead 3 (calliope)', 84 : 'Lead 4 (chiff)', 85 : 'Lead 5 (charang)', 86 : 'Lead 6 (voice)', 87 : 'Lead 7 (fifths)', 88 : 'Lead 8 (bass + lead)', 89 : 'Pad 1 (new age)', 90 : 'Pad 2 (warm)', 91 : 'Pad 3 (polysynth)', 92 : 'Pad 4 (choir)', 93 : 'Pad 5 (bowed)', 94 : 'Pad 6 (metallic)', 95 : 'Pad 7 (halo)', 96 : 'Pad 8 (sweep)', 97 : 'FX 1 (rain)', 98 : 'FX 2 (soundtrack)', 99 : 'FX 3 (crystal)', 100 : 'FX 4 (atmosphere)', 101 : 'FX 5 (brightness)', 102 : 'FX 6 (goblins)', 103 : 'FX 7 (echoes)', 104 : 'FX 8 (sci-fi)', 105 : 'Sitar', 106 : 'Banjo', 107 : 'Shamisen', 108 : 'Koto', 109 : 'Kalimba', 110 : 'Bag pipe', 111 : 'Fiddle', 112 : 'Shanai', 113 : 'Tinkle Bell', 114 : 'Agogo', 115 : 'Steel Drums', 116 : 'Woodblock', 117 : 'Taiko Drum', 118 : 'Melodic Tom', 119 : 'Synth Drum', 120 : 'Reverse Cymbal', 121 : 'Guitar Fret Noise', 122 : 'Breath Noise', 123 : 'Seashore', 124 : 'Bird Tweet', 125 : 'Telephone Ring', 126 : 'Helicopter', 127 : 'Applause', 128 : 'Gunshot' } # strasznie wolna funcja ;/ def trim_notes(pianoroll): now_block = [] for x in pianoroll: this = None prev = None new_line =[] for y in x: this = y if prev != None: if this > 0 and prev > 0: new_line.append(0) else: new_line.append(y) else: new_line.append(y) prev = this now_block.append(new_line) return np.array(now_block) def metrum_check(midi_lenght, metrum=4, beat_resolution=24): return True if midi_lenght % (metrum * beat_resolution) == 0 else False # >>> data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]] # >>> scaler = MinMaxScaler() # >>> print(scaler.fit(data)) # MinMaxScaler(copy=True, feature_range=(0, 1)) # >>> print(scaler.data_max_) # [ 1. 18.] # >>> print(scaler.transform(data)) # [[0. 0. ] # [0.25 0.25] # [0.5 0.5 ] # [1. 1. ]] # >>> print(scaler.transform([[2, 2]])) # [[1.5 0. ]] def to_samples(midi_file_path, midi_res=settings.midi_resolution, ignore_note_lenght=settings.ignore_note_lenght): print('exporting samples from: {}'.format(midi_file_path)) midi_file = roll.Multitrack(midi_file_path) samples = None all_samples = np.empty((0,settings.midi_resolution,128)) for track in midi_file.tracks: # if not track.is_drum: if not metrum_check(track.pianoroll.shape[0]): print('Track skipped') continue else: instrument_track = track.pianoroll instrument_track = trim_notes(instrument_track.T).T if ignore_note_lenght else instrument_track scaler = MinMaxScaler() instrument_track = scaler.fit_transform(instrument_track) whole_beats = int(instrument_track.shape[0] / midi_res) samples = instrument_track.reshape(whole_beats, midi_res, 128) print('Exported {} samples of {}'.format(whole_beats, midi_program[track.program])) all_samples = np.concatenate([samples, all_samples], axis=0) return all_samples def to_midi(samples, output_path=settings.generated_midi_path, program=0, tempo=120, beat_resolution=settings.beat_resolution): tracks = [roll.Track(samples, program=program)] return_midi = roll.Multitrack(tracks=tracks, tempo=tempo, downbeat=[0, 96, 192, 288], beat_resolution=beat_resolution) roll.write(return_midi, settings.generated_midi_path) def to_png(samples, output_path=settings.generated_pianoroll_path, horizontal=True): img = samples.T if horizontal else samples plt.imshow(img, cmap='gray') plt.savefig(output_path) def delete_empty_samples(sample_pack): temp_sample_pack = sample_pack index_manipulator = 1 for index, sample in enumerate(sample_pack): if sample.sum() == 0: temp_sample_pack = np.delete(temp_sample_pack, index-index_manipulator, axis=0) index_manipulator = index_manipulator + 1 print('Deleted {} empty samples'.format(index_manipulator-1)) return temp_sample_pack def main(): if sys.argv[1]=='-e': print('Exporting started...') sample_pack = np.empty((0,settings.midi_resolution,128)) for midi_file in os.listdir(settings.midi_dir): midi_file_path = '{}/{}'.format(settings.midi_dir, midi_file) midi_samples = to_samples(midi_file_path) if midi_samples is None: continue sample_pack = np.concatenate((midi_samples, sample_pack), axis=0) sample_pack = delete_empty_samples(sample_pack) np.savez_compressed(settings.samples_dir, sample_pack) print('Exported {} samples'.format(sample_pack.shape[0])) elif sys.argv[1]=='-c': to_midi(settings.generated_sample_path) print('Samples to midi saved to {}'.format(settings.generated_sample_path)) elif sys.argv[1]=='-p': sample_pack = np.load(settings.samples_path)['arr_0'] for i, sample in tqdm(enumerate(sample_pack)): to_png(sample, output_path='data/preview/{}.png'.format(i)) if i>50: sys.exit() else: print('type command afrer -e to export samples, -c to convert samples to midi, -p to preview samples in png') if __name__ == '__main__': main()