import gradio as gr from musiclang_predict import MusicLangPredictor from musiclang import Score from midi2audio import FluidSynth import os import tempfile def inner_loop(nb_tokens, temperature, chord_progression, tempo, midi_file, bar_range): top_p = 0.98 seed = 0 print(midi_file) # Initialize the MusicLangPredictor ml = MusicLangPredictor('musiclang/musiclang-v2') tempo_message = "" # Default message if no MIDI file is uploaded time_signature = (4, 4) if midi_file is not None: # Load the MIDI file and use it as the score prompt filepath = midi_file start_bar, end_bar = map(int, bar_range.split("-")) score = Score.from_midi(filepath, chord_range=(start_bar, end_bar)) tempo = score.config['tempo'] # Use the tempo from the MIDI file and change input time_signature = score.config['time_signature'] time_signature = (time_signature[1], time_signature[2]) tempo_message = f"Warning : real tempo of file is : {int(tempo)} BPM." # Update message based on MIDI file else: score = None # Default score is None if no MIDI file is uploaded # Generate the score based on provided inputs and the uploaded MIDI file if available if chord_progression.strip() == "" and score is None: # Generate without specific chord progression or MIDI prompt generated_score = ml.predict( nb_tokens=int(nb_tokens), temperature=float(temperature), topp=top_p, rng_seed=seed ) elif score is not None and chord_progression.strip() == "": # Generate using the uploaded MIDI file as a prompt generated_score = ml.predict( score=score, # Use the uploaded MIDI as the score prompt nb_tokens=int(nb_tokens), temperature=float(temperature), topp=top_p, rng_seed=seed ) else: # Generate with specific chord progression generated_score = ml.predict_chords( chord_progression, score=score, # Use the uploaded MIDI as the score prompt time_signature=time_signature, temperature=temperature, topp=top_p, rng_seed=seed ) chord_repr = generated_score.to_chord_repr() # Save the generated score as a MIDI file temp_midi_file = tempfile.NamedTemporaryFile(suffix=".mid", delete=False) midi_path = temp_midi_file.name generated_score.to_midi(midi_path, tempo=tempo, time_signature=time_signature) # Convert MIDI to WAV then WAV to MP3 for playback temp_wav_file = tempfile.NamedTemporaryFile(suffix=".wav", delete=False) temp_mp3_file = tempfile.NamedTemporaryFile(suffix=".mp3", delete=False) wav_path = temp_wav_file.name mp3_path = temp_mp3_file.name FluidSynth("/usr/share/sounds/sf2/FluidR3_GM.sf2").midi_to_audio(midi_path, wav_path) os.system(f'ffmpeg -i {wav_path} -acodec libmp3lame -y -loglevel quiet -stats {mp3_path}') # Remove the temporary WAV file os.remove(wav_path) return mp3_path, midi_path, chord_repr, tempo_message def musiclang(nb_tokens, temperature, chord_progression, tempo, midi_file, bar_range): exception = None mp3_path, midi_path, chord_repr, tempo_message = None, None, None, "" try: mp3_path, midi_path, chord_repr, tempo_message = inner_loop(nb_tokens, temperature, chord_progression, tempo, midi_file, bar_range) except Exception as e: exception = "Error : " + e.__class__.__name__ + " " + str(e) # Return the MP3 path for Gradio to display and the MIDI file path for download return mp3_path, midi_path, chord_repr, tempo_message, exception # Update Gradio interface to include MIDI file upload and bar range selection iface = gr.Interface( fn=musiclang, inputs=[ gr.Number(label="Number of Tokens", value=1024, minimum=256, maximum=2048, step=256), gr.Slider(label="Temperature", value=0.95, minimum=0.1, maximum=1.0, step=0.1), gr.Textbox(label="Chord Progression (Optional)", placeholder="Am CM Dm/F E7 Am", lines=2, value=""), gr.Slider(label="Tempo", value=120, minimum=60, maximum=240, step=1), gr.File(label="Upload MIDI File", type="filepath", file_types=[".mid", ".midi"]), gr.Textbox(label="Bar Range of input file", placeholder="0-4", value="0-4") ], outputs=[ gr.Audio(label="Generated Music"), gr.File(label="Download MIDI"), gr.Textbox(label="Inferred output Chord Progression", lines=2, value=""), gr.Textbox(label="Tempo Used", value=""), # Display the tempo used for generation gr.Textbox(label="Info Message") # Initially hidden, shown only if there's an error ], title="Controllable Symbolic Music Generation with MusicLang Predict", description=""" \n This is the demo for MusicLang Predict, which offers advanced controllability features and high-quality music generation by manipulating symbolic music. Control your music generation by : \n - Specifying the number of tokens \n - The temperature: the level of creativity of MusicLang. The higher the temperature, the more creative the generation. We suggest you test different levels to find the one that suits your needs \n - Chord progression : Available chord qualities include: M, m, 7, m7b5, sus2, sus4, m7, M7, dim, dim0. You can also specify the bass if it belongs to the chord (e.g., Bm/D) \n - The tempo \n - Uploading a MIDI file to use as a prompt \n - Selecting a bar range of the input file (For example 0-4 means first four bars) \n Note: The model generates a score file, not an audio one. Therefore, the audio rendering in this notebook serves as a quick preview of the generated music. For an optimized experience, we recommend downloading the midi file and opening it in your favorite Digital Audio Workstation (DAW).” \n If no chord progression or MIDI file is given, it generates a free sample with the specified number of tokens. \n Need more info ? Visit our Github""" ) iface.launch()