Spaces:
Running
Running
import logging | |
from basic_pitch.inference import predict | |
from basic_pitch import ICASSP_2022_MODEL_PATH | |
import pretty_midi | |
from typing import Optional, Tuple | |
logger = logging.getLogger(__name__) | |
class BasicPitchConverter: | |
def __init__(self): | |
self.process_options = { | |
'onset_threshold': 0.5, | |
'frame_threshold': 0.3, | |
'minimum_note_length': 127.70, # in milliseconds | |
'minimum_frequency': 32.7, # C1 | |
'maximum_frequency': 2093, # C7 | |
'multiple_pitch_bends': True, | |
'melodia_trick': True, | |
'midi_tempo': 120.0 | |
} | |
print("Basic Pitch converter initialized") # Keep using print for consistency | |
def convert_to_midi(self, audio_path: str, output_path: str, progress: Optional[callable] = None) -> str: | |
""" | |
Convert audio to MIDI using Basic Pitch. | |
Args: | |
audio_path: Path to input audio file | |
output_path: Path to save MIDI file | |
progress: Optional callback function for progress updates | |
Returns: | |
str: Path to saved MIDI file | |
""" | |
try: | |
print(f"Converting to MIDI: {audio_path}") # Keep debugging output | |
if progress: | |
progress(0.1, "Loading audio for MIDI conversion...") | |
# Predict using Basic Pitch with correct parameters | |
model_output, midi_data, note_events = predict( | |
audio_path=audio_path, | |
onset_threshold=self.process_options['onset_threshold'], | |
frame_threshold=self.process_options['frame_threshold'], | |
minimum_note_length=self.process_options['minimum_note_length'], | |
minimum_frequency=self.process_options['minimum_frequency'], | |
maximum_frequency=self.process_options['maximum_frequency'], | |
multiple_pitch_bends=self.process_options['multiple_pitch_bends'], | |
melodia_trick=self.process_options['melodia_trick'], | |
midi_tempo=self.process_options['midi_tempo'] | |
) | |
if progress: | |
progress(0.7, "Saving MIDI file...") | |
print(f"Saving MIDI to: {output_path}") # Keep debugging output | |
# Save MIDI file with validation | |
if isinstance(midi_data, pretty_midi.PrettyMIDI): | |
midi_data.write(output_path) | |
print(f"Successfully saved MIDI to {output_path}") # Keep using print | |
return output_path | |
else: | |
raise ValueError("MIDI conversion failed: Invalid MIDI data") | |
except Exception as e: | |
print(f"Error in MIDI conversion: {str(e)}") # Keep using print | |
raise | |
def set_process_options(self, **kwargs): | |
"""Update processing options""" | |
self.process_options.update(kwargs) |