From cd7b8896261a85af4e77104463174896e4a37a1f Mon Sep 17 00:00:00 2001 From: slSeanWU Date: Thu, 30 Oct 2025 14:07:49 -0400 Subject: [PATCH] add loudnorm; default model to hf hub --- generate_vllm.py | 6 +++--- midi_llm/utils.py | 36 ++++++++++++++++++++++++++++++++---- requirements.txt | 4 +++- 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/generate_vllm.py b/generate_vllm.py index 7986f04..5958d47 100644 --- a/generate_vllm.py +++ b/generate_vllm.py @@ -2,6 +2,7 @@ """ This script generates MIDI files from text prompts using the MIDI-LLM model with vLLM backend. vLLM provides faster inference compared to standard HuggingFace model.generate() mixin. +Caveat is that initialization + compilation takes more time, so best used for inference with many prompts. """ import json @@ -235,8 +236,8 @@ Examples: parser.add_argument( "--model", type=str, - required=True, - help="Path to MIDI-LLM model checkpoint" + default="slseanwu/MIDI-LLM_Llama-3.2-1B", + help="Path to MIDI-LLM model checkpoint, can be HuggingFace model ID or local path (default: slseanwu/MIDI-LLM_Llama-3.2-1B)" ) # Input arguments (not required if using --interactive only) @@ -494,4 +495,3 @@ Examples: if __name__ == "__main__": main() - diff --git a/midi_llm/utils.py b/midi_llm/utils.py index 55293ba..2fb47b5 100644 --- a/midi_llm/utils.py +++ b/midi_llm/utils.py @@ -23,12 +23,20 @@ except ImportError: # Optional dependencies for audio synthesis SYNTHESIS_AVAILABLE = False +LOUDNESS_NORM_AVAILABLE = False try: import midi2audio import librosa import librosa.effects import soundfile as sf SYNTHESIS_AVAILABLE = True + + # Optional loudness normalization + try: + import pyloudnorm as pyln + LOUDNESS_NORM_AVAILABLE = True + except ImportError: + pass except ImportError: pass @@ -89,16 +97,18 @@ def synthesize_midi_to_audio( midi_path: str, soundfont_path: str, save_mp3: bool = True, - samplerate: Optional[int] = None + samplerate: Optional[int] = None, + target_loudness: float = -18.0 ) -> bool: """ - Synthesize MIDI file to audio (WAV/MP3) using FluidSynth. + Synthesize MIDI file to audio (WAV/MP3) using FluidSynth with loudness normalization. Args: midi_path: Path to MIDI file soundfont_path: Path to SoundFont (.sf2) file save_mp3: If True, convert to MP3 and delete WAV samplerate: Optional sample rate for audio + target_loudness: Target loudness in LUFS (default: -14.0, Spotify standard) Returns: True if successful, False otherwise @@ -106,7 +116,7 @@ def synthesize_midi_to_audio( if not SYNTHESIS_AVAILABLE: print("Warning: Audio synthesis libraries not available. Skipping synthesis.") print("Install with: conda install conda-forge::fluidsynth conda-forge::ffmpeg") - print(" pip install midi2audio librosa soundfile") + print(" pip install midi2audio librosa soundfile pyloudnorm") return False try: @@ -120,9 +130,27 @@ def synthesize_midi_to_audio( # Synthesize MIDI to WAV fs.midi_to_audio(midi_path, wav_path) - # Trim silence from audio + # Load and trim silence from audio wav, sr = librosa.load(wav_path) wav, _ = librosa.effects.trim(wav, top_db=30) + + # Apply loudness normalization + if LOUDNESS_NORM_AVAILABLE: + try: + # Measure the loudness + meter = pyln.Meter(sr) + loudness = meter.integrated_loudness(wav) + + # Normalize to target loudness + wav = pyln.normalize.loudness(wav, loudness, target_loudness) + + # Prevent clipping + if wav.max() > 1.0 or wav.min() < -1.0: + wav = wav / max(abs(wav.max()), abs(wav.min())) + except Exception as e: + print(f"Warning: Loudness normalization failed: {e}") + + # Write normalized audio sf.write(wav_path, wav, sr) if save_mp3: diff --git a/requirements.txt b/requirements.txt index d90542c..f0deb0f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -50,6 +50,7 @@ jsonschema-specifications==2025.9.1 lark==1.2.2 lazy_loader==0.4 librosa==0.11.0 +pyloudnorm==0.1.1 llguidance==0.7.30 llvmlite==0.44.0 lm-format-enforcer==0.11.3 @@ -149,4 +150,5 @@ watchfiles==1.1.1 websockets==15.0.1 xformers==0.0.32.post1 xgrammar==0.1.25 -yarl==1.22.0 \ No newline at end of file +yarl==1.22.0 +future==1.0.0 \ No newline at end of file