Source code for pycomposer.truesampler.midi_true_sampler
# -*- coding: utf-8 -*-
import numpy as np
from pygan.true_sampler import TrueSampler
[docs]class MidiTrueSampler(TrueSampler):
'''
Sampler which draws samples from the `true` distribution of MIDI files.
'''
def __init__(
self,
midi_df_list,
batch_size=20,
seq_len=10,
time_fraction=0.1,
min_pitch=24,
max_pitch=108
):
'''
Init.
Args:
midi_df_list: `list` of paths to MIDI data extracted by `MidiController`.
batch_size: Batch size.
seq_len: The length of sequneces.
The length corresponds to the number of `time` splited by `time_fraction`.
time_fraction: Time fraction which means the length of bars.
min_pitch: The minimum of note number.
max_pitch: The maximum of note number.
'''
self.__midi_df_list = midi_df_list
self.__batch_size = batch_size
self.__seq_len = seq_len
self.__time_fraction = time_fraction
self.__min_pitch = min_pitch
self.__max_pitch = max_pitch
self.__dim = self.__max_pitch - self.__min_pitch
[docs] def draw(self):
'''
Draws samples from the `true` distribution.
Returns:
`np.ndarray` of samples.
'''
sampled_arr = np.empty((self.__batch_size, self.__seq_len, self.__dim))
for batch in range(self.__batch_size):
key = np.random.randint(low=0, high=len(self.__midi_df_list))
midi_df = self.__midi_df_list[key]
program_arr = midi_df.program.drop_duplicates().values
key = np.random.randint(low=0, high=program_arr.shape[0])
program_key = program_arr[key]
midi_df = midi_df[midi_df.program == program_key]
if midi_df.shape[0] < self.__seq_len:
raise ValueError("The length of musical performance (program: " + str(program_key) + " is short.")
row = np.random.uniform(
low=midi_df.start.min(),
high=midi_df.end.max() - (self.__seq_len * self.__time_fraction)
)
for seq in range(self.__seq_len):
start = row + (seq * self.__time_fraction)
end = row + ((seq+1) * self.__time_fraction)
df = midi_df[(start <= midi_df.start) & (midi_df.start <= end)]
sampled_arr[batch, seq] = self.__convert_into_feature(df)
return sampled_arr
def __convert_into_feature(self, df):
arr = np.zeros(self.__dim)
for i in range(df.shape[0]):
if df.pitch.values[i] < self.__max_pitch - 1:
if df.pitch.values[i] - self.__min_pitch >= 0:
arr[df.pitch.values[i] - self.__min_pitch] = 1
return arr.reshape(1, -1).astype(float)