Wryley1234 commited on
Commit
fbdbc6e
·
1 Parent(s): 9e846ad
Files changed (1) hide show
  1. app.py +198 -50
app.py CHANGED
@@ -1,55 +1,203 @@
1
- from model import PopMusicTransformer
2
- import os
3
- os.environ['CUDA_VISIBLE_DEVICES'] = '-1'
4
- import tensorflow as tf
5
- tf.compat.v1.disable_eager_execution()
6
  import gradio as gr
7
- import requests
8
- import torchtext
9
- import zipfile
10
-
11
- torchtext.utils.download_from_url("https://drive.google.com/uc?id=1gxuTSkF51NP04JZgTE46Pg4KQsbHQKGo", root=".")
12
- torchtext.utils.download_from_url("https://drive.google.com/uc?id=1nAKjaeahlzpVAX0F9wjQEG_hL4UosSbo", root=".")
13
-
14
- with zipfile.ZipFile("REMI-tempo-checkpoint.zip","r") as zip_ref:
15
- zip_ref.extractall(".")
16
- with zipfile.ZipFile("REMI-tempo-chord-checkpoint.zip","r") as zip_ref:
17
- zip_ref.extractall(".")
18
-
19
- url = 'https://github.com/AK391/remi/blob/master/input.midi?raw=true'
20
- r = requests.get(url, allow_redirects=True)
21
- open("input.midi", 'wb').write(r.content)
22
-
23
-
24
- # declare model
25
- model = PopMusicTransformer(
26
- checkpoint='REMI-tempo-checkpoint',
27
- is_training=False)
28
-
29
- def inference(midi):
30
- # generate continuation
31
- model.generate(
32
- n_target_bar=4,
33
- temperature=1.2,
34
- topk=5,
35
- output_path='./result/continuation.midi',
36
- prompt=midi.name)
37
- return './result/continuation.midi'
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
- title = "Pop Music Transformer"
41
- description = "demo for Pop Music Transformer. To use it, simply upload your midi file, or click one of the examples to load them. Read more at the links below."
42
- article = "<p style='text-align: center'><a href='https://arxiv.org/abs/2002.00212'>Pop Music Transformer: Beat-based Modeling and Generation of Expressive Pop Piano Compositions</a> | <a href='https://github.com/YatingMusic/remi'>Github Repo</a></p>"
43
-
44
- examples = [
45
- ['input.midi']
46
- ]
47
- gr.Interface(
48
- inference,
49
- gr.inputs.File(label="Input Midi"),
50
- gr.outputs.File(label="Output Midi"),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  title=title,
52
- description=description,
53
  article=article,
54
- examples=examples
55
- ).launch()
 
 
 
 
 
 
 
1
+ import pickle
2
+ import pretty_midi
 
 
 
3
  import gradio as gr
4
+ from music21 import *
5
+ from midi2audio import FluidSynth
6
+
7
+ import torch
8
+ import torch.nn as nn
9
+ from torch.nn import functional as F
10
+
11
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
12
+
13
+ file_path = './objects/int_to_note.pkl'
14
+ with open(file_path, 'rb') as f:
15
+ int_to_note = pickle.load(f)
16
+
17
+ file_path = './objects/note_to_int.pkl'
18
+ with open(file_path, 'rb') as f:
19
+ note_to_int = pickle.load(f)
20
+
21
+
22
+ class GenerationRNN(nn.Module):
23
+ def __init__(self, input_size, hidden_size, output_size, n_layers=1):
24
+ super(GenerationRNN, self).__init__()
25
+ self.input_size = input_size
26
+ self.hidden_size = hidden_size
27
+ self.output_size = output_size
28
+ self.n_layers = n_layers
 
 
 
 
 
 
29
 
