File size: 6,291 Bytes
d8926bd
115df79
 
d8926bd
 
4b77a87
cc611a7
 
 
4b77a87
a906ae7
 
115df79
d8926bd
 
4b77a87
 
115df79
 
 
 
 
4b77a87
 
 
 
115df79
 
 
 
 
 
 
 
 
 
 
 
f0a10e0
115df79
 
 
a906ae7
 
 
 
 
 
115df79
 
a906ae7
f0a10e0
4b77a87
a906ae7
 
115df79
 
d8926bd
115df79
 
 
4b77a87
 
 
d8926bd
115df79
4b77a87
 
 
 
d8926bd
 
4b77a87
 
 
 
 
cc611a7
 
 
4b77a87
cc611a7
4b77a87
 
cc611a7
 
115df79
4b77a87
ecbd558
115df79
d8926bd
 
a906ae7
0e84b37
4b77a87
f0a10e0
115df79
 
f0a10e0
a906ae7
 
 
115df79
cc611a7
4b77a87
cc611a7
a906ae7
171b8d5
cc611a7
4b77a87
 
 
 
 
 
 
 
 
 
d8926bd
 
115df79
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
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 - <b>The temperature</b>: 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 - <b>Chord progression</b> : 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 - <b>The tempo</b>
    \n - <b>Uploading a MIDI</b> 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 <a href="https://github.com/musiclang/musiclang_predict">our Github</a>"""
)

iface.launch()