Spaces:
Paused
Paused
File size: 4,942 Bytes
af8e0fa b12171d ff5958c 70b3168 af8e0fa d14d2b9 af8e0fa 62ea0b2 aab2da5 d09f276 70b3168 aab2da5 d09f276 70b3168 256bf62 aab2da5 d09f276 aab2da5 b12171d d09f276 aab2da5 62ea0b2 d09f276 00b2148 d09f276 b12171d 70b3168 af8e0fa b4e60ac af8e0fa 3ea06c2 9a36366 00b2148 a07d0b1 b12171d af8e0fa b12171d a07d0b1 af8e0fa b12171d af8e0fa b12171d af8e0fa b12171d af8e0fa b12171d |
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 |
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() |