-
Notifications
You must be signed in to change notification settings - Fork 18
/
accompany.py
134 lines (103 loc) · 3.55 KB
/
accompany.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import os
import numpy as np
from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation
from keras.optimizers import SGD, Adam, RMSprop
import midi_util
def features(pattern):
'''Construct amplitude and phase spectrum features for single track
drum pattern.'''
f = np.fft.fft(1*(pattern>64))
af = np.abs(f)
pf = np.angle(f)
return np.hstack([af, pf])
def pattern(features):
'''Construct pattern from phase and amplitude features.'''
def prepare_data():
'''Load data, compute features, and construct training set.'''
# Load the data.
# Concatenate all the vectorized
base_dir = '/Users/snikolov/Downloads/groove-monkee-midi-gm'
arrays = []
for root, dirs, files in os.walk(base_dir):
for filename in files:
if filename.split('.')[-1] == 'npy':
array = np.load(os.path.join(root, filename))
arrays.append(array)
seq = np.concatenate(arrays, axis=0)
# Select pitches and construct windows of 32 32nd notes.
pitches = np.array([36,38,42,51])
sel_seq = seq[:, pitches]
windows = []
breaks = range(len(sel_seq))[::32]
for i in xrange(len(breaks)-1):
windows.append(sel_seq[breaks[i]:breaks[i+1]][np.newaxis, :])
windows = np.concatenate(windows[:-1])
# Predict closed hihat (2) from kick (0)
X = np.zeros((windows.shape[0], windows.shape[1] * 2))
Y = np.zeros((windows.shape[0], windows.shape[1] * 2))
for i,w in enumerate(windows):
X[i,:] = features(w[:,0])
Y[i,:] = features(w[:,2])
return windows, X, Y
def init_model():
'''Define, initialize, and return model.'''
model = Sequential()
model.add(Dense(32, input_shape=(64,)))
model.add(Activation('relu'))
model.add(Dropout(0.05))
model.add(Dense(32))
model.add(Activation('relu'))
model.add(Dropout(0.05))
model.add(Dense(64))
model.add(Activation('tanh'))
rms = RMSprop(lr=0.01)
model.compile(loss='mse', optimizer=rms)
return model
def train_model(X, Y, path=None, load=True, save=True):
'''Train a model mapping a kick pattern to an accompanying hihat
pattern.'''
model = init_model()
if path is not None and load:
model.load_weights(path)
batch_size = 16
nb_epoch = 200
model.fit(X, Y,
batch_size=batch_size, nb_epoch=nb_epoch,
show_accuracy=True, verbose=2, validation_split=0.1)
# Save model.
if path is not None and save:
out_dir, out_name = os.path.split(path)
if not os.path.exists(out_dir):
os.makedirs(out_dir)
model.save_weights(path)
return model
def load_model(path):
'''Load a previous model and return it.'''
model = init_model()
model.load_weights(path)
return model
windows, X, y = prepare_data()
model = train_model(X, y, path='models/accompaniment/model')
#model = load_model('models/accompaniment/model')
in_pattern = np.zeros(32)
in_pattern[::8] = 1
in_pattern[2::8] = 1
in_pattern[::5] = 1
x = features(in_pattern)[np.newaxis, :]
y = model.predict(x)
print y
y_amplitude = y[:,:32]
y_phase = y[:,32:]
y_complex = y_amplitude + 1j * y_phase
out_pattern = np.abs(np.fft.ifft(y_complex))
print out_pattern
out_pattern[out_pattern < 0.05] = 0
print out_pattern
out_pattern = (128 * out_pattern).astype(int)
print out_pattern
combined_pattern = np.vstack([in_pattern, out_pattern])
print combined_pattern
mid = midi_util.array_to_midi(combined_pattern.transpose(),
'test', quantization=5)
mid.save('beatzzz.mid')