Spaces:
Sleeping
Sleeping
Upload 3 files
Browse files- .gitattributes +1 -0
- 16.5mg_gm_gs_mt32_v2.51_bank.sf2 +3 -0
- app.py +186 -0
- requirements.txt +9 -0
.gitattributes
CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
36 |
+
16.5mg_gm_gs_mt32_v2.51_bank.sf2 filter=lfs diff=lfs merge=lfs -text
|
16.5mg_gm_gs_mt32_v2.51_bank.sf2
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:c5971c61f49f749837b0bcf7e2b5d17d5bd6d2b60df19f98da320315a029813f
|
3 |
+
size 16944892
|
app.py
ADDED
@@ -0,0 +1,186 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import collections
|
2 |
+
#import datetime
|
3 |
+
#import glob
|
4 |
+
import numpy as np
|
5 |
+
#import pathlib
|
6 |
+
import pandas as pd
|
7 |
+
import pretty_midi
|
8 |
+
import seaborn as sns
|
9 |
+
|
10 |
+
from matplotlib import pyplot as plt
|
11 |
+
from typing import Optional
|
12 |
+
|
13 |
+
import tensorflow as tf
|
14 |
+
|
15 |
+
import keras
|
16 |
+
|
17 |
+
from tensorflow.keras.utils import custom_object_scope
|
18 |
+
|
19 |
+
import streamlit as st
|
20 |
+
|
21 |
+
from midi2audio import FluidSynth
|
22 |
+
import tempfile
|
23 |
+
import os
|
24 |
+
import base64
|
25 |
+
|
26 |
+
def midi_to_notes(midi_file: str) -> pd.DataFrame:
|
27 |
+
pm = pretty_midi.PrettyMIDI(midi_file)
|
28 |
+
instrument = pm.instruments[0]
|
29 |
+
notes = collections.defaultdict(list)
|
30 |
+
|
31 |
+
sorted_notes = sorted(instrument.notes, key=lambda note: note.start)
|
32 |
+
prev_start = sorted_notes[0].start
|
33 |
+
|
34 |
+
for note in sorted_notes:
|
35 |
+
start = note.start
|
36 |
+
end = note.end
|
37 |
+
notes['pitch'].append(note.pitch)
|
38 |
+
notes['start'].append(start)
|
39 |
+
notes['end'].append(end)
|
40 |
+
notes['step'].append(start - prev_start)
|
41 |
+
notes['duration'].append(end - start)
|
42 |
+
prev_start = start
|
43 |
+
|
44 |
+
return pd.DataFrame({name: np.array(value) for name, value in notes.items()})
|
45 |
+
|
46 |
+
def notes_to_midi(
|
47 |
+
notes: pd.DataFrame,
|
48 |
+
out_file: str,
|
49 |
+
instrument_name: str,
|
50 |
+
velocity: int = 100,
|
51 |
+
) -> pretty_midi.PrettyMIDI:
|
52 |
+
|
53 |
+
pm = pretty_midi.PrettyMIDI()
|
54 |
+
instrument = pretty_midi.Instrument(
|
55 |
+
program=pretty_midi.instrument_name_to_program(
|
56 |
+
instrument_name))
|
57 |
+
|
58 |
+
prev_start = 0
|
59 |
+
for i, note in notes.iterrows():
|
60 |
+
start = float(prev_start + note['step'])
|
61 |
+
end = float(start + note['duration'])
|
62 |
+
note = pretty_midi.Note(
|
63 |
+
velocity=velocity,
|
64 |
+
pitch=int(note['pitch']),
|
65 |
+
start=start,
|
66 |
+
end=end,
|
67 |
+
)
|
68 |
+
instrument.notes.append(note)
|
69 |
+
prev_start = start
|
70 |
+
|
71 |
+
pm.instruments.append(instrument)
|
72 |
+
pm.write(out_file)
|
73 |
+
return pm
|
74 |
+
|
75 |
+
def plot_roll(notes: pd.DataFrame, count: Optional[int] = None):
|
76 |
+
if count:
|
77 |
+
title = f'First {count} notes'
|
78 |
+
else:
|
79 |
+
title = f'Whole track'
|
80 |
+
count = len(notes['pitch'])
|
81 |
+
plt.figure(figsize=(20, 4))
|
82 |
+
plot_pitch = np.stack([notes['pitch'], notes['pitch']], axis=0)
|
83 |
+
plot_start_stop = np.stack([notes['start'], notes['end']], axis=0)
|
84 |
+
plt.plot(
|
85 |
+
plot_start_stop[:, :count], plot_pitch[:, :count], color="b", marker=".")
|
86 |
+
plt.xlabel('Time [s]')
|
87 |
+
plt.ylabel('Pitch')
|
88 |
+
_ = plt.title(title)
|
89 |
+
|
90 |
+
def plot_distributions(notes: pd.DataFrame, drop_percentile=2.5):
|
91 |
+
plt.figure(figsize=[15, 5])
|
92 |
+
plt.subplot(1, 3, 1)
|
93 |
+
sns.histplot(notes, x="pitch", bins=20)
|
94 |
+
|
95 |
+
plt.subplot(1, 3, 2)
|
96 |
+
max_step = np.percentile(notes['step'], 100 - drop_percentile)
|
97 |
+
sns.histplot(notes, x="step", bins=np.linspace(0, max_step, 21))
|
98 |
+
|
99 |
+
def predict_next_note(
|
100 |
+
notes: np.ndarray,
|
101 |
+
model: tf.keras.Model,
|
102 |
+
temperature: float = 1.0) -> tuple[int, float, float]:
|
103 |
+
|
104 |
+
assert temperature > 0
|
105 |
+
|
106 |
+
inputs = tf.expand_dims(notes, 0)
|
107 |
+
|
108 |
+
predictions = model.predict(inputs)
|
109 |
+
pitch_logits = predictions['pitch']
|
110 |
+
step = predictions['step']
|
111 |
+
duration = predictions['duration']
|
112 |
+
|
113 |
+
pitch_logits /= temperature
|
114 |
+
pitch = tf.random.categorical(pitch_logits, num_samples=1)
|
115 |
+
pitch = tf.squeeze(pitch, axis=-1)
|
116 |
+
duration = tf.squeeze(duration, axis=-1)
|
117 |
+
step = tf.squeeze(step, axis=-1)
|
118 |
+
|
119 |
+
step = tf.maximum(0, step)
|
120 |
+
duration = tf.maximum(0, duration)
|
121 |
+
|
122 |
+
return int(pitch), float(step), float(duration)
|
123 |
+
|
124 |
+
def mse_with_positive_pressure(y_true: tf.Tensor, y_pred: tf.Tensor):
|
125 |
+
mse = (y_true - y_pred) ** 2
|
126 |
+
positive_pressure = 10 * tf.maximum(-y_pred, 0.0)
|
127 |
+
return tf.reduce_mean(mse + positive_pressure)
|
128 |
+
|
129 |
+
def main():
|
130 |
+
seed = 42
|
131 |
+
tf.random.set_seed(seed)
|
132 |
+
np.random.seed(seed)
|
133 |
+
|
134 |
+
# Rutas de archivos
|
135 |
+
sample_file = '732628744bb532074f4993acfa07c718.mid'
|
136 |
+
out_file = 'output.mid'
|
137 |
+
|
138 |
+
# Cargar modelo y pesos
|
139 |
+
with custom_object_scope({'mse_with_positive_pressure': mse_with_positive_pressure}):
|
140 |
+
model = keras.models.load_model("mi_modelo_music.h5")
|
141 |
+
|
142 |
+
model.load_weights("mi_pesos_music.h5", skip_mismatch=False, by_name=False, options=None)
|
143 |
+
|
144 |
+
# Convertir MIDI generado por el modelo a archivo WAV
|
145 |
+
pm = pretty_midi.PrettyMIDI(sample_file)
|
146 |
+
instrument_name = pretty_midi.program_to_instrument_name(pm.instruments[0].program)
|
147 |
+
raw_notes = midi_to_notes(sample_file)
|
148 |
+
key_order = ['pitch', 'step', 'duration']
|
149 |
+
seq_length = 25
|
150 |
+
vocab_size = 128
|
151 |
+
temperature = 2.0
|
152 |
+
num_predictions = 120
|
153 |
+
sample_notes = np.stack([raw_notes[key] for key in key_order], axis=1)
|
154 |
+
input_notes = (sample_notes[:seq_length] / np.array([vocab_size, 1, 1]))
|
155 |
+
generated_notes = []
|
156 |
+
prev_start = 0
|
157 |
+
for _ in range(num_predictions):
|
158 |
+
pitch, step, duration = predict_next_note(input_notes, model, temperature)
|
159 |
+
start = prev_start + step
|
160 |
+
end = start + duration
|
161 |
+
input_note = (pitch, step, duration)
|
162 |
+
generated_notes.append((*input_note, start, end))
|
163 |
+
input_notes = np.delete(input_notes, 0, axis=0)
|
164 |
+
input_notes = np.append(input_notes, np.expand_dims(input_note, 0), axis=0)
|
165 |
+
prev_start = start
|
166 |
+
|
167 |
+
generated_notes = pd.DataFrame(
|
168 |
+
generated_notes, columns=(*key_order, 'start', 'end'))
|
169 |
+
|
170 |
+
notes_to_midi(
|
171 |
+
generated_notes, out_file=out_file, instrument_name=instrument_name)
|
172 |
+
|
173 |
+
# Interfaz de Streamlit
|
174 |
+
st.title("Generador de notas musicales")
|
175 |
+
|
176 |
+
archivo_midi = open(out_file, 'rb').read()
|
177 |
+
|
178 |
+
st.download_button(
|
179 |
+
label="Descargar MIDI",
|
180 |
+
data=archivo_midi,
|
181 |
+
file_name=out_file, # Nombre del archivo que se descargará
|
182 |
+
mime='audio/midi'
|
183 |
+
)
|
184 |
+
|
185 |
+
if __name__ == "__main__":
|
186 |
+
main()
|
requirements.txt
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
numpy==1.25.2
|
2 |
+
pandas==2.0.3
|
3 |
+
pretty_midi==0.2.10
|
4 |
+
seaborn==0.13.1
|
5 |
+
matplotlib==3.7.1
|
6 |
+
tensorflow==2.15.0
|
7 |
+
keras==2.15.0
|
8 |
+
|
9 |
+
midi2audio
|