Dmytro Lopushanskyy
commited on
Commit
·
c12a65c
1
Parent(s):
7b9a464
upload base version
Browse files- .DS_Store +0 -0
- .gitattributes +2 -0
- .ipynb_checkpoints/main-checkpoint.ipynb +294 -0
- .ipynb_checkpoints/music_generation_with_Variational_AE-checkpoint.ipynb +0 -0
- app.py +190 -0
- examples/.DS_Store +0 -0
- examples/beethoven.midi +0 -0
- examples/chopin.midi +0 -0
- examples/mozart.midi +0 -0
- main.ipynb +317 -0
- objects/.DS_Store +0 -0
- objects/int_to_note.pkl +3 -0
- objects/model.pkl +3 -0
- objects/model_cpu.pkl +3 -0
- objects/note_to_int.pkl +3 -0
- packages.txt +3 -0
- requirements.txt +10 -0
.DS_Store
ADDED
Binary file (6.15 kB). View file
|
|
.gitattributes
CHANGED
@@ -1,4 +1,5 @@
|
|
1 |
*.7z filter=lfs diff=lfs merge=lfs -text
|
|
|
2 |
*.arrow filter=lfs diff=lfs merge=lfs -text
|
3 |
*.bin filter=lfs diff=lfs merge=lfs -text
|
4 |
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
@@ -25,3 +26,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
25 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
26 |
*.zstandard filter=lfs diff=lfs merge=lfs -text
|
27 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
1 |
*.7z filter=lfs diff=lfs merge=lfs -text
|
2 |
+
*.pkl filter=lfs diff=lfs merge=lfs -text
|
3 |
*.arrow filter=lfs diff=lfs merge=lfs -text
|
4 |
*.bin filter=lfs diff=lfs merge=lfs -text
|
5 |
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
|
|
26 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
27 |
*.zstandard filter=lfs diff=lfs merge=lfs -text
|
28 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
29 |
+
objects/*.pkl filter=lfs diff=lfs merge=lfs -text
|
.ipynb_checkpoints/main-checkpoint.ipynb
ADDED
@@ -0,0 +1,294 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"cells": [
|
3 |
+
{
|
4 |
+
"cell_type": "code",
|
5 |
+
"execution_count": 11,
|
6 |
+
"id": "61e10139",
|
7 |
+
"metadata": {},
|
8 |
+
"outputs": [],
|
9 |
+
"source": [
|
10 |
+
"import pickle\n",
|
11 |
+
"from music21 import *"
|
12 |
+
]
|
13 |
+
},
|
14 |
+
{
|
15 |
+
"cell_type": "code",
|
16 |
+
"execution_count": 3,
|
17 |
+
"id": "1a2b28be",
|
18 |
+
"metadata": {},
|
19 |
+
"outputs": [],
|
20 |
+
"source": [
|
21 |
+
"import torch\n",
|
22 |
+
"import torch.nn as nn\n",
|
23 |
+
"from torch.nn import functional as F\n",
|
24 |
+
"\n",
|
25 |
+
"device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n",
|
26 |
+
"\n",
|
27 |
+
"class GenerationRNN(nn.Module):\n",
|
28 |
+
" def __init__(self, input_size, hidden_size, output_size, n_layers=1):\n",
|
29 |
+
" super(GenerationRNN, self).__init__()\n",
|
30 |
+
" self.input_size = input_size\n",
|
31 |
+
" self.hidden_size = hidden_size\n",
|
32 |
+
" self.output_size = output_size\n",
|
33 |
+
" self.n_layers = n_layers\n",
|
34 |
+
" \n",
|
35 |
+
" self.embedding = nn.Embedding(input_size, hidden_size)\n",
|
36 |
+
" self.gru = nn.GRU(hidden_size, hidden_size, n_layers)\n",
|
37 |
+
" self.decoder = nn.Linear(hidden_size * n_layers, output_size)\n",
|
38 |
+
" \n",
|
39 |
+
" def forward(self, input, hidden):\n",
|
40 |
+
" # Creates embedding of the input texts\n",
|
41 |
+
" #print('initial input', input.size())\n",
|
42 |
+
" input = self.embedding(input.view(1, -1))\n",
|
43 |
+
" #print('input after embedding', input.size())\n",
|
44 |
+
" output, hidden = self.gru(input, hidden)\n",
|
45 |
+
" #print('output after gru', output.size())\n",
|
46 |
+
" #print('hidden after gru', hidden.size())\n",
|
47 |
+
" output = self.decoder(hidden.view(1, -1))\n",
|
48 |
+
" #print('output after decoder', output.size())\n",
|
49 |
+
" return output, hidden\n",
|
50 |
+
"\n",
|
51 |
+
" def init_hidden(self):\n",
|
52 |
+
" return torch.zeros(self.n_layers, 1, self.hidden_size).to(device)"
|
53 |
+
]
|
54 |
+
},
|
55 |
+
{
|
56 |
+
"cell_type": "code",
|
57 |
+
"execution_count": 4,
|
58 |
+
"id": "5b7120cf",
|
59 |
+
"metadata": {},
|
60 |
+
"outputs": [],
|
61 |
+
"source": [
|
62 |
+
"def predict_multimomial(net, prime_seq, predict_len, temperature=0.8):\n",
|
63 |
+
" '''\n",
|
64 |
+
" Arguments:\n",
|
65 |
+
" prime_seq - priming sequence (converted t)\n",
|
66 |
+
" predict_len - number of notes to predict for after prime sequence\n",
|
67 |
+
" '''\n",
|
68 |
+
" hidden = net.init_hidden()\n",
|
69 |
+
"\n",
|
70 |
+
" predicted = prime_seq.copy()\n",
|
71 |
+
" prime_seq = torch.tensor(prime_seq, dtype = torch.long).to(device)\n",
|
72 |
+
"\n",
|
73 |
+
"\n",
|
74 |
+
" # \"Building up\" the hidden state using the prime sequence\n",
|
75 |
+
" for p in range(len(prime_seq) - 1):\n",
|
76 |
+
" input = prime_seq[p]\n",
|
77 |
+
" _, hidden = net(input, hidden)\n",
|
78 |
+
" \n",
|
79 |
+
" # Last character of prime sequence\n",
|
80 |
+
" input = prime_seq[-1]\n",
|
81 |
+
" \n",
|
82 |
+
" # For every index to predict\n",
|
83 |
+
" for p in range(predict_len):\n",
|
84 |
+
"\n",
|
85 |
+
" # Pass the inputs to the model - output has dimension n_pitches - scores for each of the possible characters\n",
|
86 |
+
" output, hidden = net(input, hidden)\n",
|
87 |
+
" # Sample from the network output as a multinomial distribution\n",
|
88 |
+
" output = output.data.view(-1).div(temperature).exp()\n",
|
89 |
+
" predicted_id = torch.multinomial(output, 1)\n",
|
90 |
+
"\n",
|
91 |
+
" # Add predicted index to the list and use as next input\n",
|
92 |
+
" predicted.append(predicted_id.item()) \n",
|
93 |
+
" input = predicted_id\n",
|
94 |
+
"\n",
|
95 |
+
" return predicted"
|
96 |
+
]
|
97 |
+
},
|
98 |
+
{
|
99 |
+
"cell_type": "code",
|
100 |
+
"execution_count": 5,
|
101 |
+
"id": "8ce30142",
|
102 |
+
"metadata": {},
|
103 |
+
"outputs": [],
|
104 |
+
"source": [
|
105 |
+
"file_path = '/home/dmytro/ucu/music-generation/model.pkl'\n",
|
106 |
+
"with open(file_path, 'rb') as f:\n",
|
107 |
+
" model = pickle.load(f)"
|
108 |
+
]
|
109 |
+
},
|
110 |
+
{
|
111 |
+
"cell_type": "code",
|
112 |
+
"execution_count": 6,
|
113 |
+
"id": "84a2ea9b",
|
114 |
+
"metadata": {},
|
115 |
+
"outputs": [],
|
116 |
+
"source": [
|
117 |
+
"file_path = '/home/dmytro/ucu/music-generation/int_to_note.pkl'\n",
|
118 |
+
"with open(file_path, 'rb') as f:\n",
|
119 |
+
" int_to_note = pickle.load(f)"
|
120 |
+
]
|
121 |
+
},
|
122 |
+
{
|
123 |
+
"cell_type": "code",
|
124 |
+
"execution_count": 12,
|
125 |
+
"id": "07815507",
|
126 |
+
"metadata": {},
|
127 |
+
"outputs": [],
|
128 |
+
"source": [
|
129 |
+
"def create_midi(prediction_output):\n",
|
130 |
+
" \"\"\" convert the output from the prediction to notes and create a midi file\n",
|
131 |
+
" from the notes \"\"\"\n",
|
132 |
+
" offset = 0\n",
|
133 |
+
" output_notes = []\n",
|
134 |
+
"\n",
|
135 |
+
" # create note and chord objects based on the values generated by the model\n",
|
136 |
+
" for pattern in prediction_output:\n",
|
137 |
+
" # pattern is a chord\n",
|
138 |
+
" if ('.' in pattern) or pattern.isdigit():\n",
|
139 |
+
" notes_in_chord = pattern.split('.')\n",
|
140 |
+
" notes = []\n",
|
141 |
+
" for current_note in notes_in_chord:\n",
|
142 |
+
" new_note = note.Note(int(current_note))\n",
|
143 |
+
" new_note.storedInstrument = instrument.Piano()\n",
|
144 |
+
" notes.append(new_note)\n",
|
145 |
+
" new_chord = chord.Chord(notes)\n",
|
146 |
+
" new_chord.offset = offset\n",
|
147 |
+
" output_notes.append(new_chord)\n",
|
148 |
+
" # pattern is a note\n",
|
149 |
+
" else:\n",
|
150 |
+
" new_note = note.Note(pattern)\n",
|
151 |
+
" new_note.offset = offset\n",
|
152 |
+
" new_note.storedInstrument = instrument.Piano()\n",
|
153 |
+
" output_notes.append(new_note)\n",
|
154 |
+
"\n",
|
155 |
+
" # increase offset each iteration so that notes do not stack\n",
|
156 |
+
" offset += 0.5\n",
|
157 |
+
"\n",
|
158 |
+
" midi_stream = stream.Stream(output_notes)\n",
|
159 |
+
"\n",
|
160 |
+
" return midi_stream"
|
161 |
+
]
|
162 |
+
},
|
163 |
+
{
|
164 |
+
"cell_type": "code",
|
165 |
+
"execution_count": 30,
|
166 |
+
"id": "a70a41f1",
|
167 |
+
"metadata": {},
|
168 |
+
"outputs": [],
|
169 |
+
"source": [
|
170 |
+
"input_melody = [727,\n",
|
171 |
+
" 224,\n",
|
172 |
+
" 55,\n",
|
173 |
+
" 55,\n",
|
174 |
+
" 727,\n",
|
175 |
+
" 224,\n",
|
176 |
+
" 55]\n"
|
177 |
+
]
|
178 |
+
},
|
179 |
+
{
|
180 |
+
"cell_type": "code",
|
181 |
+
"execution_count": 28,
|
182 |
+
"id": "c9afc0c0",
|
183 |
+
"metadata": {},
|
184 |
+
"outputs": [],
|
185 |
+
"source": [
|
186 |
+
"generated_seq_multinomial = predict_multimomial(model, input_melody, predict_len = 100, temperature = 2.2)\n",
|
187 |
+
"generated_seq_multinomial = [int_to_note[e] for e in generated_seq_multinomial]\n",
|
188 |
+
"pred_midi_multinomial = create_midi(generated_seq_multinomial)"
|
189 |
+
]
|
190 |
+
},
|
191 |
+
{
|
192 |
+
"cell_type": "code",
|
193 |
+
"execution_count": 29,
|
194 |
+
"id": "99a1aabe",
|
195 |
+
"metadata": {},
|
196 |
+
"outputs": [
|
197 |
+
{
|
198 |
+
"data": {
|
199 |
+
"text/plain": [
|
200 |
+
"'/home/dmytro/ucu/music-generation/output/new_2.mid'"
|
201 |
+
]
|
202 |
+
},
|
203 |
+
"execution_count": 29,
|
204 |
+
"metadata": {},
|
205 |
+
"output_type": "execute_result"
|
206 |
+
}
|
207 |
+
],
|
208 |
+
"source": [
|
209 |
+
"pred_midi_multinomial.write('midi', fp='result.mid')"
|
210 |
+
]
|
211 |
+
},
|
212 |
+
{
|
213 |
+
"cell_type": "code",
|
214 |
+
"execution_count": null,
|
215 |
+
"id": "ba84139a",
|
216 |
+
"metadata": {},
|
217 |
+
"outputs": [],
|
218 |
+
"source": [
|
219 |
+
"sound_font = \"/usr/share/sounds/sf2/FluidR3_GM.sf2\"\n",
|
220 |
+
"FluidSynth(sound_font).midi_to_audio('result.midi', 'result.wav')\n",
|
221 |
+
"return 'result.wav', 'result.midi'"
|
222 |
+
]
|
223 |
+
},
|
224 |
+
{
|
225 |
+
"cell_type": "code",
|
226 |
+
"execution_count": null,
|
227 |
+
"id": "0f4481b8",
|
228 |
+
"metadata": {},
|
229 |
+
"outputs": [],
|
230 |
+
"source": [
|
231 |
+
"def process_input():\n",
|
232 |
+
" pass"
|
233 |
+
]
|
234 |
+
},
|
235 |
+
{
|
236 |
+
"cell_type": "code",
|
237 |
+
"execution_count": null,
|
238 |
+
"id": "2f2e7a91",
|
239 |
+
"metadata": {},
|
240 |
+
"outputs": [],
|
241 |
+
"source": [
|
242 |
+
"midi_file_desc = \"\"\"Please entUpload your own MIDI file here (try to keep it small).\n",
|
243 |
+
"If you do not have a MIDI file, add some text and we will turn it into music!\n",
|
244 |
+
"\"\"\"\n",
|
245 |
+
"\n",
|
246 |
+
"article = \"\"\"# Pop Music Transformer\n",
|
247 |
+
"We are using a language model to create music by treating a musical standard MIDI a simple text, with tokens for note values, note duration, and separations to denote movement forward in time.\n",
|
248 |
+
"\n",
|
249 |
+
"This is all following the great work you can find [at this repo](https://github.com/bearpelican/musicautobot). Moreover check out [their full web app](http://musicautobot.com/). We use the pretrained model they created as well as the utilities for converting between MIDI, audio streams, numpy encodings, and WAV files.\n",
|
250 |
+
"\n",
|
251 |
+
"## Sonification\n",
|
252 |
+
"\n",
|
253 |
+
"This is the process of turning something not inherently musical into music. Here we do something pretty simple. We take your input text \"pretty cool\", get a sentiment score (hard coded right now, model TODO), and use a major progression if it's positive and a minor progression if it's negative, and then factor the score into the randomness of the generated music. We also take the text and extract a melody by taking any of the letters from A to G, which in the example is just \"E C\". With the simple \"E C\" melody and a major progression a musical idea is generated.\n",
|
254 |
+
"\"\"\"\n",
|
255 |
+
"\n",
|
256 |
+
"iface = gr.Interface(\n",
|
257 |
+
" fn=process_input, \n",
|
258 |
+
" inputs=[\n",
|
259 |
+
" gr.inputs.File(optional=True, label=midi_file_desc),\n",
|
260 |
+
" \"text\", \n",
|
261 |
+
" gr.inputs.Slider(0, 250, default=100, step=50),\n",
|
262 |
+
" gr.inputs.Radio([100, 200, 500], type=\"value\", default=100)\n",
|
263 |
+
" ], \n",
|
264 |
+
" outputs=[\"audio\", \"file\"],\n",
|
265 |
+
" article=article\n",
|
266 |
+
" # examples=['C major scale.midi']\n",
|
267 |
+
")\n",
|
268 |
+
"\n",
|
269 |
+
"iface.launch()"
|
270 |
+
]
|
271 |
+
}
|
272 |
+
],
|
273 |
+
"metadata": {
|
274 |
+
"kernelspec": {
|
275 |
+
"display_name": "Python 3 (ipykernel)",
|
276 |
+
"language": "python",
|
277 |
+
"name": "python3"
|
278 |
+
},
|
279 |
+
"language_info": {
|
280 |
+
"codemirror_mode": {
|
281 |
+
"name": "ipython",
|
282 |
+
"version": 3
|
283 |
+
},
|
284 |
+
"file_extension": ".py",
|
285 |
+
"mimetype": "text/x-python",
|
286 |
+
"name": "python",
|
287 |
+
"nbconvert_exporter": "python",
|
288 |
+
"pygments_lexer": "ipython3",
|
289 |
+
"version": "3.9.12"
|
290 |
+
}
|
291 |
+
},
|
292 |
+
"nbformat": 4,
|
293 |
+
"nbformat_minor": 5
|
294 |
+
}
|
.ipynb_checkpoints/music_generation_with_Variational_AE-checkpoint.ipynb
ADDED
The diff for this file is too large to render.
See raw diff
|
|
app.py
ADDED
@@ -0,0 +1,190 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pickle
|
2 |
+
import pretty_midi
|
3 |
+
from music21 import *
|
4 |
+
from midi2audio import FluidSynth
|
5 |
+
|
6 |
+
import torch
|
7 |
+
import torch.nn as nn
|
8 |
+
from torch.nn import functional as F
|
9 |
+
|
10 |
+
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
|
11 |
+
|
12 |
+
file_path = './objects/int_to_note.pkl'
|
13 |
+
with open(file_path, 'rb') as f:
|
14 |
+
int_to_note = pickle.load(f)
|
15 |
+
|
16 |
+
file_path = './objects/note_to_int.pkl'
|
17 |
+
with open(file_path, 'rb') as f:
|
18 |
+
note_to_int = pickle.load(f)
|
19 |
+
|
20 |
+
|
21 |
+
class GenerationRNN(nn.Module):
|
22 |
+
def __init__(self, input_size, hidden_size, output_size, n_layers=1):
|
23 |
+
super(GenerationRNN, self).__init__()
|
24 |
+
self.input_size = input_size
|
25 |
+
self.hidden_size = hidden_size
|
26 |
+
self.output_size = output_size
|
27 |
+
self.n_layers = n_layers
|
28 |
+
|
29 |
+
self.embedding = nn.Embedding(input_size, hidden_size)
|
30 |
+
self.gru = nn.GRU(hidden_size, hidden_size, n_layers)
|
31 |
+
self.decoder = nn.Linear(hidden_size * n_layers, output_size)
|
32 |
+
|
33 |
+
def forward(self, input, hidden):
|
34 |
+
# Creates embedding of the input texts
|
35 |
+
#print('initial input', input.size())
|
36 |
+
input = self.embedding(input.view(1, -1))
|
37 |
+
#print('input after embedding', input.size())
|
38 |
+
output, hidden = self.gru(input, hidden)
|
39 |
+
#print('output after gru', output.size())
|
40 |
+
#print('hidden after gru', hidden.size())
|
41 |
+
output = self.decoder(hidden.view(1, -1))
|
42 |
+
#print('output after decoder', output.size())
|
43 |
+
return output, hidden
|
44 |
+
|
45 |
+
def init_hidden(self):
|
46 |
+
return torch.zeros(self.n_layers, 1, self.hidden_size).to(device)
|
47 |
+
|
48 |
+
|
49 |
+
def predict_multimomial(net, prime_seq, predict_len, temperature=0.8):
|
50 |
+
'''
|
51 |
+
Arguments:
|
52 |
+
prime_seq - priming sequence (converted t)
|
53 |
+
predict_len - number of notes to predict for after prime sequence
|
54 |
+
'''
|
55 |
+
hidden = net.init_hidden()
|
56 |
+
|
57 |
+
predicted = prime_seq.copy()
|
58 |
+
prime_seq = torch.tensor(prime_seq, dtype = torch.long).to(device)
|
59 |
+
|
60 |
+
|
61 |
+
# "Building up" the hidden state using the prime sequence
|
62 |
+
for p in range(len(prime_seq) - 1):
|
63 |
+
input = prime_seq[p]
|
64 |
+
_, hidden = net(input, hidden)
|
65 |
+
|
66 |
+
# Last character of prime sequence
|
67 |
+
input = prime_seq[-1]
|
68 |
+
|
69 |
+
# For every index to predict
|
70 |
+
for p in range(predict_len):
|
71 |
+
|
72 |
+
# Pass the inputs to the model - output has dimension n_pitches - scores for each of the possible characters
|
73 |
+
output, hidden = net(input, hidden)
|
74 |
+
# Sample from the network output as a multinomial distribution
|
75 |
+
output = output.data.view(-1).div(temperature).exp()
|
76 |
+
predicted_id = torch.multinomial(output, 1)
|
77 |
+
|
78 |
+
# Add predicted index to the list and use as next input
|
79 |
+
predicted.append(predicted_id.item())
|
80 |
+
input = predicted_id
|
81 |
+
|
82 |
+
return predicted
|
83 |
+
|
84 |
+
|
85 |
+
def create_midi(prediction_output):
|
86 |
+
""" convert the output from the prediction to notes and create a midi file
|
87 |
+
from the notes """
|
88 |
+
offset = 0
|
89 |
+
output_notes = []
|
90 |
+
|
91 |
+
# create note and chord objects based on the values generated by the model
|
92 |
+
for pattern in prediction_output:
|
93 |
+
# pattern is a chord
|
94 |
+
if ('.' in pattern) or pattern.isdigit():
|
95 |
+
notes_in_chord = pattern.split('.')
|
96 |
+
notes = []
|
97 |
+
for current_note in notes_in_chord:
|
98 |
+
new_note = note.Note(int(current_note))
|
99 |
+
new_note.storedInstrument = instrument.Piano()
|
100 |
+
notes.append(new_note)
|
101 |
+
new_chord = chord.Chord(notes)
|
102 |
+
new_chord.offset = offset
|
103 |
+
output_notes.append(new_chord)
|
104 |
+
# pattern is a note
|
105 |
+
else:
|
106 |
+
new_note = note.Note(pattern)
|
107 |
+
new_note.offset = offset
|
108 |
+
new_note.storedInstrument = instrument.Piano()
|
109 |
+
output_notes.append(new_note)
|
110 |
+
|
111 |
+
# increase offset each iteration so that notes do not stack
|
112 |
+
offset += 0.5
|
113 |
+
|
114 |
+
midi_stream = stream.Stream(output_notes)
|
115 |
+
|
116 |
+
return midi_stream
|
117 |
+
|
118 |
+
|
119 |
+
def get_note_names(midi):
|
120 |
+
s2 = instrument.partitionByInstrument(midi)
|
121 |
+
|
122 |
+
piano_part = None
|
123 |
+
# Filter for only the piano part
|
124 |
+
instr = instrument.Piano
|
125 |
+
for part in s2:
|
126 |
+
if isinstance(part.getInstrument(), instr):
|
127 |
+
piano_part = part
|
128 |
+
|
129 |
+
notes_song = []
|
130 |
+
if not piano_part: # Some songs somehow have no piano parts
|
131 |
+
# Just take the first part
|
132 |
+
piano_part = s2[0]
|
133 |
+
|
134 |
+
for element in piano_part:
|
135 |
+
if isinstance(element, note.Note):
|
136 |
+
# Return the pitch of the single note
|
137 |
+
notes_song.append(str(element.pitch))
|
138 |
+
elif isinstance(element, chord.Chord):
|
139 |
+
# Returns the normal order of a Chord represented in a list of integers
|
140 |
+
notes_song.append('.'.join(str(n) for n in element.normalOrder))
|
141 |
+
|
142 |
+
return notes_song
|
143 |
+
|
144 |
+
|
145 |
+
def process_input(input_midi_file, input_randomness, input_duration):
|
146 |
+
midi = converter.parse(input_midi_file)
|
147 |
+
note_names = get_note_names(midi)
|
148 |
+
int_notes = [note_to_int[note_name] for note_name in note_names]
|
149 |
+
|
150 |
+
generated_seq_multinomial = predict_multimomial(model, int_notes, predict_len = 100, temperature = 2.2)
|
151 |
+
generated_seq_multinomial = [int_to_note[e] for e in generated_seq_multinomial]
|
152 |
+
pred_midi_multinomial = create_midi(generated_seq_multinomial)
|
153 |
+
|
154 |
+
pred_midi_multinomial.write('midi', fp='result.midi')
|
155 |
+
|
156 |
+
# sound_font = "/usr/share/sounds/sf2/FluidR3_GM.sf2"
|
157 |
+
FluidSynth().midi_to_audio('result.midi', 'result.wav')
|
158 |
+
return 'result.wav', 'result.midi'
|
159 |
+
|
160 |
+
|
161 |
+
file_path = './objects/model_cpu.pkl'
|
162 |
+
with open(file_path, 'rb') as f:
|
163 |
+
model = pickle.load(f)
|
164 |
+
|
165 |
+
|
166 |
+
midi_file_desc = """
|
167 |
+
This model allows to generate music based on your input.
|
168 |
+
Please upload a MIDI file below, choose music randomness and duration. Enjoy!
|
169 |
+
"""
|
170 |
+
|
171 |
+
article = """# Music Generation
|
172 |
+
This project has been created by the students of Ukrainian Catholic University for our ML course.
|
173 |
+
|
174 |
+
We are using a GRU model to output new notes based on the given input. You can find more information at our Git repo: https://github.com/DmytroLopushanskyy/music-generation
|
175 |
+
We are using a language model to create music by treating a musical standard MIDI a simple text, with tokens for note values, note duration, and separations to denote movement forward in time.
|
176 |
+
"""
|
177 |
+
|
178 |
+
iface = gr.Interface(
|
179 |
+
fn=process_input,
|
180 |
+
inputs=[
|
181 |
+
gr.inputs.File(label=midi_file_desc),
|
182 |
+
gr.inputs.Slider(0, 250, default=100, step=50),
|
183 |
+
gr.inputs.Radio([10, 20, 30], type="value", default=20)
|
184 |
+
],
|
185 |
+
outputs=["audio", "file"],
|
186 |
+
article=article,
|
187 |
+
examples=['examples/mozart.midi']
|
188 |
+
)
|
189 |
+
|
190 |
+
iface.launch()
|
examples/.DS_Store
ADDED
Binary file (6.15 kB). View file
|
|
examples/beethoven.midi
ADDED
Binary file (759 Bytes). View file
|
|
examples/chopin.midi
ADDED
Binary file (1.18 kB). View file
|
|
examples/mozart.midi
ADDED
Binary file (761 Bytes). View file
|
|
main.ipynb
ADDED
@@ -0,0 +1,317 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"cells": [
|
3 |
+
{
|
4 |
+
"cell_type": "code",
|
5 |
+
"execution_count": 108,
|
6 |
+
"id": "61e10139",
|
7 |
+
"metadata": {},
|
8 |
+
"outputs": [],
|
9 |
+
"source": [
|
10 |
+
"import pickle\n",
|
11 |
+
"import pretty_midi\n",
|
12 |
+
"from music21 import *\n",
|
13 |
+
"from midi2audio import FluidSynth"
|
14 |
+
]
|
15 |
+
},
|
16 |
+
{
|
17 |
+
"cell_type": "code",
|
18 |
+
"execution_count": 48,
|
19 |
+
"id": "1a2b28be",
|
20 |
+
"metadata": {},
|
21 |
+
"outputs": [],
|
22 |
+
"source": [
|
23 |
+
"import torch\n",
|
24 |
+
"import torch.nn as nn\n",
|
25 |
+
"from torch.nn import functional as F\n",
|
26 |
+
"\n",
|
27 |
+
"device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n",
|
28 |
+
"\n",
|
29 |
+
"class GenerationRNN(nn.Module):\n",
|
30 |
+
" def __init__(self, input_size, hidden_size, output_size, n_layers=1):\n",
|
31 |
+
" super(GenerationRNN, self).__init__()\n",
|
32 |
+
" self.input_size = input_size\n",
|
33 |
+
" self.hidden_size = hidden_size\n",
|
34 |
+
" self.output_size = output_size\n",
|
35 |
+
" self.n_layers = n_layers\n",
|
36 |
+
" \n",
|
37 |
+
" self.embedding = nn.Embedding(input_size, hidden_size)\n",
|
38 |
+
" self.gru = nn.GRU(hidden_size, hidden_size, n_layers)\n",
|
39 |
+
" self.decoder = nn.Linear(hidden_size * n_layers, output_size)\n",
|
40 |
+
" \n",
|
41 |
+
" def forward(self, input, hidden):\n",
|
42 |
+
" # Creates embedding of the input texts\n",
|
43 |
+
" #print('initial input', input.size())\n",
|
44 |
+
" input = self.embedding(input.view(1, -1))\n",
|
45 |
+
" #print('input after embedding', input.size())\n",
|
46 |
+
" output, hidden = self.gru(input, hidden)\n",
|
47 |
+
" #print('output after gru', output.size())\n",
|
48 |
+
" #print('hidden after gru', hidden.size())\n",
|
49 |
+
" output = self.decoder(hidden.view(1, -1))\n",
|
50 |
+
" #print('output after decoder', output.size())\n",
|
51 |
+
" return output, hidden\n",
|
52 |
+
"\n",
|
53 |
+
" def init_hidden(self):\n",
|
54 |
+
" return torch.zeros(self.n_layers, 1, self.hidden_size).to(device)"
|
55 |
+
]
|
56 |
+
},
|
57 |
+
{
|
58 |
+
"cell_type": "code",
|
59 |
+
"execution_count": 49,
|
60 |
+
"id": "5b7120cf",
|
61 |
+
"metadata": {},
|
62 |
+
"outputs": [],
|
63 |
+
"source": [
|
64 |
+
"def predict_multimomial(net, prime_seq, predict_len, temperature=0.8):\n",
|
65 |
+
" '''\n",
|
66 |
+
" Arguments:\n",
|
67 |
+
" prime_seq - priming sequence (converted t)\n",
|
68 |
+
" predict_len - number of notes to predict for after prime sequence\n",
|
69 |
+
" '''\n",
|
70 |
+
" hidden = net.init_hidden()\n",
|
71 |
+
"\n",
|
72 |
+
" predicted = prime_seq.copy()\n",
|
73 |
+
" prime_seq = torch.tensor(prime_seq, dtype = torch.long).to(device)\n",
|
74 |
+
"\n",
|
75 |
+
"\n",
|
76 |
+
" # \"Building up\" the hidden state using the prime sequence\n",
|
77 |
+
" for p in range(len(prime_seq) - 1):\n",
|
78 |
+
" input = prime_seq[p]\n",
|
79 |
+
" _, hidden = net(input, hidden)\n",
|
80 |
+
" \n",
|
81 |
+
" # Last character of prime sequence\n",
|
82 |
+
" input = prime_seq[-1]\n",
|
83 |
+
" \n",
|
84 |
+
" # For every index to predict\n",
|
85 |
+
" for p in range(predict_len):\n",
|
86 |
+
"\n",
|
87 |
+
" # Pass the inputs to the model - output has dimension n_pitches - scores for each of the possible characters\n",
|
88 |
+
" output, hidden = net(input, hidden)\n",
|
89 |
+
" # Sample from the network output as a multinomial distribution\n",
|
90 |
+
" output = output.data.view(-1).div(temperature).exp()\n",
|
91 |
+
" predicted_id = torch.multinomial(output, 1)\n",
|
92 |
+
"\n",
|
93 |
+
" # Add predicted index to the list and use as next input\n",
|
94 |
+
" predicted.append(predicted_id.item()) \n",
|
95 |
+
" input = predicted_id\n",
|
96 |
+
"\n",
|
97 |
+
" return predicted"
|
98 |
+
]
|
99 |
+
},
|
100 |
+
{
|
101 |
+
"cell_type": "code",
|
102 |
+
"execution_count": 63,
|
103 |
+
"id": "8ce30142",
|
104 |
+
"metadata": {},
|
105 |
+
"outputs": [],
|
106 |
+
"source": [
|
107 |
+
"file_path = './objects/model_cpu.pkl'\n",
|
108 |
+
"with open(file_path, 'rb') as f:\n",
|
109 |
+
" model = pickle.load(f)"
|
110 |
+
]
|
111 |
+
},
|
112 |
+
{
|
113 |
+
"cell_type": "code",
|
114 |
+
"execution_count": 64,
|
115 |
+
"id": "84a2ea9b",
|
116 |
+
"metadata": {},
|
117 |
+
"outputs": [],
|
118 |
+
"source": [
|
119 |
+
"file_path = './objects/int_to_note.pkl'\n",
|
120 |
+
"with open(file_path, 'rb') as f:\n",
|
121 |
+
" int_to_note = pickle.load(f)"
|
122 |
+
]
|
123 |
+
},
|
124 |
+
{
|
125 |
+
"cell_type": "code",
|
126 |
+
"execution_count": 65,
|
127 |
+
"id": "102cd217",
|
128 |
+
"metadata": {},
|
129 |
+
"outputs": [],
|
130 |
+
"source": [
|
131 |
+
"file_path = './objects/note_to_int.pkl'\n",
|
132 |
+
"with open(file_path, 'rb') as f:\n",
|
133 |
+
" note_to_int = pickle.load(f)"
|
134 |
+
]
|
135 |
+
},
|
136 |
+
{
|
137 |
+
"cell_type": "code",
|
138 |
+
"execution_count": 66,
|
139 |
+
"id": "07815507",
|
140 |
+
"metadata": {},
|
141 |
+
"outputs": [],
|
142 |
+
"source": [
|
143 |
+
"def create_midi(prediction_output):\n",
|
144 |
+
" \"\"\" convert the output from the prediction to notes and create a midi file\n",
|
145 |
+
" from the notes \"\"\"\n",
|
146 |
+
" offset = 0\n",
|
147 |
+
" output_notes = []\n",
|
148 |
+
"\n",
|
149 |
+
" # create note and chord objects based on the values generated by the model\n",
|
150 |
+
" for pattern in prediction_output:\n",
|
151 |
+
" # pattern is a chord\n",
|
152 |
+
" if ('.' in pattern) or pattern.isdigit():\n",
|
153 |
+
" notes_in_chord = pattern.split('.')\n",
|
154 |
+
" notes = []\n",
|
155 |
+
" for current_note in notes_in_chord:\n",
|
156 |
+
" new_note = note.Note(int(current_note))\n",
|
157 |
+
" new_note.storedInstrument = instrument.Piano()\n",
|
158 |
+
" notes.append(new_note)\n",
|
159 |
+
" new_chord = chord.Chord(notes)\n",
|
160 |
+
" new_chord.offset = offset\n",
|
161 |
+
" output_notes.append(new_chord)\n",
|
162 |
+
" # pattern is a note\n",
|
163 |
+
" else:\n",
|
164 |
+
" new_note = note.Note(pattern)\n",
|
165 |
+
" new_note.offset = offset\n",
|
166 |
+
" new_note.storedInstrument = instrument.Piano()\n",
|
167 |
+
" output_notes.append(new_note)\n",
|
168 |
+
"\n",
|
169 |
+
" # increase offset each iteration so that notes do not stack\n",
|
170 |
+
" offset += 0.5\n",
|
171 |
+
"\n",
|
172 |
+
" midi_stream = stream.Stream(output_notes)\n",
|
173 |
+
"\n",
|
174 |
+
" return midi_stream"
|
175 |
+
]
|
176 |
+
},
|
177 |
+
{
|
178 |
+
"cell_type": "code",
|
179 |
+
"execution_count": 113,
|
180 |
+
"id": "ad197703",
|
181 |
+
"metadata": {},
|
182 |
+
"outputs": [],
|
183 |
+
"source": [
|
184 |
+
"def get_note_names(midi):\n",
|
185 |
+
" s2 = instrument.partitionByInstrument(midi)\n",
|
186 |
+
"\n",
|
187 |
+
" piano_part = None\n",
|
188 |
+
" # Filter for only the piano part\n",
|
189 |
+
" instr = instrument.Piano\n",
|
190 |
+
" for part in s2:\n",
|
191 |
+
" if isinstance(part.getInstrument(), instr):\n",
|
192 |
+
" piano_part = part\n",
|
193 |
+
"\n",
|
194 |
+
" notes_song = []\n",
|
195 |
+
" if not piano_part: # Some songs somehow have no piano parts\n",
|
196 |
+
" # Just take the first part\n",
|
197 |
+
" piano_part = s2[0]\n",
|
198 |
+
" \n",
|
199 |
+
" for element in piano_part:\n",
|
200 |
+
" if isinstance(element, note.Note):\n",
|
201 |
+
" # Return the pitch of the single note\n",
|
202 |
+
" notes_song.append(str(element.pitch))\n",
|
203 |
+
" elif isinstance(element, chord.Chord):\n",
|
204 |
+
" # Returns the normal order of a Chord represented in a list of integers\n",
|
205 |
+
" notes_song.append('.'.join(str(n) for n in element.normalOrder))\n",
|
206 |
+
" \n",
|
207 |
+
" return notes_song"
|
208 |
+
]
|
209 |
+
},
|
210 |
+
{
|
211 |
+
"cell_type": "code",
|
212 |
+
"execution_count": 114,
|
213 |
+
"id": "0d1140d7",
|
214 |
+
"metadata": {},
|
215 |
+
"outputs": [],
|
216 |
+
"source": [
|
217 |
+
"def process_input(input_midi_file, input_randomness, input_duration):\n",
|
218 |
+
" midi = converter.parse(input_midi_file)\n",
|
219 |
+
" note_names = get_note_names(midi)\n",
|
220 |
+
" int_notes = [note_to_int[note_name] for note_name in note_names]\n",
|
221 |
+
" \n",
|
222 |
+
" generated_seq_multinomial = predict_multimomial(model, int_notes, predict_len = 100, temperature = 2.2)\n",
|
223 |
+
" generated_seq_multinomial = [int_to_note[e] for e in generated_seq_multinomial]\n",
|
224 |
+
" pred_midi_multinomial = create_midi(generated_seq_multinomial)\n",
|
225 |
+
" \n",
|
226 |
+
" pred_midi_multinomial.write('midi', fp='result.midi')\n",
|
227 |
+
" \n",
|
228 |
+
" # sound_font = \"/usr/share/sounds/sf2/FluidR3_GM.sf2\"\n",
|
229 |
+
" FluidSynth().midi_to_audio('result.midi', 'result.wav')\n",
|
230 |
+
" return 'result.wav', 'result.midi'"
|
231 |
+
]
|
232 |
+
},
|
233 |
+
{
|
234 |
+
"cell_type": "code",
|
235 |
+
"execution_count": 115,
|
236 |
+
"id": "7227d54b",
|
237 |
+
"metadata": {},
|
238 |
+
"outputs": [
|
239 |
+
{
|
240 |
+
"ename": "FileNotFoundError",
|
241 |
+
"evalue": "[Errno 2] No such file or directory: 'fluidsynth'",
|
242 |
+
"output_type": "error",
|
243 |
+
"traceback": [
|
244 |
+
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
245 |
+
"\u001b[0;31mFileNotFoundError\u001b[0m Traceback (most recent call last)",
|
246 |
+
"Input \u001b[0;32mIn [115]\u001b[0m, in \u001b[0;36m<cell line: 2>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m example_path \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m/Users/dmytrolopushanskyy/Documents/ucu/music-generation/examples/mozart.midi\u001b[39m\u001b[38;5;124m'\u001b[39m\n\u001b[0;32m----> 2\u001b[0m \u001b[43mprocess_input\u001b[49m\u001b[43m(\u001b[49m\u001b[43mexample_path\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m2\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m3\u001b[39;49m\u001b[43m)\u001b[49m\n",
|
247 |
+
"Input \u001b[0;32mIn [114]\u001b[0m, in \u001b[0;36mprocess_input\u001b[0;34m(input_midi_file, input_randomness, input_duration)\u001b[0m\n\u001b[1;32m 10\u001b[0m pred_midi_multinomial\u001b[38;5;241m.\u001b[39mwrite(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mmidi\u001b[39m\u001b[38;5;124m'\u001b[39m, fp\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mresult.midi\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[1;32m 12\u001b[0m sound_font \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m/usr/share/sounds/sf2/FluidR3_GM.sf2\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m---> 13\u001b[0m \u001b[43mFluidSynth\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmidi_to_audio\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mresult.midi\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mresult.wav\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 14\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mresult.wav\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mresult.midi\u001b[39m\u001b[38;5;124m'\u001b[39m\n",
|
248 |
+
"File \u001b[0;32m~/miniconda3/envs/hugface-demo/lib/python3.9/site-packages/midi2audio.py:46\u001b[0m, in \u001b[0;36mFluidSynth.midi_to_audio\u001b[0;34m(self, midi_file, audio_file)\u001b[0m\n\u001b[1;32m 45\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mmidi_to_audio\u001b[39m(\u001b[38;5;28mself\u001b[39m, midi_file, audio_file):\n\u001b[0;32m---> 46\u001b[0m \u001b[43msubprocess\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcall\u001b[49m\u001b[43m(\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mfluidsynth\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43m-ni\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msound_font\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mmidi_file\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43m-F\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43maudio_file\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43m-r\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mstr\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msample_rate\u001b[49m\u001b[43m)\u001b[49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n",
|
249 |
+
"File \u001b[0;32m~/miniconda3/envs/hugface-demo/lib/python3.9/subprocess.py:349\u001b[0m, in \u001b[0;36mcall\u001b[0;34m(timeout, *popenargs, **kwargs)\u001b[0m\n\u001b[1;32m 341\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mcall\u001b[39m(\u001b[38;5;241m*\u001b[39mpopenargs, timeout\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs):\n\u001b[1;32m 342\u001b[0m \u001b[38;5;124;03m\"\"\"Run command with arguments. Wait for command to complete or\u001b[39;00m\n\u001b[1;32m 343\u001b[0m \u001b[38;5;124;03m timeout, then return the returncode attribute.\u001b[39;00m\n\u001b[1;32m 344\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 347\u001b[0m \u001b[38;5;124;03m retcode = call([\"ls\", \"-l\"])\u001b[39;00m\n\u001b[1;32m 348\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m--> 349\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[43mPopen\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mpopenargs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m p:\n\u001b[1;32m 350\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 351\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m p\u001b[38;5;241m.\u001b[39mwait(timeout\u001b[38;5;241m=\u001b[39mtimeout)\n",
|
250 |
+
"File \u001b[0;32m~/miniconda3/envs/hugface-demo/lib/python3.9/subprocess.py:951\u001b[0m, in \u001b[0;36mPopen.__init__\u001b[0;34m(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, user, group, extra_groups, encoding, errors, text, umask)\u001b[0m\n\u001b[1;32m 947\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtext_mode:\n\u001b[1;32m 948\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstderr \u001b[38;5;241m=\u001b[39m io\u001b[38;5;241m.\u001b[39mTextIOWrapper(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstderr,\n\u001b[1;32m 949\u001b[0m encoding\u001b[38;5;241m=\u001b[39mencoding, errors\u001b[38;5;241m=\u001b[39merrors)\n\u001b[0;32m--> 951\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_execute_child\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mexecutable\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mpreexec_fn\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mclose_fds\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 952\u001b[0m \u001b[43m \u001b[49m\u001b[43mpass_fds\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcwd\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43menv\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 953\u001b[0m \u001b[43m \u001b[49m\u001b[43mstartupinfo\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcreationflags\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mshell\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 954\u001b[0m \u001b[43m \u001b[49m\u001b[43mp2cread\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mp2cwrite\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 955\u001b[0m \u001b[43m \u001b[49m\u001b[43mc2pread\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mc2pwrite\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 956\u001b[0m \u001b[43m \u001b[49m\u001b[43merrread\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43merrwrite\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 957\u001b[0m \u001b[43m \u001b[49m\u001b[43mrestore_signals\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 958\u001b[0m \u001b[43m \u001b[49m\u001b[43mgid\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mgids\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43muid\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mumask\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 959\u001b[0m \u001b[43m \u001b[49m\u001b[43mstart_new_session\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 960\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m:\n\u001b[1;32m 961\u001b[0m \u001b[38;5;66;03m# Cleanup if the child failed starting.\u001b[39;00m\n\u001b[1;32m 962\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m f \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mfilter\u001b[39m(\u001b[38;5;28;01mNone\u001b[39;00m, (\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstdin, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstdout, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstderr)):\n",
|
251 |
+
"File \u001b[0;32m~/miniconda3/envs/hugface-demo/lib/python3.9/subprocess.py:1821\u001b[0m, in \u001b[0;36mPopen._execute_child\u001b[0;34m(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session)\u001b[0m\n\u001b[1;32m 1819\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m errno_num \u001b[38;5;241m!=\u001b[39m \u001b[38;5;241m0\u001b[39m:\n\u001b[1;32m 1820\u001b[0m err_msg \u001b[38;5;241m=\u001b[39m os\u001b[38;5;241m.\u001b[39mstrerror(errno_num)\n\u001b[0;32m-> 1821\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m child_exception_type(errno_num, err_msg, err_filename)\n\u001b[1;32m 1822\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m child_exception_type(err_msg)\n",
|
252 |
+
"\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: 'fluidsynth'"
|
253 |
+
]
|
254 |
+
}
|
255 |
+
],
|
256 |
+
"source": [
|
257 |
+
"example_path = '/Users/dmytrolopushanskyy/Documents/ucu/music-generation/examples/mozart.midi'\n",
|
258 |
+
"process_input(example_path, 2, 3)"
|
259 |
+
]
|
260 |
+
},
|
261 |
+
{
|
262 |
+
"cell_type": "code",
|
263 |
+
"execution_count": null,
|
264 |
+
"id": "01491a9f",
|
265 |
+
"metadata": {},
|
266 |
+
"outputs": [],
|
267 |
+
"source": [
|
268 |
+
"midi_file_desc = \"\"\"\n",
|
269 |
+
"This model allows to generate music based on your input. \n",
|
270 |
+
"Please upload a MIDI file below, choose music randomness and duration. Enjoy!\n",
|
271 |
+
"\"\"\"\n",
|
272 |
+
"\n",
|
273 |
+
"article = \"\"\"# Music Generation\n",
|
274 |
+
"This project has been created by the students of Ukrainian Catholic University for our ML course.\n",
|
275 |
+
"\n",
|
276 |
+
"We are using a GRU model to output new notes based on the given input. You can find more information at our Git repo: https://github.com/DmytroLopushanskyy/music-generation\n",
|
277 |
+
"We are using a language model to create music by treating a musical standard MIDI a simple text, with tokens for note values, note duration, and separations to denote movement forward in time.\n",
|
278 |
+
"\"\"\"\n",
|
279 |
+
"\n",
|
280 |
+
"iface = gr.Interface(\n",
|
281 |
+
" fn=process_input, \n",
|
282 |
+
" inputs=[\n",
|
283 |
+
" gr.inputs.File(label=midi_file_desc),\n",
|
284 |
+
" gr.inputs.Slider(0, 250, default=100, step=50),\n",
|
285 |
+
" gr.inputs.Radio([10, 20, 30], type=\"value\", default=20)\n",
|
286 |
+
" ], \n",
|
287 |
+
" outputs=[\"audio\", \"file\"],\n",
|
288 |
+
" article=article,\n",
|
289 |
+
" examples=['examples/mozart.midi']\n",
|
290 |
+
")\n",
|
291 |
+
"\n",
|
292 |
+
"iface.launch()"
|
293 |
+
]
|
294 |
+
}
|
295 |
+
],
|
296 |
+
"metadata": {
|
297 |
+
"kernelspec": {
|
298 |
+
"display_name": "Python 3 (ipykernel)",
|
299 |
+
"language": "python",
|
300 |
+
"name": "python3"
|
301 |
+
},
|
302 |
+
"language_info": {
|
303 |
+
"codemirror_mode": {
|
304 |
+
"name": "ipython",
|
305 |
+
"version": 3
|
306 |
+
},
|
307 |
+
"file_extension": ".py",
|
308 |
+
"mimetype": "text/x-python",
|
309 |
+
"name": "python",
|
310 |
+
"nbconvert_exporter": "python",
|
311 |
+
"pygments_lexer": "ipython3",
|
312 |
+
"version": "3.9.12"
|
313 |
+
}
|
314 |
+
},
|
315 |
+
"nbformat": 4,
|
316 |
+
"nbformat_minor": 5
|
317 |
+
}
|
objects/.DS_Store
ADDED
Binary file (6.15 kB). View file
|
|
objects/int_to_note.pkl
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:4fe1e610f0141d28688665699dece4874401b0ab34c567d976cf15e9005f4950
|
3 |
+
size 11141
|
objects/model.pkl
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:d7b7367ebab17c01d1d0127193a603335c432525431488c80a7073bc1c607e71
|
3 |
+
size 4615215
|
objects/model_cpu.pkl
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:7b17bffabc953e0d18122c78e9ef6ba7924c536e54e742bd6ca398ecc72a1e1e
|
3 |
+
size 1486285
|
objects/note_to_int.pkl
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:0221d1cb9e7fe0839a8a5c1342006618f917413102968d73b7bc4f0921aed346
|
3 |
+
size 11141
|
packages.txt
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
fluidsynth
|
2 |
+
fluid-soundfont-gm
|
3 |
+
fluid-soundfont-gs
|
requirements.txt
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
musicautobot
|
2 |
+
fastai==1.0.61
|
3 |
+
music21
|
4 |
+
pebble
|
5 |
+
midi2audio
|
6 |
+
spacy
|
7 |
+
transformers
|
8 |
+
gradio
|
9 |
+
pretty_midi
|
10 |
+
pypianoroll
|