import gradio as gr import os import allin1 import zipfile import shutil from subprocess import Popen from concurrent.futures import ThreadPoolExecutor from pathlib import Path from dissector import generate_dissector_data HEADER = """

All-In-One Music Structure Analyzer 🔮

[Python Package] [Paper] [Visual Demo]

This Space demonstrates the music structure analyzer predicts:

It takes about 4:30 to analyze a 3-minute song. If you are in a hurry, you can try the examples at the bottom.

For more information, please visit the links above ✨🧸

""" CACHE_EXAMPLES = os.getenv('CACHE_EXAMPLES', '1') == '1' BASIC_PITCH_DIR = "basic-pitch" def compress_files(demucs_output_path, dissector_file, original_audio): """Compresses specific files in the specified folder into a .zip file""" # List of the files to be compressed wav_files = ['bass.wav', 'drums.wav', 'other.wav', 'vocals.wav'] mp3_files = [file.replace('.wav', '.mp3') for file in wav_files] def convert_to_mp3(wav, mp3): """Utility function to run the ffmpeg command""" command = ["ffmpeg", "-i", os.path.join(demucs_output_path, wav), os.path.join(demucs_output_path, mp3)] process = Popen(command) process.communicate() # Use ThreadPoolExecutor to convert .wav files to .mp3 in parallel with ThreadPoolExecutor(max_workers=8) as executor: list(executor.map(convert_to_mp3, wav_files, mp3_files)) try: shutil.rmtree(BASIC_PITCH_DIR) except: # FileNotFoundError on first run pass if not os.path.exists(BASIC_PITCH_DIR): os.makedirs(BASIC_PITCH_DIR) command = [ "basic-pitch", '--save-note-events', BASIC_PITCH_DIR, os.path.join(demucs_output_path, 'bass.wav'), os.path.join(demucs_output_path, 'vocals.wav'), os.path.join(demucs_output_path, 'other.wav') ] process = Popen(command) process.communicate() # Compress the files zip_path = demucs_output_path + ".zip" with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf: for mp3 in mp3_files: zipf.write(os.path.join(demucs_output_path, mp3), arcname=mp3) zipf.write(f'{BASIC_PITCH_DIR}/bass_basic_pitch.mid', arcname='bass_basic_pitch.mid') zipf.write(f'{BASIC_PITCH_DIR}/vocals_basic_pitch.mid', arcname='vocals_basic_pitch.mid') zipf.write(f'{BASIC_PITCH_DIR}/other_basic_pitch.mid', arcname='other_basic_pitch.mid') zipf.write(f'{BASIC_PITCH_DIR}/bass_basic_pitch.csv', arcname='bass_basic_pitch.csv') zipf.write(f'{BASIC_PITCH_DIR}/vocals_basic_pitch.csv', arcname='vocals_basic_pitch.csv') zipf.write(f'{BASIC_PITCH_DIR}/other_basic_pitch.csv', arcname='other_basic_pitch.csv') zipf.write(dissector_file, arcname='dissector.json') # Fixed name zipf.write(original_audio, arcname='mixdown.mp3') # Added original audio return zip_path def analyze(path): path = Path(path) result = allin1.analyze( path, keep_byproducts=True, # TODO(taejun): remove this ) fig = allin1.visualize(result) fig.set_dpi(300) allin1.sonify(result, out_dir='./sonif') sonif_path = Path(f'./sonif/{path.stem}.sonif{path.suffix}').resolve().as_posix() dissector_file = generate_dissector_data(path.stem, result) compressed_file = compress_files(f"demix/htdemucs/{path.stem}", dissector_file, path.as_posix()) return result.bpm, fig, sonif_path, compressed_file with gr.Blocks() as demo: gr.HTML(HEADER) input_audio_path = gr.Audio( label='Input', source='upload', type='filepath', format='mp3', show_download_button=False, ) button = gr.Button('Analyze', variant='primary') output_viz = gr.Plot(label='Visualization') with gr.Row(): output_bpm = gr.Textbox(label='BPM', scale=1) output_sonif = gr.Audio( label='Sonification', type='filepath', format='mp3', show_download_button=False, scale=9, ) output_compressed = gr.File( label="Compressed Files", type="file", ) gr.Examples( examples=[ './assets/kult.mp3', # './assets/krematorii.mp3', # './assets/NewJeans - Super Shy.mp3', # './assets/Bruno Mars - 24k Magic.mp3' ], inputs=input_audio_path, outputs=[output_bpm, output_viz, output_sonif, output_compressed], fn=analyze, cache_examples=CACHE_EXAMPLES, ) button.click( fn=analyze, inputs=input_audio_path, outputs=[output_bpm, output_viz, output_sonif, output_compressed], api_name='analyze', ) if __name__ == '__main__': demo.launch()