Spaces:
Sleeping
Sleeping
File size: 10,122 Bytes
52d7d5e dd9364e 7a3a629 52d7d5e 6e4f2b4 52d7d5e dd9364e fc99099 dd9364e 6e4f2b4 52d7d5e f3df7ae 2d59e3d dd9364e 57b79b0 dd9364e 57b79b0 dd9364e 52d7d5e dd9364e 52d7d5e f3df7ae 52d7d5e 6169d9d dd9364e 52d7d5e fc99099 dd9364e 52d7d5e fc99099 6e4f2b4 dd9364e 6e4f2b4 52d7d5e 6e4f2b4 dd9364e 52d7d5e dd9364e 52d7d5e 57b79b0 52d7d5e 57b79b0 52d7d5e d654f15 52d7d5e d654f15 fc99099 52d7d5e 6e4f2b4 fc99099 f783922 52d7d5e fc99099 6e4f2b4 8d89421 fc99099 52d7d5e d654f15 57b79b0 52d7d5e 57b79b0 f783922 57b79b0 f783922 52d7d5e f783922 52d7d5e f783922 52d7d5e d654f15 fc99099 52d7d5e 651000e 52d7d5e 6807c17 dd9364e 52d7d5e 2d59e3d | 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 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | import ast
import gradio as gr
import numpy as np
from mido import Message, MidiFile, MidiTrack
import os
from music21 import converter, note, stream, chord, tempo, meter
import hexachords
from format_conversions import Format_Converter
import verovio
import subprocess
from legacy.essai_mido_to_xml import midi_path
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
def get_verovio_resource_path():
for path in verovio.__path__:
candidate = os.path.join(path, "data")
if os.path.exists(candidate):
return candidate
return None
# Initialize the Verovio toolkit with rendering options
tk = verovio.toolkit()
resource_path = get_verovio_resource_path()
print(f"resource path: {os.listdir(resource_path)}")
print("[Debug] Using resource path:", resource_path)
if resource_path:
try:
tk.setResourcePath(resource_path)
except Exception as e:
print("[Error] Failed to set resourcePath:", e)
tk.setOptions({
"adjustPageWidth": True,
"header": 'none', # This disables the rendering of the title
"scale": 70,
"adjustPageHeight": True,
"landscape": False,
})
print(tk.getOptions())
class HexachordApp:
def __init__(self):
self._hexachord = hexachords.Hexachord()
self.ui = None
self.on_huggingface = "HUGGINGFACE_SPACE" in os.environ
def is_fsynth_installed(self):
try:
subprocess.run(["fluidsynth", "--version"], check=True)
print('fluidsynth is installed')
return True
except Exception:
print('fluidsynth is NOT installed')
return False
def generate_chords(self, note_names, itvl):
interval_21 = 'P5'
if itvl == 'fourth':
interval_21 = 'P4'
return self._hexachord.generate_base_sequence(note_names, intrvl=interval_21)
def generate_realizations(self):
# returns triples of midipath, score image, audio player
reals = self._hexachord.generate_3_chords_realizations(self._hexachord._base_sequence)
all_paths = []
fm = Format_Converter()
for i, real in enumerate(reals):
midi_path = f"real{i}.mid"
all_paths.append(self.create_midi_file(real, midi_path))
all_paths.append(fm.midi_to_svg_file(tk, midi_path, f"real{i}.svg"))
all_paths.append(fm.convert_midi_to_audio(midi_path, f"real{i}"))
return tuple(all_paths)
def create_midi_file(self, chords, file_name, duration_in_quarter_lengths=4.0, tempo_bpm=120, time_signature="4/4"):
midi_path = os.path.join(BASE_DIR, file_name)
self._hexachord.save_chords_to_midi_file(chords, midi_path)
return file_name
def generate_svg(self, midi_file, output_file_name):
return Format_Converter().midi_to_svg_file(tk, midi_file, output_file_name)
def launch_score_editor(self, midi_path):
try:
score = converter.parse(midi_path)
score.show('musicxml')
return "Opened MIDI file in the default score editor!"
except Exception as e:
return f"Error opening score editor: {str(e)}"
def build_octave_dependent_notes_from_string(self, note_string):
start_octave = 3
notes = []
previous_note = None
for nn in note_string.split():
n = note.Note(nn)
n.octave = start_octave
if previous_note is not None and n.pitch.midi < previous_note.pitch.midi:
n.octave = n.octave + 1
start_octave += 1
notes.append(n)
previous_note = n
return notes
def process_hexachord(self, hexachord_str, itvl):
try:
notes = self.build_octave_dependent_notes_from_string(hexachord_str)
if len(notes) != 6 or len(set(notes)) != 6:
return "Please enter exactly 6 unique notes."
except ValueError:
return "Invalid input. Enter 6 notes separated by spaces."
fm = Format_Converter()
chords = self.generate_chords(notes, itvl)
midi_path = self.create_midi_file(chords, "base_chords.mid")
score_path = fm.midi_to_svg_file(tk, midi_path, "score_base_chords.svg")
audio_path = fm.convert_midi_to_audio(midi_path, "base_chords")
return (midi_path, score_path, audio_path) + self.generate_realizations()
def generate_movements(self):
# take 2 realizations of the same root
everyone = ()
for index_of_chord in range(6):
chords = [real[index_of_chord] for real in self._hexachord._realizations]
fm = Format_Converter()
midi_path = self.create_midi_file(chords, f"movement{index_of_chord}.mid")
score_path = fm.midi_to_svg_file(tk, midi_path, f"movement{index_of_chord}.svg")
audio_path = fm.convert_midi_to_audio(midi_path, f"movement{index_of_chord}")
everyone = everyone + (midi_path, score_path, audio_path)
return everyone
def render(self):
with gr.Blocks() as ui:
gr.Markdown("# Hexachord-based Chord Generator")
with gr.Tabs():
with gr.TabItem("Hexachord Generator"):
with gr.Row():
hexachord_selector = gr.Dropdown(label="Select Known Hexachord",
choices=self.get_known_hexachords_choice(), value=None, interactive=True)
hexachord_input = gr.Textbox(
label="Enter 6 pitchclasses, separated by spaces",
value="C D E G A B",
interactive = True
)
interval_switch = gr.Radio(
choices=["fourth", "fifth"],
label="Select Interval",
value="fifth"
)
generate_button = gr.Button("Generate Chords")
with gr.Row():
gr.Markdown(f"#### base chords")
midi_output = gr.File(label="Download MIDI File", scale=1)
score_output = gr.Image(label="Score Visualization", scale=3)
audio_output = gr.Audio(label="Play Generated Chords", value=None, interactive=False, scale=3)
realization_outputs = [midi_output, score_output, audio_output]
for i in range(3): # Three alternative realizations
with gr.Row():
gr.Markdown(f"#### Realization {i + 1}")
midi_output = gr.File(label="Download MIDI File", scale=1)
piano_roll = gr.Image(label=f"Piano Roll {i + 1}", scale=3)
audio_player = gr.Audio(label=f"Play Chords {i + 1}", interactive=False, scale=3)
realization_outputs += (midi_output, piano_roll, audio_player)
hexachord_selector.change(
fn=self.get_selected_hexachord,
inputs=[hexachord_selector],
outputs=[hexachord_input]
)
generate_button.click(
fn=self.process_hexachord,
inputs=[hexachord_input, interval_switch],
# outputs=[midi_output, piano_roll_output, audio_output]
outputs = realization_outputs
)
# Pressing Enter in the textbox also triggers processing
hexachord_input.submit(
fn=self.process_hexachord,
inputs=[hexachord_input, interval_switch],
outputs=realization_outputs
)
with gr.TabItem("Movements"):
gr.Markdown("Movements")
with gr.Row():
generate_mvmt_button = gr.Button("Generate Movements")
realization_outputs = []
for i in range(6): # Three alternative realizations
with gr.Row():
gr.Markdown(f"#### Movement {i + 1}")
midi_output = gr.File(label="Download MIDI File", scale=1)
piano_roll = gr.Image(label=f"Piano Roll {i + 1}", scale=3)
audio_player = gr.Audio(label=f"Play Chords {i + 1}", interactive=False, scale=3)
realization_outputs += (midi_output, piano_roll, audio_player)
generate_mvmt_button.click(
fn=self.generate_movements,
inputs=[],
outputs = realization_outputs
)
with gr.TabItem("Settings"):
gr.Markdown("### Configuration Options")
setting_1 = gr.Checkbox(label="Enable Advanced Mode")
setting_2 = gr.Slider(0, 100, label="Complexity Level")
self.ui = ui
def get_known_hexachords_choice(self):
return self._hexachord.known_hexachords
def get_selected_hexachord(self, x):
# lambda x: {"Hexachord 1": "C3 D3 E3 G3 A3 B3", "Hexachord 2": "D3 E3 F3 A3 B3 C4",
# "Hexachord 3": "E3 G3 A3 C4 D4 F4"}.get(x, "")
item = x[x.index('['):x.index(']')+1]
int_array = np.array(ast.literal_eval(item))
hexa_string = ''
start_note = note.Note('C3')
for i in int_array:
add_note = start_note.transpose(int(i))
hexa_string = hexa_string + ' ' + add_note.nameWithOctave
return hexa_string
def launch_app():
hex = HexachordApp()
hex.is_fsynth_installed()
hex.render()
if hex.on_huggingface:
hex.ui.launch(server_name="0.0.0.0", server_port=7860, share=True)
else:
hex.ui.launch(server_name="0.0.0.0", server_port=7860)
launch_app()
|