simplify a little midi.py module

This commit is contained in:
Cezary Pukownik 2019-05-29 10:36:34 +02:00
parent 0a297e331d
commit 4aa5916346
2 changed files with 80 additions and 249 deletions

80
project/midi.py Normal file
View File

@ -0,0 +1,80 @@
#!/usr/bin/env python3
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
def to_samples(midi_file_path, midi_res=settings.midi_resolution):
# this function export a samples from midi file:
# and for every track in midi file chopped pianoroll
# for a samples of given beat_lenth (midi_res)
# every track is single line
print('Exporting samples from: {}'.format(midi_file_path))
all_beats = np.empty((0, settings.midi_resolution, 128))
for track in roll.Multitrack(midi_file_path).tracks:
print('Track: {}'.format(track.name))
if not track.is_drum:
number_of_beats = floor(track.pianoroll.shape[0] / midi_res)
track_pianoroll = track.pianoroll[: number_of_beats * midi_res]
track_beats = track_pianoroll.reshape(number_of_beats, midi_res, 128)
all_beats = np.concatenate([track_beats, all_beats], axis=0)
print('Exported {} samples of {}'.format(number_of_beats, settings.midi_program[track.program]))
else:
# add code for drums samples
pass
return all_beats
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 delete_empty_samples(sample_pack):
print('Deleting empty samples...')
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]=='export':
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]))
fig, axes = plt.subplots(nrows=10, ncols=10, figsize=(20, 20))
for idx, ax in enumerate(axes.ravel()):
n = np.random.randint(0, sample_pack.shape[0])
sample = sample_pack[n]
ax.imshow(sample, cmap = plt.get_cmap('gray'))
plt.savefig(settings.sample_preview_path)
if __name__ == '__main__':
main()

View File

@ -1,249 +0,0 @@
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()