File size: 4,397 Bytes
21a0b97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fcbbb62
 
 
219f12e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fcbbb62
219f12e
 
21a0b97
 
 
 
 
 
 
 
fcbbb62
 
 
 
 
21a0b97
fcbbb62
 
 
 
 
 
21a0b97
fcbbb62
 
 
 
 
e07c9a8
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
import os
import time
import numpy as np
import librosa
import soundfile as sf
import pyloudnorm as pyln
import scipy.signal
import gradio as gr

# ---- CONFIG ----
TARGET_LOUDNESS = -24.0
FINAL_LOUDNESS = -14.0

# ---- AUDIO PROCESSING FUNCTIONS ----
def normalize_loudness(audio, sr, target_lufs):
    meter = pyln.Meter(sr)
    return pyln.normalize.loudness(audio, meter.integrated_loudness(audio), target_lufs)

def highpass(audio, sr, cutoff=40):
    sos = scipy.signal.butter(2, cutoff, btype='highpass', fs=sr, output='sos')
    return scipy.signal.sosfilt(sos, audio)

def pan_stereo(mono_audio, pan):
    left = mono_audio * (1 - max(0, pan))
    right = mono_audio * (1 - max(0, -pan))
    return np.vstack((left, right))

def auto_mix(track1, track2, track3, track4, track5, track6, track7, track8,
             vol1, vol2, vol3, vol4, vol5, vol6, vol7, vol8,
             pan1, pan2, pan3, pan4, pan5, pan6, pan7, pan8,
             bass_boost=0.0, brightness=0.0, vocal_boost=0.0):

    tracks = [track1, track2, track3, track4, track5, track6, track7, track8]
    volumes = [vol1, vol2, vol3, vol4, vol5, vol6, vol7, vol8]
    pans = [pan1, pan2, pan3, pan4, pan5, pan6, pan7, pan8]

    tracks_info = [(t, v, p) for t, v, p in zip(tracks, volumes, pans) if t is not None]
    if not tracks_info:
        return None

    stems = []
    sr = None

    for t, vol, pan in tracks_info:
        fpath = t.name
        audio, sr = librosa.load(fpath, sr=None, mono=True)
        audio = normalize_loudness(audio, sr, TARGET_LOUDNESS)
        audio = highpass(audio, sr)

        if bass_boost > 0:
            sos = scipy.signal.butter(2, 150, btype='low', fs=sr, output='sos')
            audio += bass_boost * scipy.signal.sosfilt(sos, audio)
        if brightness > 0:
            sos = scipy.signal.butter(2, 4000, btype='high', fs=sr, output='sos')
            audio += brightness * scipy.signal.sosfilt(sos, audio)
        if vocal_boost > 0 and "voc" in os.path.basename(fpath).lower():
            audio *= (1.0 + vocal_boost)

        audio *= vol
        stems.append(pan_stereo(audio, pan))

    max_len = max(stem.shape[1] for stem in stems)
    mix = np.zeros((2, max_len))
    for stem in stems:
        padded = np.zeros((2, max_len))
        padded[:, :stem.shape[1]] = stem
        mix += padded

    meter = pyln.Meter(sr)
    mix = pyln.normalize.loudness(mix.T, meter.integrated_loudness(mix.T), FINAL_LOUDNESS).T

    timestamp = time.strftime("%Y%m%d_%H%M%S")
    out_file = f"mix_{timestamp}.wav"
    sf.write(out_file, mix.T, sr)
    return out_file

# ---- GRADIO UI ----
with gr.Blocks() as demo:
    gr.Markdown("## 🎚️ Mini Automatic Mixer (Online Version)")

    tracks = []
    vols = []
    pans = []

    # ---- First row: Track 1-4 ----
    with gr.Row():
        for i in range(4):
            with gr.Column():
                track = gr.File(label=f"Track {i+1}", file_types=[".wav", ".aiff", ".mp3"])
                vol = gr.Slider(0, 2.0, step=0.05, label="Volume", value=1.0)
                pan = gr.Slider(-1.0, 1.0, step=0.05, label="Pan", value=0.0)
                tracks.append(track)
                vols.append(vol)
                pans.append(pan)

    # ---- Second row: Track 5-8 ----
    with gr.Row():
        for i in range(4, 8):
            with gr.Column():
                track = gr.File(label=f"Track {i+1}", file_types=[".wav", ".aiff", ".mp3"])
                vol = gr.Slider(0, 2.0, step=0.05, label="Volume", value=1.0)
                pan = gr.Slider(-1.0, 1.0, step=0.05, label="Pan", value=0.0)
                tracks.append(track)
                vols.append(vol)
                pans.append(pan)

    # ---- General effects row ----
    with gr.Row():
        bass = gr.Slider(0, 1.0, step=0.1, label="Bass Boost")
        bright = gr.Slider(0, 1.0, step=0.1, label="Brightness")
        vocal = gr.Slider(0, 1.0, step=0.1, label="Vocal Boost (files with 'voc' in name)")

    # ---- Mix / Preview / Download ----
    mix_btn = gr.Button("🎛️ Auto Mix & Master")
    audio_out = gr.Audio(label="Preview Mix", type="filepath")
    download_btn = gr.File(label="Download Mix")

    mix_btn.click(
        auto_mix,
        inputs=tracks + vols + pans + [bass, bright, vocal],
        outputs=[audio_out]
    )

    audio_out.change(lambda f: f, inputs=audio_out, outputs=download_btn)

demo.launch(share=True)