reallyrogueradio commited on
Commit
81882f8
ยท
verified ยท
1 Parent(s): c89ca77

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +131 -0
app.py ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import numpy as np
3
+ import scipy.signal as signal
4
+ import librosa
5
+ import plotly.graph_objects as go
6
+ from plotly.subplots import make_subplots
7
+
8
+ def run_forensic_analysis(vocal_file, master_file):
9
+ if not vocal_file or not master_file:
10
+ return None, None, None, "โŒ Error: Please upload both assets to run diagnostics."
11
+
12
+ # Load audio clips (Optimized downsampling & 60-second execution cap)
13
+ y_v, sr_v = librosa.load(vocal_file, sr=22050, duration=60.0)
14
+ y_m, sr_m = librosa.load(master_file, sr=22050, duration=60.0)
15
+
16
+ # =================================================================
17
+ # MODULE 1: STRUCTURAL RECURRENCE MAPPER (SSM)
18
+ # =================================================================
19
+ # Extract chroma features to map harmonic patterns
20
+ chroma = librosa.feature.chroma_stft(y=y_m, sr=sr_m, hop_length=1024)
21
+ chroma = librosa.util.normalize(chroma, axis=0)
22
+ ssm = np.dot(chroma.T, chroma)
23
+
24
+ fig_ssm = go.Figure(data=gr.Plot(go.Heatmap(
25
+ z=ssm, colorscale='Viridis', showscale=False,
26
+ x0=0, dx=1024/sr_m, y0=0, dy=1024/sr_m
27
+ )))
28
+ fig_ssm.update_layout(
29
+ title="Structural Recurrence Matrix (Pattern Matches Over Time)",
30
+ xaxis_title="Timeline (Seconds)",
31
+ yaxis_title="Timeline (Seconds)",
32
+ height=400, margin=dict(l=10, r=10, t=40, b=10)
33
+ )
34
+
35
+ # =================================================================
36
+ # MODULE 2: MIX FORENSICS & FREQUENCY HEALTH
37
+ # =================================================================
38
+ centroid = librosa.feature.spectral_centroid(y=y_m, sr=sr_m, hop_length=512)[0]
39
+ flatness = librosa.feature.spectral_flatness(y=y_m, hop_length=512)[0]
40
+ t_m = librosa.times_like(centroid, sr=sr_m, hop_length=512)
41
+
42
+ rms_m = librosa.feature.rms(y=y_m)[0]
43
+ crest_factor = np.max(np.abs(y_m)) / (np.mean(rms_m) + 1e-6)
44
+
45
+ fig_mix = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.1)
46
+ fig_mix.add_trace(go.Scatter(x=t_m, y=centroid, mode='lines', name='Centroid (Brightness)', line=dict(color='#FF4B4B')), row=1, col=1)
47
+ fig_mix.add_trace(go.Scatter(x=t_m, y=flatness, mode='lines', name='Flatness (Noise/Harsh)', line=dict(color='#00E5FF')), row=2, col=1)
48
+
49
+ fig_mix.update_layout(
50
+ title="Spectral Diagnostic Vectors",
51
+ xaxis2_title="Timeline (Seconds)",
52
+ height=400, showlegend=False, margin=dict(l=10, r=10, t=40, b=10)
53
+ )
54
+
55
+ # =================================================================
56
+ # MODULE 3: SYLLABLE VELOCITY & PHRASING DENSITY
57
+ # =================================================================
58
+ onset_v = librosa.onset.onset_strength(y=y_v, sr=sr_v, hop_length=512)
59
+ t_v = librosa.times_like(onset_v, sr=sr_v, hop_length=512)
60
+
61
+ peaks, _ = signal.find_peaks(onset_v, height=0.2, distance=10)
62
+ peak_times = t_v[peaks]
63
+
64
+ # Calculate local density (syllables per second window)
65
+ window_sz = 2.0
66
+ density_y = []
67
+ for t in t_v:
68
+ count = np.sum((peak_times >= t - window_sz/2) & (peak_times <= t + window_sz/2))
69
+ density_y.append(count / window_sz)
70
+
71
+ fig_vocal = go.Figure()
72
+ fig_vocal.add_trace(go.Scatter(x=t_v, y=density_y, mode='lines', fill='tozeroy', line=dict(color='#00FF66', width=2)))
73
+ fig_vocal.update_layout(
74
+ title="Lyrical Delivery Velocity (Syllables Per Second)",
75
+ xaxis_title="Timeline (Seconds)",
76
+ yaxis_title="Syllables/Sec",
77
+ height=350, margin=dict(l=10, r=10, t=40, b=10)
78
+ )
79
+
80
+ # =================================================================
81
+ # DIAGNOSTIC SUMMARY GENERATOR
82
+ # =================================================================
83
+ avg_flatness = np.mean(flatness)
84
+ mix_critique = "Balanced clean spectrum." if avg_flatness < 0.01 else "High harshness/noise ratios detected."
85
+ if crest_factor > 5.0:
86
+ dynamics_status = "Dynamic, punchy transient preservation."
87
+ else:
88
+ dynamics_status = "Highly compressed / squashed brickwall mix."
89
+
90
+ report = f"""### ๐Ÿ“Š Forensic Lab Insights (First 60s)
91
+ * **Dynamic Crest Factor:** {crest_factor:.2f} $\\rightarrow$ *{dynamics_status}*
92
+ * **Total Vocal Artifact Onsets:** {len(peaks)} individual syllables mapped.
93
+ * **Peak Delivery Speed:** {max(density_y):.1f} syllables per second.
94
+ * **Acoustic Blueprint Profile:** {mix_critique}
95
+
96
+ > **How to interpret charts:** > * **Recurrence Map:** Look for solid diagonal block shapes. These explicitly flag identical choruses or looping sample patterns.
97
+ > * **Spectral Vectors:** Sharp dips or valleys reveal filtering tricks, transitions, or frequency drops.
98
+ > * **Delivery Velocity:** Waves illustrate the emotional phrasing of a performance, showing where the artist rushes or drags words."""
99
+
100
+ return fig_ssm, fig_mix, fig_vocal, report
101
+
102
+ # =====================================================================
103
+ # INTERFACE LAYOUT
104
+ # =====================================================================
105
+ with gr.Blocks(title="Audio Forensic Analytics Lab") as demo:
106
+ gr.Markdown("# ๐Ÿ”ฌ Audio Forensic & Structural Intelligence Lab")
107
+ gr.Markdown("Drop clean stems extracted from Space 1 to extract advanced frequency blueprints, structural maps, and vocal data matrices.")
108
+
109
+ with gr.Row():
110
+ vocal_input = gr.Audio(type="filepath", label="Upload Isolated Vocal Stem (vocals.wav)")
111
+ master_input = gr.Audio(type="filepath", label="Upload Instrumental or Full Mix Master")
112
+
113
+ analyze_btn = gr.Button("Deploy Forensic Diagnosis Engines", variant="primary")
114
+
115
+ with gr.Tab("1. Structural Recurrence Map"):
116
+ plot_ssm = gr.Plot()
117
+ with gr.Tab("2. Mix Health & Spectral Vectors"):
118
+ plot_mix = gr.Plot()
119
+ with gr.Tab("3. Lyrical Velocity Matrix"):
120
+ plot_vocal = gr.Plot()
121
+
122
+ text_report = gr.Markdown()
123
+
124
+ analyze_btn.click(
125
+ fn=run_forensic_analysis,
126
+ inputs=[vocal_input, master_input],
127
+ outputs=[plot_ssm, plot_mix, plot_vocal, text_report]
128
+ )
129
+
130
+ if __name__ == "__main__":
131
+ demo.launch()