File size: 2,848 Bytes
46cea13
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
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()