omar1232 commited on
Commit
ca48bb6
·
verified ·
1 Parent(s): 73ee4a0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +113 -3
app.py CHANGED
@@ -42,9 +42,113 @@ def audio_visualizer(audio_file, audio_record):
42
  elif audio_record:
43
  vis_data, audio_output = process_audio(audio_record)
44
  else:
45
- return "Please upload an audio file or record audio.", None
46
 
47
- return vis_data, audio_output
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
  # Gradio interface
50
  with gr.Blocks() as demo:
@@ -59,14 +163,20 @@ with gr.Blocks() as demo:
59
  vis_output = gr.JSON(label="Visualization Data")
60
  audio_output = gr.Audio(label="Audio Playback", type="filepath")
61
 
 
 
 
62
  with gr.Row():
63
  submit = gr.Button("Visualize")
64
  clear = gr.Button("Clear")
65
 
 
 
 
66
  submit.click(
67
  fn=audio_visualizer,
68
  inputs=[audio_file, audio_record],
69
- outputs=[vis_output, audio_output]
70
  )
71
  clear.click(
72
  fn=lambda: (None, None),
 
42
  elif audio_record:
43
  vis_data, audio_output = process_audio(audio_record)
44
  else:
45
+ return "Please upload an audio file or record audio.", None, None
46
 
47
+ return vis_data, audio_output, vis_data
48
+
49
+ # Custom CSS and JavaScript for the visualizer
50
+ visualizer_html = """
51
+ <div class="visualizer-container" id="visualizer" style="position: relative; width: 100%; height: 500px; background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%); border-radius: 16px; overflow: hidden; box-shadow: 0 15px 40px rgba(0, 0, 0, 0.4);">
52
+ <div class="audio-wave" id="audioWave" style="position: absolute; bottom: 0; left: 0; width: 100%; height: 120px; background: linear-gradient(to top, rgba(0, 180, 219, 0.2), transparent);"></div>
53
+ <div class="loading-spinner" id="loadingSpinner" style="display: none; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); border: 4px solid rgba(255,255,255,0.3); border-top: 4px solid #00b4db; border-radius: 50%; width: 40px; height: 40px; animation: spin 1s linear infinite;"></div>
54
+ </div>
55
+
56
+ <style>
57
+ .visualizer-container { transition: background 0.5s; }
58
+ .bar {
59
+ position: absolute;
60
+ bottom: 0;
61
+ background: linear-gradient(to top, #00b4db, #0083b0);
62
+ border-radius: 6px 6px 0 0;
63
+ transition: height 0.1s cubic-bezier(0.4, 0, 0.2, 1);
64
+ }
65
+ @keyframes spin {
66
+ 0% { transform: translate(-50%, -50%) rotate(0deg); }
67
+ 100% { transform: translate(-50%, -50%) rotate(360deg); }
68
+ }
69
+ .bg-animated {
70
+ animation: gradient 15s ease infinite;
71
+ background-size: 400% 400%;
72
+ }
73
+ @keyframes gradient {
74
+ 0% { background-position: 0% 50%; }
75
+ 50% { background-position: 100% 50%; }
76
+ 100% { background-position: 0% 50%; }
77
+ }
78
+ </style>
79
+
80
+ <script>
81
+ document.addEventListener('DOMContentLoaded', () => {
82
+ const visualizer = document.getElementById('visualizer');
83
+ const audioWave = document.getElementById('audioWave');
84
+ let bars = [];
85
+ const barCount = 80;
86
+ const barSpacing = 2;
87
+
88
+ // Create bars
89
+ function createBars() {
90
+ visualizer.querySelectorAll('.bar').forEach(bar => bar.remove());
91
+ bars = [];
92
+ const containerWidth = visualizer.clientWidth;
93
+ const barWidth = (containerWidth / barCount) - barSpacing;
94
+ for (let i = 0; i < barCount; i++) {
95
+ const bar = document.createElement('div');
96
+ bar.className = 'bar';
97
+ bar.style.left = `${i * (barWidth + barSpacing)}px`;
98
+ bar.style.width = `${barWidth}px`;
99
+ bar.style.height = '0px';
100
+ visualizer.appendChild(bar);
101
+ bars.push(bar);
102
+ }
103
+ }
104
+
105
+ createBars();
106
+
107
+ // Function to update visualization
108
+ function updateVisualization(data) {
109
+ if (!data || !data.frequencies) return;
110
+ const { frequencies } = data;
111
+ const freqCount = Math.min(frequencies.length, barCount);
112
+ for (let i = 0; i < freqCount; i++) {
113
+ const height = (frequencies[i] / Math.max(...frequencies)) * visualizer.clientHeight * 0.8;
114
+ bars[i].style.height = `${height}px`;
115
+ }
116
+ const wavePoints = frequencies.map((f, i) => [
117
+ (i / frequencies.length) * visualizer.clientWidth,
118
+ visualizer.clientHeight * (1 - f / Math.max(...frequencies))
119
+ ]);
120
+ let wavePath = `path('M0 ${visualizer.clientHeight / 2} `;
121
+ wavePoints.forEach(([x, y]) => {
122
+ wavePath += `L${x} ${y} `;
123
+ });
124
+ wavePath += `L${visualizer.clientWidth} ${visualizer.clientHeight / 2} Z')`;
125
+ audioWave.style.clipPath = wavePath;
126
+ }
127
+
128
+ // Listen for updates from Gradio
129
+ window.addEventListener('message', (event) => {
130
+ if (event.data && event.data.vis_data) {
131
+ updateVisualization(event.data.vis_data);
132
+ }
133
+ });
134
+
135
+ window.addEventListener('resize', createBars);
136
+
137
+ // Poll the hidden JSON output for updates
138
+ setInterval(() => {
139
+ const visDataOutput = document.querySelector('#vis_data_output textarea');
140
+ if (visDataOutput && visDataOutput.value) {
141
+ try {
142
+ const data = JSON.parse(visDataOutput.value);
143
+ updateVisualization(data);
144
+ } catch (e) {
145
+ console.error('Error parsing visualization data:', e);
146
+ }
147
+ }
148
+ }, 500);
149
+ });
150
+ </script>
151
+ """
152
 
153
  # Gradio interface
154
  with gr.Blocks() as demo:
 
163
  vis_output = gr.JSON(label="Visualization Data")
164
  audio_output = gr.Audio(label="Audio Playback", type="filepath")
165
 
166
+ # Hidden output to pass data to JavaScript
167
+ vis_data_output = gr.JSON(elem_id="vis_data_output", visible=False)
168
+
169
  with gr.Row():
170
  submit = gr.Button("Visualize")
171
  clear = gr.Button("Clear")
172
 
173
+ # Visualizer section
174
+ gr.HTML(visualizer_html)
175
+
176
  submit.click(
177
  fn=audio_visualizer,
178
  inputs=[audio_file, audio_record],
179
+ outputs=[vis_output, audio_output, vis_data_output]
180
  )
181
  clear.click(
182
  fn=lambda: (None, None),