UltraSingerUI / src /modules /Midi /midi_creator.py
TIMBOVILL's picture
Rename src/modules/midi_creator.py to src/modules/Midi/midi_creator.py
693f56e verified
"""Midi creator module"""
import math
from collections import Counter
import librosa
import numpy as np
import pretty_midi
from modules.Pitcher.pitcher import get_frequencies_with_high_confidence
from modules.Ultrastar.ultrastar_converter import (
get_end_time_from_ultrastar,
get_start_time_from_ultrastar,
ultrastar_note_to_midi_note,
)
from modules.console_colors import (
ULTRASINGER_HEAD,
red_highlighted,
)
from modules.Ultrastar.ultrastar_txt import UltrastarTxtValue
from modules.Pitcher.pitched_data import PitchedData
def convert_ultrastar_to_midi_instrument(ultrastar_class: UltrastarTxtValue) -> object:
"""Converts an Ultrastar data to a midi instrument"""
print(f"{ULTRASINGER_HEAD} Creating midi instrument from Ultrastar txt")
instrument = pretty_midi.Instrument(program=0)
velocity = 100
for i in enumerate(ultrastar_class.words):
pos = i[0]
start_time = get_start_time_from_ultrastar(ultrastar_class, pos)
end_time = get_end_time_from_ultrastar(ultrastar_class, pos)
pitch = ultrastar_note_to_midi_note(int(ultrastar_class.pitches[pos]))
note = pretty_midi.Note(velocity, pitch, start_time, end_time)
instrument.notes.append(note)
return instrument
def instruments_to_midi(instruments: list[object], bpm: float, midi_output: str) -> None:
"""Write instruments to midi file"""
print(f"{ULTRASINGER_HEAD} Creating midi file -> {midi_output}")
midi_data = pretty_midi.PrettyMIDI(initial_tempo=bpm)
for instrument in instruments:
midi_data.instruments.append(instrument)
midi_data.write(midi_output)
class MidiCreator:
"""Docstring"""
def convert_frequencies_to_notes(frequency: [str]) -> list[list[str]]:
"""Converts frequencies to notes"""
notes = []
for freq in frequency:
notes.append(librosa.hz_to_note(float(freq)))
return notes
def most_frequent(array: [str]) -> list[tuple[str, int]]:
"""Get most frequent item in array"""
return Counter(array).most_common(1)
def find_nearest_index(array: list[float], value: float) -> int:
"""Nearest index in array"""
idx = np.searchsorted(array, value, side="left")
if idx > 0 and (
idx == len(array)
or math.fabs(value - array[idx - 1]) < math.fabs(value - array[idx])
):
return idx - 1
return idx
def create_midi_notes_from_pitched_data(start_times: list[float], end_times: list[float], pitched_data: PitchedData) -> list[str]:
"""Create midi notes from pitched data"""
print(f"{ULTRASINGER_HEAD} Creating midi notes from pitched data")
midi_notes = []
for i in enumerate(start_times):
pos = i[0]
start_time = start_times[pos]
end_time = end_times[pos]
note = create_midi_note_from_pitched_data(
start_time, end_time, pitched_data
)
midi_notes.append(note)
# todo: Progress?
# print(filename + " f: " + str(mean))
return midi_notes
def create_midi_note_from_pitched_data(start_time: float, end_time: float, pitched_data: PitchedData) -> str:
"""Create midi note from pitched data"""
start = find_nearest_index(pitched_data.times, start_time)
end = find_nearest_index(pitched_data.times, end_time)
if start == end:
freqs = [pitched_data.frequencies[start]]
confs = [pitched_data.confidence[start]]
else:
freqs = pitched_data.frequencies[start:end]
confs = pitched_data.confidence[start:end]
conf_f = get_frequencies_with_high_confidence(freqs, confs)
notes = convert_frequencies_to_notes(conf_f)
note = most_frequent(notes)[0][0]
return note