30
+ self.embedding = nn.Embedding(input_size, hidden_size)
31
+ self.gru = nn.GRU(hidden_size, hidden_size, n_layers)
32
+ self.decoder = nn.Linear(hidden_size * n_layers, output_size)
33
+
34
+ def forward(self, input, hidden):
35
+ # Creates embedding of the input texts
36
+ #print('initial input', input.size())
37
+ input = self.embedding(input.view(1, -1))
38
+ #print('input after embedding', input.size())
39
+ output, hidden = self.gru(input, hidden)
40
+ #print('output after gru', output.size())
41
+ #print('hidden after gru', hidden.size())
42
+ output = self.decoder(hidden.view(1, -1))
43
+ #print('output after decoder', output.size())
44
+ return output, hidden
45
+
46
+ def init_hidden(self):
47
+ return torch.zeros(self.n_layers, 1, self.hidden_size).to(device)
48
+
49
+
50
+ def predict_multimomial(net, prime_seq, predict_len, temperature=0.8):
51
+ '''
52
+ Arguments:
53
+ prime_seq - priming sequence (converted t)
54
+ predict_len - number of notes to predict for after prime sequence
55
+ '''
56
+ hidden = net.init_hidden()
57
+
58
+ predicted = prime_seq.copy()
59
+ prime_seq = torch.tensor(prime_seq, dtype = torch.long).to(device)
60
+
61
+
62
+ # "Building up" the hidden state using the prime sequence
63
+ for p in range(len(prime_seq) - 1):
64
+ input = prime_seq[p]
65
+ _, hidden = net(input, hidden)
66
+
67
+ # Last character of prime sequence
68
+ input = prime_seq[-1]
69
+
70
+ # For every index to predict
71
+ for p in range(predict_len):
72
+
73
+ # Pass the inputs to the model - output has dimension n_pitches - scores for each of the possible characters
74
+ output, hidden = net(input, hidden)
75
+ # Sample from the network output as a multinomial distribution
76
+ output = output.data.view(-1).div(temperature).exp()
77
+ predicted_id = torch.multinomial(output, 1)
78
+
79
+ # Add predicted index to the list and use as next input
80
+ predicted.append(predicted_id.item())
81
+ input = predicted_id
82
+
83
+ return predicted
84
+
85
+
86
+ def create_midi(prediction_output):
87
+ """ convert the output from the prediction to notes and create a midi file
88
+ from the notes """
89
+ offset = 0
90
+ output_notes = []
91
+
92
+ # create note and chord objects based on the values generated by the model
93
+ for pattern in prediction_output:
94
+ # pattern is a chord
95
+ if ('.' in pattern) or pattern.isdigit():
96
+ notes_in_chord = pattern.split('.')
97
+ notes = []
98
+ for current_note in notes_in_chord:
99
+ new_note = note.Note(int(current_note))
100
+ new_note.storedInstrument = instrument.Piano()
101
+ notes.append(new_note)
102
+ new_chord = chord.Chord(notes)
103
+ new_chord.offset = offset
104
+ output_notes.append(new_chord)
105
+ # pattern is a note
106
+ else:
107
+ new_note = note.Note(pattern)
108
+ new_note.offset = offset
109
+ new_note.storedInstrument = instrument.Piano()
110
+ output_notes.append(new_note)
111
+
112
+ # increase offset each iteration so that notes do not stack
113
+ offset += 0.5
114
+
115
+ midi_stream = stream.Stream(output_notes)
116
 
117
+ return midi_stream
118
+
119
+
120
+ def get_note_names(midi):
121
+ s2 = instrument.partitionByInstrument(midi)
122
+
123
+ piano_part = None
124
+ # Filter for only the piano part
125
+ instr = instrument.Piano
126
+ for part in s2:
127
+ if isinstance(part.getInstrument(), instr):
128
+ piano_part = part
129
+
130
+ notes_song = []
131
+ if not piano_part: # Some songs somehow have no piano parts
132
+ # Just take the first part
133
+ piano_part = s2[0]
134
+
135
+ for element in piano_part:
136
+ if isinstance(element, note.Note):
137
+ # Return the pitch of the single note
138
+ notes_song.append(str(element.pitch))
139
+ elif isinstance(element, chord.Chord):
140
+ # Returns the normal order of a Chord represented in a list of integers
141
+ notes_song.append('.'.join(str(n) for n in element.normalOrder))
142
+
143
+ return notes_song
144
+
145
+
146
+ def process_input(input_midi_file, input_randomness, input_duration):
147
+ print(input_midi_file.name)
148
+ midi = converter.parse(input_midi_file.name)
149
+ note_names = get_note_names(midi)
150
+ int_notes = [note_to_int[note_name] for note_name in note_names]
151
+
152
+ duration_to_size = {30: 100, 20: 66, 10: 33}
153
+ dur = duration_to_size[input_duration]
154
+
155
+ generated_seq_multinomial = predict_multimomial(model, int_notes, predict_len = dur, temperature = input_randomness / 50)
156
+ generated_seq_multinomial = [int_to_note[e] for e in generated_seq_multinomial]
157
+ pred_midi_multinomial = create_midi(generated_seq_multinomial)
158
+
159
+ pred_midi_multinomial.write('midi', fp='result.midi')
160
+
161
+ sound_font = "/usr/share/sounds/sf2/FluidR3_GM.sf2"
162
+ FluidSynth(sound_font).midi_to_audio('result.midi', 'result.wav')
163
+ return 'result.wav', 'result.midi'
164
+
165
+
166
+ file_path = './objects/model_cpu.pkl'
167
+ with open(file_path, 'rb') as f:
168
+ model = pickle.load(f)
169
+
170
+
171
+ midi_file_desc = """
172
+ Audio file in .midi format
173
+ """
174
+
175
+ article = """
176
+ This model allows you to generate music based on audio input. Please upload a MIDI file below, choose music randomness and duration. The project has been created by the students of Ukrainian Catholic University for our ML course.
177
+
178
+ 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
179
+ 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.
180
+ """
181
+
182
+ title = """
183
+ Classical Music Generation
184
+ """
185
+
186
+ iface = gr.Interface(
187
+ fn=process_input,
188
+ inputs=[
189
+ gr.inputs.File(label=midi_file_desc),
190
+ gr.inputs.Slider(50, 250, default=100, step=50),
191
+ gr.inputs.Radio([10, 20, 30], type="value", default=20)
192
+ ],
193
  title=title,
194
+ outputs=["audio", "file"],
195
  article=article,
196
+ examples=[
197
+ ['examples/mozart.midi', 100, 10],
198
+ ['examples/beethoven.midi', 50, 30],
199
+ ['examples/chopin.midi', 100, 20]
200
+ ]
201
+ )
202
+
203
+ iface.launch()