Spaces:
Running
Running
ziqiangao
commited on
Commit
·
25c18af
1
Parent(s):
e0df6af
update app.py
Browse files
app.py
CHANGED
@@ -15,7 +15,6 @@ import subprocess
|
|
15 |
import traceback
|
16 |
import time
|
17 |
import shutil
|
18 |
-
import LRC
|
19 |
import LRC2SRT
|
20 |
|
21 |
path = "" # Update with your path
|
@@ -26,7 +25,6 @@ def safe_read(i: int, a: list):
|
|
26 |
else:
|
27 |
return a[i]
|
28 |
|
29 |
-
|
30 |
def getRenderCords(ta: list, idx: int, res: int = 1024, size: tuple = (1280, 720)) -> list:
|
31 |
i = idx - res // 2
|
32 |
x, y = size[0] * .9 / -2, (ta[i] - 128) * (size[1] / 2000) + (size[1] * .7 / -2)
|
@@ -69,8 +67,6 @@ def getTitleAndArtist(mp3_file):
|
|
69 |
audio = MP3(mp3_file, ID3=ID3)
|
70 |
title = audio.get('TIT2', TIT2(encoding=3, text='')).text[0]
|
71 |
artist = audio.get('TPE1', TPE1(encoding=3, text='')).text[0]
|
72 |
-
|
73 |
-
|
74 |
return title, artist
|
75 |
|
76 |
def getColour(img):
|
@@ -144,8 +140,7 @@ def render_frame(params):
|
|
144 |
(linear_interpolate(width * .95 // -2, width * .95 // 2, s / len(samples_array)),
|
145 |
height * .95 // -2)],width=width, height=height), fill='#fff', width=10 * height // 360)
|
146 |
|
147 |
-
|
148 |
-
img.save(path+f'out/{name}/{str(n)}.png', 'PNG',)
|
149 |
|
150 |
return 1 # Indicate one frame processed
|
151 |
|
@@ -169,7 +164,9 @@ def stripinvisibles(s):
|
|
169 |
for i in invisible_chars:
|
170 |
e.replace(i,"")
|
171 |
return e
|
|
|
172 |
haslyrics = False
|
|
|
173 |
def main(file, name, fps=30, res: tuple=(1280,720), oscres=512, sr=11025, lyrics=None, img=None, tit=None, ast=None):
|
174 |
p = gr.Progress()
|
175 |
LRC2SRT.clear()
|
@@ -178,11 +175,10 @@ def main(file, name, fps=30, res: tuple=(1280,720), oscres=512, sr=11025, lyrics
|
|
178 |
global haslyrics
|
179 |
haslyrics = False
|
180 |
if lyrics:
|
181 |
-
p(0.5,"parsing lyrics")
|
182 |
try:
|
183 |
-
outf = open("out.srt",mode="x", encoding="UTF8")
|
184 |
sf = stripinvisibles(open(lyrics, encoding="UTF8").read())
|
185 |
-
print(sf[0])
|
186 |
if sf[0] == '[':
|
187 |
gr.Info("Lyrics of LRC type was detected, converting to SRT")
|
188 |
LRC2SRT.convert_to_srt(sf)
|
@@ -198,30 +194,29 @@ def main(file, name, fps=30, res: tuple=(1280,720), oscres=512, sr=11025, lyrics
|
|
198 |
print(traceback.format_exc())
|
199 |
gr.Warning("Failed to parse lyrics, ensure there are no blank lines in between")
|
200 |
|
201 |
-
os.makedirs(path+f'out/{name}/', exist_ok=True)
|
202 |
global iii
|
203 |
iii = 0
|
204 |
# Load the audio file
|
205 |
-
p(0.25,"loading file")
|
206 |
audio_path = file
|
207 |
y, sr = librosa.load(audio_path, sr=sr) # Resample to 11025 Hz
|
208 |
y_u8 = (y * 128 + 128).astype('uint8')
|
209 |
samples_array = y_u8.tolist()
|
210 |
-
p(0.5,"extracting metadata")
|
211 |
# Extract cover image, title, and artist
|
212 |
cover_file = None
|
213 |
if img:
|
214 |
cover_file = Image.open(img)
|
215 |
cover_img = extract_cover_image(audio_path)
|
216 |
-
if cover_img
|
217 |
if img:
|
218 |
cover_img = cover_file
|
219 |
else:
|
220 |
raise gr.Error("Mp3 must have a cover image, upload the image under the 'Metadata' section")
|
221 |
elif cover_img == -1 and not (tit or ast):
|
222 |
raise gr.Error("Mp3 is missing tags, add the info under the 'Metadata' section")
|
223 |
-
|
224 |
-
|
225 |
title, artist = getTitleAndArtist(audio_path)
|
226 |
if title == '' or artist == '':
|
227 |
if not (tit or ast):
|
@@ -239,19 +234,17 @@ def main(file, name, fps=30, res: tuple=(1280,720), oscres=512, sr=11025, lyrics
|
|
239 |
|
240 |
try:
|
241 |
with Pool(cpu_count()) as pool:
|
242 |
-
|
243 |
num_frames = len(samples_array) // (sr // fps)
|
244 |
# Use imap to get progress updates
|
245 |
for _ in pool.imap_unordered(render_frame, params):
|
246 |
iii += 1 # Increment frame count for progress
|
247 |
-
p((iii,num_frames),desc="Rendering Frames")
|
248 |
|
249 |
-
|
250 |
except Exception as e:
|
251 |
print('Ended in error: ' + traceback.format_exc(), iii)
|
252 |
-
|
253 |
p = gr.Progress()
|
254 |
-
p(0.5,desc="Compiling video")
|
255 |
print('FFMPEG')
|
256 |
if haslyrics:
|
257 |
ffmpeg_cmd = [
|
@@ -272,56 +265,69 @@ def main(file, name, fps=30, res: tuple=(1280,720), oscres=512, sr=11025, lyrics
|
|
272 |
ffmpeg_cmd = [
|
273 |
"ffmpeg",
|
274 |
'-framerate', '30',
|
275 |
-
'-i', path+f'out/{name}/%d.png', # Input PNG images
|
276 |
-
'-i', f'{file}',
|
277 |
'-c:v', 'libx264',
|
278 |
'-r', '30',
|
279 |
'-pix_fmt', 'yuv420p',
|
280 |
'-c:a', 'aac',
|
281 |
'-y',
|
282 |
-
path+f'{name}.mp4' # Output MP4 filename
|
283 |
-
|
284 |
subprocess.run(ffmpeg_cmd)
|
285 |
|
|
|
|
|
286 |
def gradio_interface(audio_file, lyrics, output_name, fps=30, vidwidth=1280, vidheight=720, oscres=512, img=None, tit=None, ast=None):
|
287 |
resolution = f"{vidwidth}x{vidheight}"
|
288 |
res = tuple(map(int, resolution.split('x')))
|
289 |
-
main(audio_file, output_name, fps=fps, res=res, oscres=oscres, lyrics=lyrics, img=img, tit=tit, ast=ast)
|
290 |
time.sleep(5)
|
291 |
|
292 |
shutil.rmtree("out")
|
293 |
-
if haslyrics
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
return
|
298 |
|
299 |
with gr.Blocks() as inputs:
|
300 |
gr.Markdown('Upload an MP3 file and configure parameters to create a visualization video.\nOptionally upload a word or line synced lyric file\nEnsure a blank line at the end to avoid conversion errors')
|
301 |
with gr.Accordion(label="Audio Settings", open=True):
|
302 |
gr.Markdown('#Load your mp3 and lyrics file here')
|
303 |
-
gr.components.File(label="Upload your MP3 file", file_count='single', file_types=['mp3'])
|
304 |
-
gr.components.File(label="(Optional) Upload Lyrics as LRC or SRT", file_count='single', file_types=['lrc','srt'])
|
305 |
|
306 |
with gr.Accordion(label="Video Output Settings"):
|
307 |
gr.Markdown('#Configure Video Output Here')
|
308 |
-
gr.components.Textbox(label="Output Video Name", value='video')
|
309 |
-
gr.components.Slider(label="Frames per Second", minimum=20, maximum=60, step=1, value=30)
|
310 |
-
gr.components.Slider(label="Output Video Width", minimum=100, maximum=2000, value=1280, step=2)
|
311 |
-
gr.components.Slider(label="Output Video Height", minimum=100, maximum=2000, value=720, step=2)
|
312 |
-
|
313 |
-
|
314 |
-
|
|
|
|
|
315 |
gr.Markdown('#Add Metadata here if your mp3 does not have one')
|
316 |
-
gr.components.Image(label='Cover Art')
|
317 |
-
gr.components.Textbox(label='Title')
|
318 |
-
gr.components.Textbox(label='Artists')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
319 |
|
320 |
iface = gr.Interface(
|
321 |
fn=gradio_interface,
|
322 |
inputs=inputs,
|
323 |
-
outputs=[
|
324 |
)
|
325 |
|
326 |
# Launch Gradio interface
|
327 |
-
iface.launch()
|
|
|
15 |
import traceback
|
16 |
import time
|
17 |
import shutil
|
|
|
18 |
import LRC2SRT
|
19 |
|
20 |
path = "" # Update with your path
|
|
|
25 |
else:
|
26 |
return a[i]
|
27 |
|
|
|
28 |
def getRenderCords(ta: list, idx: int, res: int = 1024, size: tuple = (1280, 720)) -> list:
|
29 |
i = idx - res // 2
|
30 |
x, y = size[0] * .9 / -2, (ta[i] - 128) * (size[1] / 2000) + (size[1] * .7 / -2)
|
|
|
67 |
audio = MP3(mp3_file, ID3=ID3)
|
68 |
title = audio.get('TIT2', TIT2(encoding=3, text='')).text[0]
|
69 |
artist = audio.get('TPE1', TPE1(encoding=3, text='')).text[0]
|
|
|
|
|
70 |
return title, artist
|
71 |
|
72 |
def getColour(img):
|
|
|
140 |
(linear_interpolate(width * .95 // -2, width * .95 // 2, s / len(samples_array)),
|
141 |
height * .95 // -2)],width=width, height=height), fill='#fff', width=10 * height // 360)
|
142 |
|
143 |
+
img.save(path+f'out/{name}/{str(n)}.png', 'PNG')
|
|
|
144 |
|
145 |
return 1 # Indicate one frame processed
|
146 |
|
|
|
164 |
for i in invisible_chars:
|
165 |
e.replace(i,"")
|
166 |
return e
|
167 |
+
|
168 |
haslyrics = False
|
169 |
+
|
170 |
def main(file, name, fps=30, res: tuple=(1280,720), oscres=512, sr=11025, lyrics=None, img=None, tit=None, ast=None):
|
171 |
p = gr.Progress()
|
172 |
LRC2SRT.clear()
|
|
|
175 |
global haslyrics
|
176 |
haslyrics = False
|
177 |
if lyrics:
|
178 |
+
p(0.5, "parsing lyrics")
|
179 |
try:
|
180 |
+
outf = open("out.srt", mode="x", encoding="UTF8")
|
181 |
sf = stripinvisibles(open(lyrics, encoding="UTF8").read())
|
|
|
182 |
if sf[0] == '[':
|
183 |
gr.Info("Lyrics of LRC type was detected, converting to SRT")
|
184 |
LRC2SRT.convert_to_srt(sf)
|
|
|
194 |
print(traceback.format_exc())
|
195 |
gr.Warning("Failed to parse lyrics, ensure there are no blank lines in between")
|
196 |
|
197 |
+
os.makedirs(path + f'out/{name}/', exist_ok=True)
|
198 |
global iii
|
199 |
iii = 0
|
200 |
# Load the audio file
|
201 |
+
p(0.25, "loading file")
|
202 |
audio_path = file
|
203 |
y, sr = librosa.load(audio_path, sr=sr) # Resample to 11025 Hz
|
204 |
y_u8 = (y * 128 + 128).astype('uint8')
|
205 |
samples_array = y_u8.tolist()
|
206 |
+
p(0.5, "extracting metadata")
|
207 |
# Extract cover image, title, and artist
|
208 |
cover_file = None
|
209 |
if img:
|
210 |
cover_file = Image.open(img)
|
211 |
cover_img = extract_cover_image(audio_path)
|
212 |
+
if cover_img is None:
|
213 |
if img:
|
214 |
cover_img = cover_file
|
215 |
else:
|
216 |
raise gr.Error("Mp3 must have a cover image, upload the image under the 'Metadata' section")
|
217 |
elif cover_img == -1 and not (tit or ast):
|
218 |
raise gr.Error("Mp3 is missing tags, add the info under the 'Metadata' section")
|
219 |
+
|
|
|
220 |
title, artist = getTitleAndArtist(audio_path)
|
221 |
if title == '' or artist == '':
|
222 |
if not (tit or ast):
|
|
|
234 |
|
235 |
try:
|
236 |
with Pool(cpu_count()) as pool:
|
|
|
237 |
num_frames = len(samples_array) // (sr // fps)
|
238 |
# Use imap to get progress updates
|
239 |
for _ in pool.imap_unordered(render_frame, params):
|
240 |
iii += 1 # Increment frame count for progress
|
241 |
+
p((iii, num_frames), desc="Rendering Frames")
|
242 |
|
|
|
243 |
except Exception as e:
|
244 |
print('Ended in error: ' + traceback.format_exc(), iii)
|
245 |
+
|
246 |
p = gr.Progress()
|
247 |
+
p(0.5, desc="Compiling video")
|
248 |
print('FFMPEG')
|
249 |
if haslyrics:
|
250 |
ffmpeg_cmd = [
|
|
|
265 |
ffmpeg_cmd = [
|
266 |
"ffmpeg",
|
267 |
'-framerate', '30',
|
268 |
+
'-i', path + f'out/{name}/%d.png', # Input PNG images
|
269 |
+
'-i', f'{file}', # Input MP3 audio
|
270 |
'-c:v', 'libx264',
|
271 |
'-r', '30',
|
272 |
'-pix_fmt', 'yuv420p',
|
273 |
'-c:a', 'aac',
|
274 |
'-y',
|
275 |
+
path + f'{name}.mp4' # Output MP4 filename
|
276 |
+
]
|
277 |
subprocess.run(ffmpeg_cmd)
|
278 |
|
279 |
+
return f"{name}.mp4", haslyrics
|
280 |
+
|
281 |
def gradio_interface(audio_file, lyrics, output_name, fps=30, vidwidth=1280, vidheight=720, oscres=512, img=None, tit=None, ast=None):
|
282 |
resolution = f"{vidwidth}x{vidheight}"
|
283 |
res = tuple(map(int, resolution.split('x')))
|
284 |
+
video_file, haslyrics = main(audio_file, output_name, fps=fps, res=res, oscres=oscres, lyrics=lyrics, img=img, tit=tit, ast=ast)
|
285 |
time.sleep(5)
|
286 |
|
287 |
shutil.rmtree("out")
|
288 |
+
srt_output = "out.srt" if haslyrics else None
|
289 |
+
return video_file, srt_output
|
290 |
+
|
291 |
+
def update_srt_output_visibility(haslyrics):
|
292 |
+
return gr.update(visible=haslyrics)
|
293 |
|
294 |
with gr.Blocks() as inputs:
|
295 |
gr.Markdown('Upload an MP3 file and configure parameters to create a visualization video.\nOptionally upload a word or line synced lyric file\nEnsure a blank line at the end to avoid conversion errors')
|
296 |
with gr.Accordion(label="Audio Settings", open=True):
|
297 |
gr.Markdown('#Load your mp3 and lyrics file here')
|
298 |
+
audio_file = gr.components.File(label="Upload your MP3 file", file_count='single', file_types=['mp3'])
|
299 |
+
lyrics_file = gr.components.File(label="(Optional) Upload Lyrics as LRC or SRT", file_count='single', file_types=['lrc', 'srt'])
|
300 |
|
301 |
with gr.Accordion(label="Video Output Settings"):
|
302 |
gr.Markdown('#Configure Video Output Here')
|
303 |
+
output_name = gr.components.Textbox(label="Output Video Name", value='video')
|
304 |
+
fps_slider = gr.components.Slider(label="Frames per Second", minimum=20, maximum=60, step=1, value=30)
|
305 |
+
vidwidth_slider = gr.components.Slider(label="Output Video Width", minimum=100, maximum=2000, value=1280, step=2)
|
306 |
+
vidheight_slider = gr.components.Slider(label="Output Video Height", minimum=100, maximum=2000, value=720, step=2)
|
307 |
+
|
308 |
+
with gr.Accordion(title="Advanced Options"):
|
309 |
+
oscres_slider = gr.components.Slider(label="Number of Visualization Segments", minimum=256, maximum=2048, step=2, value=512)
|
310 |
+
|
311 |
+
with gr.Accordion(title="Mp3 Metadata"):
|
312 |
gr.Markdown('#Add Metadata here if your mp3 does not have one')
|
313 |
+
cover_img = gr.components.Image(label='Cover Art')
|
314 |
+
title_input = gr.components.Textbox(label='Title')
|
315 |
+
artist_input = gr.components.Textbox(label='Artists')
|
316 |
+
|
317 |
+
output_video = gr.components.Video(label="Output")
|
318 |
+
srt_output = gr.components.File(label="SRT Output", visible=False)
|
319 |
+
|
320 |
+
inputs.load(fn=gradio_interface,
|
321 |
+
inputs=[audio_file, lyrics_file, output_name, fps_slider, vidwidth_slider, vidheight_slider, oscres_slider, cover_img, title_input, artist_input],
|
322 |
+
outputs=[output_video, srt_output])
|
323 |
+
|
324 |
+
inputs.load(fn=update_srt_output_visibility, inputs=None, outputs=srt_output)
|
325 |
|
326 |
iface = gr.Interface(
|
327 |
fn=gradio_interface,
|
328 |
inputs=inputs,
|
329 |
+
outputs=[output_video, srt_output]
|
330 |
)
|
331 |
|
332 |
# Launch Gradio interface
|
333 |
+
iface.launch()
|