szili2011's picture
Create app.py
46cea13 verified
import random
import librosa
import soundfile as sf
import gradio as gr
from pydub import AudioSegment
from pydub.silence import split_on_silence
def load_audio(file):
audio, sr = librosa.load(file, sr=None)
return audio, sr
def sync_to_same_bpm(instrumental_1, instrumental_2):
bpm_1 = librosa.beat.tempo(instrumental_1)[0]
bpm_2 = librosa.beat.tempo(instrumental_2)[0]
target_bpm = max(bpm_1, bpm_2)
rate_1 = target_bpm / bpm_1
rate_2 = target_bpm / bpm_2
inst1_synced = librosa.effects.time_stretch(instrumental_1, rate_1)
inst2_synced = librosa.effects.time_stretch(instrumental_2, rate_2)
return inst1_synced, inst2_synced, target_bpm
def split_vocals_on_silence(vocals_file):
vocals_audio = AudioSegment.from_file(vocals_file)
# Split vocals at points with at least 0.8 seconds of silence or near-silence
vocal_segments = split_on_silence(
vocals_audio, min_silence_len=800, silence_thresh=vocals_audio.dBFS - 14
)
return vocal_segments
def create_mashup(opponent_vocals, player_vocals, instrumental_1, instrumental_2):
# Load and sync audio files
inst1_audio, sr = load_audio(instrumental_1)
inst2_audio, _ = load_audio(instrumental_2)
inst1_sync, inst2_sync, bpm = sync_to_same_bpm(inst1_audio, inst2_audio)
# Split vocals into segments based on silence detection
opponent_segments = split_vocals_on_silence(opponent_vocals)
player_segments = split_vocals_on_silence(player_vocals)
# Randomly alternate between opponent and player vocal segments
vocal_turns = []
for _ in range(10): # Set the number of turns (adjustable)
segment = random.choice(opponent_segments + player_segments)
vocal_turns.append(segment)
# Generate mashup by combining each vocal turn with alternating instrumentals
mashup = []
for i, vocal_segment in enumerate(vocal_turns):
inst = inst1_sync if i % 2 == 0 else inst2_sync
vocal_segment = vocal_segment.set_frame_rate(sr).set_channels(1)
combined = vocal_segment.overlay(AudioSegment.from_array(inst, frame_rate=sr))
mashup.append(combined)
final_mashup = sum(mashup)
output_file = "mashup.wav"
final_mashup.export(output_file, format="wav")
return output_file
# Interface with Gradio
iface = gr.Interface(
fn=create_mashup,
inputs=[
gr.Audio(label="Opponent Vocals", type="filepath"),
gr.Audio(label="Player Vocals", type="filepath"),
gr.Audio(label="Instrumental #1", type="filepath"),
gr.Audio(label="Instrumental #2", type="filepath"),
],
outputs=gr.Audio(label="Mashup Output"),
title="FNF Mashup Maker",
description="Upload FNF opponent and player vocals along with two instrumentals to generate a randomized mashup."
)
iface.launch()