all-in-one / app.py
vpavlenko's picture
Update app.py
62ea0b2
raw
history blame
4.94 kB
import gradio as gr
import os
import allin1
import zipfile
from subprocess import Popen
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path
from dissector import generate_dissector_data
HEADER = """
<header style="text-align: center;">
<h1>
All-In-One Music Structure Analyzer 🔮
</h1>
<p>
<a href="https://github.com/mir-aidj/all-in-one">[Python Package]</a>
<a href="https://arxiv.org/abs/2307.16425">[Paper]</a>
<a href="https://taejun.kim/music-dissector/">[Visual Demo]</a>
</p>
</header>
<main
style="display: flex; justify-content: center;"
>
<div
style="display: inline-block;"
>
<p>
This Space demonstrates the music structure analyzer predicts:
<ul
style="padding-left: 1rem;"
>
<li>BPM</li>
<li>Beats</li>
<li>Downbeats</li>
<li>Functional segment boundaries</li>
<li>Functional segment labels (e.g. intro, verse, chorus, bridge, outro)</li>
</ul>
</p>
<p>
It takes about 4:30 to analyze a 3-minute song.
If you are in a hurry, you can <strong><u>try the examples at the bottom</u></strong>.
</p>
<p>
For more information, please visit the links above ✨🧸
</p>
</div>
</main>
"""
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))
if not os.path.exists(BASIC_PITCH_DIR):
os.makedirs(BASIC_PITCH_DIR)
command = [
"basic-pitch",
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(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()