Added scaling and capping in midi_to_notes; removed notes_to_midi
Browse filesThe scaling and capping was done outside of midi_to_notes.
notes_to_midi was not necessary, since map_to_wav already did its job while being aware of the output format of the model.
- audio_methods.py +15 -36
audio_methods.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
_SAMPLING_RATE = 16000 # Parameter to pass continuous signal to a discrete one
|
| 4 |
_INSTRUMENT_NAME = "Acoustic Grand Piano" # MIDI instrument used
|
| 5 |
_SCALING_FACTORS = pd.Series(
|
|
@@ -7,6 +6,9 @@ _SCALING_FACTORS = pd.Series(
|
|
| 7 |
) # Factors used to normalize song maps
|
| 8 |
|
| 9 |
def midi_to_notes(midi_file: str) -> pd.DataFrame:
|
|
|
|
|
|
|
|
|
|
| 10 |
pm = pretty_midi.PrettyMIDI(midi_file)
|
| 11 |
instrument = pm.instruments[0]
|
| 12 |
notes = collections.defaultdict(list)
|
|
@@ -15,45 +17,20 @@ def midi_to_notes(midi_file: str) -> pd.DataFrame:
|
|
| 15 |
sorted_notes = sorted(instrument.notes, key=lambda note: note.start)
|
| 16 |
prev_start = sorted_notes[0].start
|
| 17 |
|
|
|
|
| 18 |
for note in sorted_notes:
|
| 19 |
start = note.start
|
| 20 |
end = note.end
|
| 21 |
notes['pitch'].append(note.pitch)
|
| 22 |
-
notes['start'].append(start)
|
| 23 |
-
notes['end'].append(end)
|
| 24 |
notes['step'].append(start - prev_start)
|
| 25 |
notes['duration'].append(end - start)
|
| 26 |
prev_start = start
|
| 27 |
|
| 28 |
-
return pd.DataFrame({name: np.array(value) for name, value in notes.items()})
|
| 29 |
-
|
| 30 |
-
def notes_to_midi(
|
| 31 |
-
notes: pd.DataFrame,
|
| 32 |
-
out_file: str,
|
| 33 |
-
velocity: int = 100, # note loudness
|
| 34 |
-
) -> pretty_midi.PrettyMIDI:
|
| 35 |
-
|
| 36 |
-
pm = pretty_midi.PrettyMIDI()
|
| 37 |
-
instrument = pretty_midi.Instrument(
|
| 38 |
-
program=pretty_midi.instrument_name_to_program(
|
| 39 |
-
_INSTRUMENT_NAME))
|
| 40 |
-
|
| 41 |
-
prev_start = 0
|
| 42 |
-
for i, note in notes.iterrows():
|
| 43 |
-
start = float(prev_start + note['step'])
|
| 44 |
-
end = float(start + note['duration'])
|
| 45 |
-
note = pretty_midi.Note(
|
| 46 |
-
velocity=velocity,
|
| 47 |
-
pitch=int(note['pitch']),
|
| 48 |
-
start=start,
|
| 49 |
-
end=end,
|
| 50 |
-
)
|
| 51 |
-
instrument.notes.append(note)
|
| 52 |
-
prev_start = start
|
| 53 |
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
|
|
|
| 57 |
|
| 58 |
|
| 59 |
def display_audio(pm: pretty_midi.PrettyMIDI, seconds=120):
|
|
@@ -65,7 +42,9 @@ def display_audio(pm: pretty_midi.PrettyMIDI, seconds=120):
|
|
| 65 |
|
| 66 |
# Define function to convert song map to wav
|
| 67 |
|
| 68 |
-
def map_to_wav(song_map, out_file
|
|
|
|
|
|
|
| 69 |
contracted_map = tf.squeeze(song_map)
|
| 70 |
song_map_T = contracted_map.numpy().T
|
| 71 |
notes = pd.DataFrame(song_map_T, columns=["pitch", "step", "duration"]).mul(_SCALING_FACTORS, axis=1)
|
|
@@ -74,7 +53,7 @@ def map_to_wav(song_map, out_file, instrument_name, velocity=100):
|
|
| 74 |
pm = pretty_midi.PrettyMIDI()
|
| 75 |
instrument = pretty_midi.Instrument(
|
| 76 |
program=pretty_midi.instrument_name_to_program(
|
| 77 |
-
|
| 78 |
|
| 79 |
prev_start = 0
|
| 80 |
for i, note in notes.iterrows():
|
|
@@ -93,9 +72,9 @@ def map_to_wav(song_map, out_file, instrument_name, velocity=100):
|
|
| 93 |
pm.write(out_file)
|
| 94 |
return pm
|
| 95 |
|
| 96 |
-
def generate_and_display(out_file,
|
| 97 |
song_map = model.generate(z_sample)
|
| 98 |
display.display(imshow(tf.squeeze(song_map)[:,:50]))
|
| 99 |
-
wav = map_to_wav(song_map, out_file,
|
| 100 |
|
| 101 |
return display_audio(wav, seconds)
|
|
|
|
| 1 |
+
_CAP = 3501 # Cap for the number of notes
|
|
|
|
| 2 |
_SAMPLING_RATE = 16000 # Parameter to pass continuous signal to a discrete one
|
| 3 |
_INSTRUMENT_NAME = "Acoustic Grand Piano" # MIDI instrument used
|
| 4 |
_SCALING_FACTORS = pd.Series(
|
|
|
|
| 6 |
) # Factors used to normalize song maps
|
| 7 |
|
| 8 |
def midi_to_notes(midi_file: str) -> pd.DataFrame:
|
| 9 |
+
# Convert midi file to "song map" (dataframe where each note is broken
|
| 10 |
+
# into its components)
|
| 11 |
+
|
| 12 |
pm = pretty_midi.PrettyMIDI(midi_file)
|
| 13 |
instrument = pm.instruments[0]
|
| 14 |
notes = collections.defaultdict(list)
|
|
|
|
| 17 |
sorted_notes = sorted(instrument.notes, key=lambda note: note.start)
|
| 18 |
prev_start = sorted_notes[0].start
|
| 19 |
|
| 20 |
+
# Separate each individual note in pitch, step and duration
|
| 21 |
for note in sorted_notes:
|
| 22 |
start = note.start
|
| 23 |
end = note.end
|
| 24 |
notes['pitch'].append(note.pitch)
|
|
|
|
|
|
|
| 25 |
notes['step'].append(start - prev_start)
|
| 26 |
notes['duration'].append(end - start)
|
| 27 |
prev_start = start
|
| 28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 29 |
|
| 30 |
+
# Put notes in a dataframe
|
| 31 |
+
notes_df = pd.DataFrame({name: np.array(value) for name, value in notes.items()})
|
| 32 |
+
notes_df = notes_df[:_CAP] # Cap the song to match the model's architecture
|
| 33 |
+
return notes_df / _SCALING_FACTORS # Scale
|
| 34 |
|
| 35 |
|
| 36 |
def display_audio(pm: pretty_midi.PrettyMIDI, seconds=120):
|
|
|
|
| 42 |
|
| 43 |
# Define function to convert song map to wav
|
| 44 |
|
| 45 |
+
def map_to_wav(song_map: pd.DataFrame, out_file: str, velocity: int=100):
|
| 46 |
+
# Convert "song map" to midi file (reverse process with respect to midi_to_notes)
|
| 47 |
+
|
| 48 |
contracted_map = tf.squeeze(song_map)
|
| 49 |
song_map_T = contracted_map.numpy().T
|
| 50 |
notes = pd.DataFrame(song_map_T, columns=["pitch", "step", "duration"]).mul(_SCALING_FACTORS, axis=1)
|
|
|
|
| 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():
|
|
|
|
| 72 |
pm.write(out_file)
|
| 73 |
return pm
|
| 74 |
|
| 75 |
+
def generate_and_display(out_file, model, z_sample=None, velocity=100, seconds=120):
|
| 76 |
song_map = model.generate(z_sample)
|
| 77 |
display.display(imshow(tf.squeeze(song_map)[:,:50]))
|
| 78 |
+
wav = map_to_wav(song_map, out_file, velocity)
|
| 79 |
|
| 80 |
return display_audio(wav, seconds)
|