new library for midi processing
This commit is contained in:
parent
acb3024341
commit
7d5cd31bdd
676
project/midi_processing.py
Normal file
676
project/midi_processing.py
Normal file
@ -0,0 +1,676 @@
|
||||
#!/usr/bin/env python
|
||||
# coding: utf-8
|
||||
|
||||
# In[1]:
|
||||
|
||||
|
||||
import os
|
||||
import pickle
|
||||
import numpy as np
|
||||
from collections import defaultdict
|
||||
|
||||
import pretty_midi as pm
|
||||
from tqdm import tqdm
|
||||
|
||||
|
||||
# In[98]:
|
||||
|
||||
|
||||
TODO = '''
|
||||
TODO: put methods of data extraction for seq2seq arangment model to multitrack class [DONE]
|
||||
TODO: make functions for data extraction for seq2seq model for riff/melody generation [DONE]
|
||||
'''
|
||||
|
||||
|
||||
# In[367]:
|
||||
|
||||
|
||||
# '''return a dictionary with tracks indexes grouped by instrument class'''
|
||||
# tracks = file.tracks
|
||||
# names = [track.name for track in tracks]
|
||||
# uniqe_instruemnts = set(names)
|
||||
# tracks_by_instrument = dict()
|
||||
# for key in uniqe_instruemnts:
|
||||
# tracks_by_instrument[key] = []
|
||||
|
||||
# for i, track in enumerate(tracks):
|
||||
# tracks_by_instrument[track.name].append(i)
|
||||
|
||||
# tracks_by_instrument
|
||||
|
||||
|
||||
# In[368]:
|
||||
|
||||
|
||||
# def get_posible_pairs(instrument_x, instrument_y):
|
||||
# '''it takes two lists, and return a list of tuples with every posible 2-element combination
|
||||
# parameters:
|
||||
# -----------
|
||||
# instrument_x, instrument_y : string {'Guitar','Bass','Drums'}
|
||||
# a string that represent a instrument class you want to look for in midi file.
|
||||
|
||||
# returns:
|
||||
# ----------
|
||||
# pairs: list of tuples
|
||||
# a list of posible 2-element combination of two lists
|
||||
# '''
|
||||
# x_indexes = tracks_by_instrument[instrument_x]
|
||||
# y_indexes = tracks_by_instrument[instrument_y]
|
||||
# pairs = []
|
||||
# # pairs = [(x,y) for x in x_indexes for y in y_indexes]
|
||||
|
||||
# for x in x_indexes:
|
||||
# for y in y_indexes:
|
||||
# pairs.append((x,y))
|
||||
|
||||
# return pairs
|
||||
|
||||
|
||||
# In[369]:
|
||||
|
||||
|
||||
# def get_common_bars_for_every_possible_pair(pairs)
|
||||
# ''' for every possible pair of given instrument classes
|
||||
# returns common bars from multitrack'''
|
||||
# x_bars = []
|
||||
# y_bars = []
|
||||
# for x_track_index, y_track_index in pairs:
|
||||
# _x_bars, _y_bars = get_common_bars(file.tracks[x_track_index], file.tracks[y_track_index])
|
||||
# x_bars.extend(_x_bars)
|
||||
# y_bars.extend(_y_bars)
|
||||
|
||||
# return x_bars, y_bars
|
||||
|
||||
|
||||
# In[370]:
|
||||
|
||||
|
||||
# def get_data_seq2seq_arrangment(self, bars_in_seq):
|
||||
# ## This is the end of extracting data from midis to seq2seq arranging network.
|
||||
# '''this method is returning a sequances of given lenth by rolling this lists of x and y for arrangemt generation'''
|
||||
# x_seq = []
|
||||
# y_seq = []
|
||||
|
||||
# for i in range(len(x_bars) - bars_in_seq + 1):
|
||||
# x_seq_to_add = [note for bar in x_bars[i:i+bars_in_seq] for note in bar ]
|
||||
# y_seq_to_add = [note for bar in y_bars[i:i+bars_in_seq] for note in bar ]
|
||||
# x_seq.append(x_seq_to_add)
|
||||
# y_seq.append(y_seq_to_add)
|
||||
|
||||
# len(x_seq), len(y_seq)
|
||||
# # get_bar_len(y_seq[0])
|
||||
|
||||
|
||||
# In[371]:
|
||||
|
||||
|
||||
# def get_track_by_instrument(self):
|
||||
# '''return a dictionary with tracks indexes grouped by instrument class'''
|
||||
# tracks = self.tracks
|
||||
# names = [track.name for track in tracks]
|
||||
# uniqe_instruemnts = set(names)
|
||||
# tracks_by_instrument = dict()
|
||||
# for key in uniqe_instruemnts:
|
||||
# tracks_by_instrument[key] = []
|
||||
|
||||
# for i, track in enumerate(tracks):
|
||||
# tracks_by_instrument[track.name].append(i)
|
||||
|
||||
# return tracks_by_instrument
|
||||
|
||||
|
||||
# In[372]:
|
||||
|
||||
|
||||
# def get_data_seq2seq_melody(self,instrument_class, x_seq_len=4)
|
||||
# '''return a list of bars with content for every track with given instrument class for melody generaiton'''
|
||||
|
||||
# instrument_tracks = tracks_by_instrument[instrument_class]
|
||||
|
||||
# for track_index in instrument_tracks:
|
||||
# # make below as function: get_bars_with_content
|
||||
# bars = file.tracks[track_index].stream_to_bars()
|
||||
# bars_indexes_with_content = get_bar_indexes_with_content(bars)
|
||||
# bars_with_content = [bars[i] for i in get_bar_indexes_with_content(bars)]
|
||||
|
||||
# # make below as function: get_sequances_from_bars (for seq2seq melody generator)
|
||||
# x_seq = []
|
||||
# y_bar = []
|
||||
# for i in range(len(bars_with_content)-seq_len-1):
|
||||
# _x_seq = bars_with_content[i:i+seq_len]
|
||||
# _y_bar = bars_with_content[i+seq_len]
|
||||
# x_seq.append(_x_seq)
|
||||
# y_bar.append(_y_bar)
|
||||
|
||||
|
||||
# len(x_seq), len(y_bar)
|
||||
# # print( ' x:' ,x_seq[1],'\n', 'y: ', y_bar[1],'\n', 'seq: ',bars_with_content[1:6])
|
||||
|
||||
|
||||
# In[15]:
|
||||
|
||||
|
||||
def get_bar_indexes_with_content(bars):
|
||||
'''this method is looking for non-empty bars in the tracks bars
|
||||
the empty bar consist of only rest notes.
|
||||
returns: a set of bars indexes with notes
|
||||
'''
|
||||
bars_indexes_with_content = set()
|
||||
for i, bar in enumerate(bars):
|
||||
if bar_has_content(bar):
|
||||
bars_indexes_with_content.add(i)
|
||||
|
||||
return bars_indexes_with_content
|
||||
|
||||
|
||||
# In[4]:
|
||||
|
||||
|
||||
def get_bars_with_content(bars):
|
||||
'''this method is looking for non-empty bars in the tracks bars
|
||||
the empty bar consist of only rest notes.
|
||||
returns: a set of bars with notes
|
||||
'''
|
||||
bars_with_content = []
|
||||
for bar in bars:
|
||||
if bar_has_content(bar):
|
||||
bars_with_content.append(bar)
|
||||
|
||||
return bars_with_content
|
||||
|
||||
|
||||
# In[5]:
|
||||
|
||||
|
||||
def get_common_bars(track_x,track_y):
|
||||
'''return common bars, for two tracks is song
|
||||
return X_train, y_train list of
|
||||
'''
|
||||
bars_x = track_x.stream_to_bars()
|
||||
bars_y = track_y.stream_to_bars()
|
||||
bwc_x = get_bar_indexes_with_content(bars_x)
|
||||
bwc_y = get_bar_indexes_with_content(bars_y)
|
||||
|
||||
common_bars = bwc_x.intersection(bwc_y)
|
||||
common_bars_x = [bars_x[i] for i in common_bars]
|
||||
common_bars_y = [bars_y[i] for i in common_bars]
|
||||
return common_bars_x, common_bars_y
|
||||
|
||||
|
||||
# In[6]:
|
||||
|
||||
|
||||
def get_bar_len(bar):
|
||||
"""calculate a lenth of a bar
|
||||
parameters:
|
||||
bar : list
|
||||
list of "notes", tuples like (pitches, len)
|
||||
"""
|
||||
time = 0
|
||||
for note in bar:
|
||||
time += note[1]
|
||||
return time
|
||||
|
||||
|
||||
# In[7]:
|
||||
|
||||
|
||||
def bar_has_content(bar):
|
||||
'''check if bar has any musical information, more accurate
|
||||
it checks if in a bar is any non-rest event like note, or chord
|
||||
|
||||
parameters:
|
||||
-----------
|
||||
bar: list
|
||||
list of notes
|
||||
|
||||
return:
|
||||
-------
|
||||
bool:
|
||||
True if bas has concent and False of doesn't
|
||||
'''
|
||||
bar_notes = len(bar)
|
||||
count_rest = 0
|
||||
for note in bar:
|
||||
if note[0] == (-1,):
|
||||
count_rest += 1
|
||||
if count_rest == bar_notes:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
# In[8]:
|
||||
|
||||
|
||||
def round_to_sixteenth_note(x, base=0.25):
|
||||
'''round value to closest multiplication by base
|
||||
in default to 0.25 witch is sisteenth note accuracy
|
||||
'''
|
||||
|
||||
return base * round(x/base)
|
||||
|
||||
|
||||
# In[9]:
|
||||
|
||||
|
||||
def parse_pretty_midi_instrument(instrument, resolution, time_to_tick, key_offset):
|
||||
''' arguments: a prettyMidi instrument object
|
||||
return: a custom SingleTrack object
|
||||
'''
|
||||
|
||||
first_tick = None
|
||||
prev_tick = 0
|
||||
prev_note_lenth = 0
|
||||
max_rest_len = 4.0
|
||||
|
||||
notes = defaultdict(lambda:[set(), set()])
|
||||
for note in instrument.notes:
|
||||
if first_tick == None:
|
||||
# first_tick = round_to_sixteenth_note(time_to_tick(note.start)/resolution)
|
||||
first_tick = 0
|
||||
|
||||
tick = round_to_sixteenth_note(time_to_tick(note.start)/resolution)
|
||||
# add rest if needed
|
||||
if prev_tick != None:
|
||||
act_tick = prev_tick + prev_note_lenth
|
||||
if act_tick < tick:
|
||||
rest_lenth = tick - act_tick
|
||||
while rest_lenth > max_rest_len:
|
||||
notes[act_tick] = [{-1},{max_rest_len}]
|
||||
act_tick += max_rest_len
|
||||
rest_lenth -= max_rest_len
|
||||
notes[act_tick] = [{-1},{rest_lenth}]
|
||||
|
||||
note_lenth = round_to_sixteenth_note(time_to_tick(note.end-note.start)/resolution)
|
||||
|
||||
if -1 in notes[tick][0]:
|
||||
notes[tick] = [set(), set()]
|
||||
|
||||
if instrument.is_drum:
|
||||
notes[tick][0].add(note.pitch)
|
||||
else:
|
||||
notes[tick][0].add(note.pitch+key_offset)
|
||||
notes[tick][1].add(note_lenth)
|
||||
|
||||
prev_tick = tick
|
||||
prev_note_lenth = note_lenth
|
||||
|
||||
notes = [(tuple(e[0]), max(e[1])) for e in notes.values()]
|
||||
|
||||
name = 'Drums' if instrument.is_drum else pm.program_to_instrument_class(instrument.program)
|
||||
return SingleTrack(name, instrument.program, instrument.is_drum, Stream(first_tick,notes) )
|
||||
|
||||
|
||||
# In[10]:
|
||||
|
||||
|
||||
def remove_duplicated_sequences(xy_tuple):
|
||||
x = xy_tuple[0]
|
||||
y = xy_tuple[1]
|
||||
x_freeze = [tuple(seq) for seq in x]
|
||||
y_freeze = [tuple(seq) for seq in y]
|
||||
unique_data = list(set(zip(x_freeze,y_freeze)))
|
||||
x_unique = [seq[0] for seq in unique_data]
|
||||
y_unique = [seq[1] for seq in unique_data]
|
||||
return x_unique, y_unique
|
||||
|
||||
|
||||
# In[11]:
|
||||
|
||||
|
||||
class Stream():
|
||||
|
||||
def __init__ (self, first_tick, notes):
|
||||
self.notes = notes
|
||||
self.first_tick = first_tick
|
||||
|
||||
def __repr__(self):
|
||||
return '<Stream object with {} musical events>'.format(len(self.notes))
|
||||
|
||||
|
||||
# In[12]:
|
||||
|
||||
|
||||
class SingleTrack():
|
||||
'''class of single track in midi file encoded from pretty midi library
|
||||
|
||||
atributes:
|
||||
----------
|
||||
name: str
|
||||
name of instrument class
|
||||
program: int
|
||||
midi instrument program
|
||||
is_drum: bool
|
||||
True if this track is drums track, False otherwise
|
||||
stream:
|
||||
Stream object of encoded music events (chords or notes)
|
||||
'''
|
||||
|
||||
def __init__(self, name=None, program=None, is_drum=None, stream=None):
|
||||
self.name = name
|
||||
self.program = program
|
||||
self.is_drum = is_drum
|
||||
self.stream = stream
|
||||
|
||||
def __repr__(self):
|
||||
return "<SingleTrack object. Name:{}, Program:{}, is_drum:{}>".format(self.name, self.program, self.is_drum)
|
||||
|
||||
def to_pretty_midi_instrument(self, tempo=100):
|
||||
'''is create a pretty midi Instrument object from self.stream.notes sequance
|
||||
|
||||
parameters:
|
||||
-----------
|
||||
self: SingleTrack object
|
||||
|
||||
return:
|
||||
-------
|
||||
track: PrettyMIDI.Instrument object
|
||||
'''
|
||||
|
||||
tempo_strech = 100/tempo
|
||||
track = pm.Instrument(program=self.program, is_drum=self.is_drum, name=self.name)
|
||||
time = self.stream.first_tick * tempo_strech
|
||||
for note in self.stream.notes:
|
||||
note_pitch = note[0]
|
||||
note_len = note[1] * tempo_strech
|
||||
for pitch in note_pitch:
|
||||
# if note is a rest (pause)
|
||||
if pitch == -1:
|
||||
break
|
||||
event = pm.Note(velocity=100, pitch=pitch, start=time, end=time+note_len)
|
||||
track.notes.append(event)
|
||||
time = time + note_len
|
||||
|
||||
return track
|
||||
|
||||
def stream_to_bars(self, beat_per_bar=4):
|
||||
'''it takes notes and split it into equaly time distibuted sequances
|
||||
if note is between bars, the note is splited into two notes, with time sum equal to the note between bars.
|
||||
arguments:
|
||||
stream: list of "notes"
|
||||
return:
|
||||
bars: list: list of lists of notes, every list has equal time. in musical context it returns bars
|
||||
'''
|
||||
# TODO: if last bar of sequance has less notes to has time equal given bar lenth it is left shorter
|
||||
# fill the rest of bar with rests
|
||||
notes = self.stream.notes
|
||||
bars = []
|
||||
time = 0
|
||||
bar_index = 0
|
||||
add_tail = False
|
||||
note_pitch = lambda note: note[0]
|
||||
note_len = lambda note: note[1]
|
||||
for note in notes:
|
||||
try:
|
||||
temp = bars[bar_index]
|
||||
except IndexError:
|
||||
bars.append([])
|
||||
|
||||
if add_tail:
|
||||
bars[bar_index].append(tail_note)
|
||||
time += note_len(tail_note)
|
||||
add_tail = False
|
||||
|
||||
time += note_len(note)
|
||||
|
||||
if time == beat_per_bar:
|
||||
bars[bar_index].append(note)
|
||||
time = 0
|
||||
bar_index += 1
|
||||
|
||||
elif time > beat_per_bar: # if note is between bars
|
||||
between_bars_note_len = note_len(note)
|
||||
tail_note_len = time - beat_per_bar
|
||||
leading_note_len = between_bars_note_len - tail_note_len
|
||||
|
||||
leading_note = (note_pitch(note), leading_note_len)
|
||||
bars[bar_index].append(leading_note)
|
||||
tail_note = (note_pitch(note), tail_note_len)
|
||||
|
||||
add_tail = True
|
||||
time = 0
|
||||
bar_index += 1
|
||||
else:
|
||||
bars[bar_index].append(note)
|
||||
|
||||
return bars
|
||||
|
||||
|
||||
# In[99]:
|
||||
|
||||
|
||||
class MultiTrack():
|
||||
'''Class that represent one midi file
|
||||
atributes:
|
||||
pm_obj : PrettyMIDI class object of this midi file
|
||||
res: resolution of midi
|
||||
time_to_tick: function that coverts miliseconds to ticks. it depends on midi resolution for every midi
|
||||
name: path to midi file
|
||||
tracks: a list of SingleTrack objects
|
||||
'''
|
||||
|
||||
def __init__(self, path=None, tempo=100):
|
||||
self.tempo = tempo
|
||||
self.pm_obj = pm.PrettyMIDI(path, initial_tempo=self.tempo)
|
||||
self.res = self.pm_obj.resolution
|
||||
self.time_to_tick = self.pm_obj.time_to_tick
|
||||
self.name = path
|
||||
self.tracks = [parse_pretty_midi_instrument(instrument, self.res, self.time_to_tick, self.get_pitch_offset_to_C() ) for instrument in self.pm_obj.instruments]
|
||||
self.tracks_by_instrument = self.get_track_by_instrument()
|
||||
|
||||
def get_multiseq(self):
|
||||
'''tracks: list of SingleTrack objects
|
||||
reaturn a dictionary of sequences for every sequence in SingleTrack
|
||||
'''
|
||||
|
||||
multiseq_indexes = set([key for music_track in self.tracks for key in music_track.seq])
|
||||
multiseq = dict()
|
||||
|
||||
for seq_id in multiseq_indexes:
|
||||
multiseq[seq_id] = []
|
||||
|
||||
for single_track in self.tracks:
|
||||
for key, value in single_track.seq.items():
|
||||
multiseq[key].append((single_track.name,value))
|
||||
|
||||
return multiseq
|
||||
|
||||
def get_pitch_offset_to_C(self):
|
||||
'''to get better train resoult without augmenting midis to all posible keys
|
||||
we assumed that most frequent note is the rootnote of song then calculate
|
||||
the offset of semitones to move song key to C.
|
||||
|
||||
You should ADD this offset to note pitch to get it right
|
||||
'''
|
||||
|
||||
hist = self.pm_obj.get_pitch_class_histogram()
|
||||
offset = np.argmax(hist)
|
||||
if offset > 6:
|
||||
return 12-offset
|
||||
else:
|
||||
return -offset
|
||||
|
||||
def save(self, path):
|
||||
midi_file = pm.PrettyMIDI()
|
||||
for track in self.tracks:
|
||||
midi_file.instruments.append(track.to_pretty_midi_instrument(self.tempo))
|
||||
midi_file.write(path)
|
||||
return midi_file
|
||||
|
||||
def get_track_by_instrument(self):
|
||||
'''return a dictionary with tracks indexes grouped by instrument class'''
|
||||
tracks = self.tracks
|
||||
names = [track.name for track in tracks]
|
||||
uniqe_instruemnts = set(names)
|
||||
tracks_by_instrument = dict()
|
||||
for key in uniqe_instruemnts:
|
||||
tracks_by_instrument[key] = []
|
||||
|
||||
for i, track in enumerate(tracks):
|
||||
tracks_by_instrument[track.name].append(i)
|
||||
|
||||
return tracks_by_instrument
|
||||
|
||||
def get_common_bars_for_every_possible_pair(self, x_instrument, y_instrument):
|
||||
''' for every possible pair of given instrument classes
|
||||
returns common bars from multitrack'''
|
||||
x_bars = []
|
||||
y_bars = []
|
||||
pairs = self.get_posible_pairs(x_instrument, y_instrument)
|
||||
for x_track_index, y_track_index in pairs:
|
||||
_x_bars, _y_bars = get_common_bars(self.tracks[x_track_index], self.tracks[y_track_index])
|
||||
x_bars.extend(_x_bars)
|
||||
y_bars.extend(_y_bars)
|
||||
|
||||
return x_bars, y_bars
|
||||
|
||||
def get_data_seq2seq_arrangment(self, x_instrument, y_instrument, bars_in_seq=4):
|
||||
'''this method is returning a sequances of given lenth by rolling this lists of x and y for arrangemt generation'''
|
||||
x_seq = []
|
||||
y_seq = []
|
||||
x_bars, y_bars = self.get_common_bars_for_every_possible_pair(x_instrument, y_instrument)
|
||||
|
||||
for i in range(len(x_bars) - bars_in_seq + 1):
|
||||
x_seq_to_add = [note for bar in x_bars[i:i+bars_in_seq] for note in bar ]
|
||||
y_seq_to_add = [note for bar in y_bars[i:i+bars_in_seq] for note in bar ]
|
||||
x_seq.append(x_seq_to_add)
|
||||
y_seq.append(y_seq_to_add)
|
||||
|
||||
return x_seq, y_seq
|
||||
|
||||
def get_data_seq2seq_melody(self,instrument_class, x_seq_len=4):
|
||||
'''return a list of bars with content for every track with given instrument class for melody generaiton'''
|
||||
|
||||
instrument_tracks = self.tracks_by_instrument[instrument_class]
|
||||
|
||||
for track_index in instrument_tracks:
|
||||
bars = self.tracks[track_index].stream_to_bars()
|
||||
bars_indexes_with_content = get_bar_indexes_with_content(bars)
|
||||
bars_with_content = [bars[i] for i in get_bar_indexes_with_content(bars)]
|
||||
|
||||
x_seq = []
|
||||
y_seq = []
|
||||
for i in range(len(bars_with_content)-x_seq_len-1):
|
||||
_x_seq = [note for bar in bars_with_content[i:i+x_seq_len] for note in bar]
|
||||
_y_bar = bars_with_content[i+x_seq_len]
|
||||
x_seq.append(_x_seq)
|
||||
y_seq.append(_y_bar)
|
||||
|
||||
return x_seq, y_seq
|
||||
|
||||
def get_posible_pairs(self, instrument_x, instrument_y):
|
||||
'''it takes two lists, and return a list of tuples with every posible 2-element combination
|
||||
parameters:
|
||||
-----------
|
||||
instrument_x, instrument_y : string {'Guitar','Bass','Drums'}
|
||||
a string that represent a instrument class you want to look for in midi file.
|
||||
|
||||
returns:
|
||||
----------
|
||||
pairs: list of tuples
|
||||
a list of posible 2-element combination of two lists
|
||||
'''
|
||||
x_indexes = self.tracks_by_instrument[instrument_x]
|
||||
y_indexes = self.tracks_by_instrument[instrument_y]
|
||||
# pairs = []
|
||||
pairs = [(x,y) for x in x_indexes for y in y_indexes]
|
||||
|
||||
# for x in x_indexes:
|
||||
# for y in y_indexes:
|
||||
# pairs.append((x,y))
|
||||
|
||||
return pairs
|
||||
|
||||
def show_map(self):
|
||||
print(self.name)
|
||||
print()
|
||||
for track in self.tracks:
|
||||
bars = track.stream_to_bars(4)
|
||||
track_str = ''
|
||||
for bar in bars:
|
||||
if bar_has_content(bar):
|
||||
track_str += '█'
|
||||
else:
|
||||
track_str += '_'
|
||||
|
||||
print(track.name[:4],':', track_str)
|
||||
|
||||
|
||||
|
||||
# In[104]:
|
||||
|
||||
|
||||
def extract_data(midi_folder_path=None, how=None, instrument=None, remove_duplicates=True):
|
||||
'''extract musical data from midis in given folder, to x_train, y_train lists on sequences
|
||||
|
||||
parameters:
|
||||
-----------
|
||||
midi_folder_path : string
|
||||
a path to directory where midi files are stored
|
||||
how : string {'melody','arrangment'}
|
||||
- if melody: function extract data of one instrument,
|
||||
and return lists of x and y that x is actual sequance of 4 bars
|
||||
and y is next bar
|
||||
- if arrangment: function extract data of two instruments and
|
||||
returns a lists of x and y that x is one instrument sequence,
|
||||
and y is coresponing sequance to x, played by second instrument
|
||||
instrument: string or tuple of two strings
|
||||
this parameter is used to specify a instrument class, or classes that you wanted
|
||||
to extract from midi files.
|
||||
|
||||
if how='melody': string
|
||||
if how='arrangment' : (string_x, string_y)
|
||||
|
||||
return:
|
||||
-------
|
||||
x_train, y_train - tuple of coresponding lists of x_train and y_train data for training set
|
||||
|
||||
notes:
|
||||
------
|
||||
extracted data is transposed to the key od C
|
||||
duplicated x,y pairs are removed
|
||||
'''
|
||||
if how not in {'melody','arrangment'}:
|
||||
raise ValueError('how parameter must by one of {melody,arrangment} ')
|
||||
|
||||
x_train = []
|
||||
y_train = []
|
||||
|
||||
for directory, subdirectories, files in os.walk(midi_folder_path):
|
||||
for midi_file in tqdm(files):
|
||||
midi_file_path = os.path.join(directory, midi_file)
|
||||
try:
|
||||
mt = MultiTrack(midi_file_path)
|
||||
if how=='melody':
|
||||
x ,y = mt.get_data_seq2seq_melody(instrument)
|
||||
if how=='arrangment':
|
||||
x ,y = mt.get_data_seq2seq_arrangment(instrument[0], instrument[1])
|
||||
x_train.extend(x)
|
||||
y_train.extend(y)
|
||||
except:
|
||||
continue
|
||||
|
||||
if remove_duplicates:
|
||||
x_train, y_train = remove_duplicated_sequences((x_train, y_train))
|
||||
|
||||
return x_train , y_train
|
||||
|
||||
|
||||
# In[109]:
|
||||
|
||||
|
||||
def main():
|
||||
'''extract data from midis
|
||||
'''
|
||||
x_train, y_train = extract_data(midi_folder_path='WhiteStripes', how='arrangment', instrument=('Guitar','Bass'))
|
||||
pickle.dump((x_train, y_train), open('Guitar_to_Bass_data.pkl','wb'))
|
||||
return x_train, y_train
|
||||
|
||||
|
||||
# In[107]:
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
main()
|
||||
|
Loading…
Reference in New Issue
Block a user