CoolFace
Apppublic

DavidShiver/mastering-ai

sourceHugging Faceupdated 7mo agoView on Hugging Face
0likes
app.py126 linesDownload Raw Back to root
1import gradio as gr2import librosa3import numpy as np4import soundfile as sf5import scipy.signal as signal6 7def calculate_loudness_db(y):8    rms = np.sqrt(np.mean(y**2)) + 1e-99    return 20 * np.log10(rms)10 11def match_loudness(target, source):12    target_rms = np.sqrt(np.mean(target**2)) + 1e-913    source_rms = np.sqrt(np.mean(source**2)) + 1e-914    return source * (target_rms / source_rms)15 16def apply_high_shelf(y, sr, gain_db, freq=10000):17    if abs(gain_db) < 0.1: return y18    A = 10**(gain_db/40)19    w0 = 2 * np.pi * freq / sr20    alpha = np.sin(w0) / 2 * np.sqrt(2)21    cos_w0 = np.cos(w0)22    b0 = A * ((A+1) + (A-1)*cos_w0 + 2*np.sqrt(A)*alpha)23    b1 = -2 * A * ((A-1) + (A+1)*cos_w0)24    b2 = A * ((A+1) + (A-1)*cos_w0 - 2*np.sqrt(A)*alpha)25    a0 = (A+1) - (A-1)*cos_w0 + 2*np.sqrt(A)*alpha26    a1 = 2 * ((A-1) - (A+1)*cos_w0)27    a2 = (A+1) - (A-1)*cos_w0 - 2*np.sqrt(A)*alpha28    return signal.lfilter([b0, b1, b2], [a0, a1, a2], y)29 30def master_v14_engine(audio, saturation_bp, stereo_bp, bass_bp, air_shelf, l_drive, l_ceiling, post_gain):31    if audio is None: return None, None, "Brak pliku."32    try:33        y, sr = librosa.load(audio, sr=44100, mono=False)34        if len(y.shape) < 2: y = np.array([y, y])35        orig_db = calculate_loudness_db(y)36        37        mid = (y[0] + y[1]) * 0.538        side = (y[0] - y[1]) * 0.539        40        # 1. Korekcja Tonalna41        sos_low = signal.butter(4, 100, 'lp', fs=sr, output='sos')42        mid = mid + (signal.sosfilt(sos_low, mid) * (bass_bp / 100))43        44        if stereo_bp < 0:45            side *= (1.0 + (stereo_bp / 100))46        else:47            sos_high_s = signal.butter(2, 200, 'hp', fs=sr, output='sos')48            side += signal.sosfilt(sos_high_s, side) * (stereo_bp / 100)49            50        y_proc = np.array([mid + side, mid - side])51        52        # 2. Saturation & Air53        if abs(saturation_bp) > 0.1:54            drive = 1.0 + (abs(saturation_bp) / 100)55            y_proc = np.tanh(y_proc * drive) / drive if saturation_bp > 0 else y_proc * (1.0 - abs(saturation_bp)/200)56        57        y_proc = apply_high_shelf(y_proc, sr, air_shelf / 15, freq=10000)58        59        # 3. LOGIKA LIMITERA (ZMIANA)60        # Limiter Drive - zwiększa głośność odczuwalną przed "sufitem"61        drive_factor = 10**(l_drive / 20)62        y_limited = np.tanh(y_proc * drive_factor) # Soft-clipping jako limiter63        64        # Final Ceiling & Post-Gain65        # Teraz l_ceiling to absolutna granica, a post_gain to Twoja kontrola głośności zgrania66        ceiling_linear = 10**(l_ceiling / 20)67        gain_linear = 10**(post_gain / 20)68        69        # Skalowanie bez wymuszonej normalizacji do 0dB70        y_final = y_limited * ceiling_linear * gain_linear71        72        # Zabezpieczenie przed twardym clippingiem powyżej ceilingu73        y_final = np.clip(y_final, -ceiling_linear, ceiling_linear)74        75        # 4. Export & Report76        out_pro_path = "master_v14_24bit.wav"77        out_match_path = "compare_matched.wav"78        sf.write(out_pro_path, y_final.T, sr, subtype='PCM_24')79        sf.write(out_match_path, match_loudness(y, y_final).T, sr, subtype='PCM_16')80        81        db_diff = calculate_loudness_db(y_final) - orig_db82        83        report = (f"Raport Inżynieryjny:\n"84                  f"• Wzmocnienie efektywne: {db_diff:.2f} dB\n"85                  f"• Ustawiony sufic (Ceiling): {l_ceiling} dB\n"86                  f"• Dodatkowe tłumienie zgrania: {post_gain} dB\n"87                  f"• Dynamika: Zachowana dzięki architekturze Gain-Stage")88        89        return out_pro_path, out_match_path, report90 91    except Exception as e:92        return None, None, f"Błąd: {str(e)}"93 94with gr.Blocks(theme=gr.themes.Monochrome()) as demo:95    gr.Markdown("# 🎚️ AI MASTERING STUDIO V14 - DYNAMIC ARCHITECTURE")96    with gr.Row():97        with gr.Column(scale=1):98            in_audio = gr.Audio(label="Mix", type="filepath")99            gr.Markdown("### 🎛️ Korekcja")100            with gr.Row():101                saturator = gr.Slider(-100, 100, value=10, label="Saturation")102                stereo = gr.Slider(-100, 100, value=20, label="Stereo Width")103            with gr.Row():104                bass = gr.Slider(-100, 100, value=10, label="Bass")105                air = gr.Slider(-100, 100, value=15, label="10kHz Air")106            107            gr.Markdown("### 🛡️ Sekcja Dynamiki (Limiter)")108            l_drive = gr.Slider(0, 20, value=3, step=0.5, label="Limiter Input Drive (dB) - 'Gęstość'")109            l_ceiling = gr.Slider(-6.0, -0.1, value=-0.3, step=0.1, label="Ceiling (Limit Peak)")110            post_gain = gr.Slider(-20.0, 0.0, value=0.0, step=0.5, label="Final Export Gain (dB) - 'Głośność zgrania'")111            112            btn = gr.Button("🚀 GENERUJ MASTER", variant="primary")113            114        with gr.Column(scale=1):115            status = gr.Textbox(label="Analiza AI", lines=5)116            out_pro = gr.Audio(label="24-bit MASTER")117            out_matched = gr.Audio(label="PORÓWNANIE (Loudness Match)")118 119    btn.click(fn=master_v14_engine, inputs=[in_audio, saturator, stereo, bass, air, l_drive, l_ceiling, post_gain], outputs=[out_pro, out_matched, status])120 121demo.launch()122 123 124 125 126