Ivan000's picture
Update app.py
228d08d verified
# app.py
# =============
# This is a complete app.py file for a Gradio application that allows users to upload an audio file and generate a video with frequency visualization.
import gradio as gr
import numpy as np
import librosa
import os
import cv2
import matplotlib.pyplot as plt
# Function to generate frequency visualization frames from audio
def generate_frequency_visualization(audio_path, fps, num_bars, sensitivity):
try:
# Load the audio file
y, sr = librosa.load(audio_path, sr=None)
duration = librosa.get_duration(y=y, sr=sr)
print(f"Loaded audio file with sampling rate: {sr}, and duration: {duration} seconds.")
if sr == 0 or len(y) == 0:
raise ValueError("Invalid audio file: sampling rate or audio data is zero.")
# Perform Short-Time Fourier Transform (STFT)
hop_length = int(sr / fps) # Hop length to match the desired fps
S = np.abs(librosa.stft(y, n_fft=2048, hop_length=hop_length))
S = S[:num_bars, :] # Limit the frequency bands to match the number of bars
# Normalize frequency power with sensitivity adjustment
S = (S / np.max(S)) * sensitivity
# Create a directory to save the frames
os.makedirs('frames', exist_ok=True)
# Generate and save each frame
for i in range(S.shape[1]):
# Create black background
img = np.zeros((720, 1280, 3), dtype=np.uint8)
# Get the bar heights for the current frame
heights = (S[:, i] * 600).astype(int)
# Calculate bar positions
bar_width = 80
spacing = (1280 - num_bars * bar_width) // (num_bars + 1)
for j, height in enumerate(heights):
x = spacing + j * (bar_width + spacing)
y = 720 - height
color = tuple(int(c * 255) for c in plt.cm.viridis(j / num_bars)[:3]) # Use Viridis colormap
cv2.rectangle(img, (x, 720), (x + bar_width, y), color, -1)
# Save the frame
frame_path = f'frames/frame_{i:04d}.png'
cv2.imwrite(frame_path, img)
print(f"Generated {S.shape[1]} frames for visualization.")
return 'frames', duration
except Exception as e:
print(f"Error generating frequency visualization: {e}")
return None, None
# Function to create a video from the generated frames
def create_video_from_frames(frames_directory, audio_path, fps):
try:
# Get the list of frame files
frame_files = [os.path.join(frames_directory, f) for f in os.listdir(frames_directory) if f.endswith('.png')]
frame_files.sort()
if not frame_files:
raise ValueError("No frames found to create the video.")
# Get video dimensions from the first frame
first_frame = cv2.imread(frame_files[0])
height, width, _ = first_frame.shape
# Initialize video writer
video_path = 'output_video.mp4'
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
video_writer = cv2.VideoWriter(video_path, fourcc, fps, (width, height))
# Write frames to video
for frame_file in frame_files:
frame = cv2.imread(frame_file)
video_writer.write(frame)
video_writer.release()
# Merge audio with video using ffmpeg
os.system(f"ffmpeg -i {video_path} -i {audio_path} -c:v copy -c:a aac -strict experimental output_with_audio.mp4 -y")
print(f"Video created with {len(frame_files)} frames.")
return 'output_with_audio.mp4'
except Exception as e:
print(f"Error creating video from frames: {e}")
return None
# Gradio interface function
def process_audio(audio, sensitivity):
audio_path = audio
fps = 60
num_bars = 12
frames_directory, duration = generate_frequency_visualization(audio_path, fps, num_bars, sensitivity)
if frames_directory:
video_path = create_video_from_frames(frames_directory, audio_path, fps)
return video_path
else:
return None
# Create the Gradio interface with explanations and recommendations
iface = gr.Interface(
fn=process_audio,
inputs=[
gr.Audio(type="filepath", label="Upload Audio File"),
gr.Slider(minimum=0.1, maximum=5.0, step=0.1, value=1.0, label="Sensitivity")
],
outputs=gr.Video(label="Generated Video"),
title="Audio Frequency Visualization",
description="Upload an audio file to generate a video with frequency visualization. "
"Supported file types: WAV, MP3, FLAC. "
"Recommended file duration: 10 seconds to 5 minutes. "
"The visualization will consist of 12 bars representing frequency ranges. Adjust sensitivity to control bar movement.",
)
# Launch the Gradio interface
if __name__ == "__main__":
iface.launch()
# Dependencies
# =============
# The following dependencies are required to run this app:
# - librosa
# - numpy
# - opencv-python
# - matplotlib
# - ffmpeg (installed separately)