Created
October 2, 2025 22:35
-
-
Save twobob/077531cecbb77aa44fe97cec23628f5d to your computer and use it in GitHub Desktop.
Revisions
-
twobob created this gist
Oct 2, 2025 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,203 @@ import numpy as np import matplotlib.pyplot as plt import matplotlib.cm as cm import wave import contextlib import cv2 import os import shutil from moviepy.editor import AudioFileClip, VideoFileClip # --- Configuration --- # Input WAV and output MP4 paths WAV_PATH = "garbage.wav" OUTPUT_MP4 = "garbage_VISUAL.mp4" # Visualization parameters FPS = 30 FIG_SIZE = (10, 10) DPI = 120 NUM_LOOPS = 4 # Number of concentric visualizer loops # Aesthetics BG_COLOR = '#0B0014' COLORMAP = cm.magma # Colormap for dynamic colors (e.g., magma, plasma, inferno) PARTICLE_COLOR = '#FFFFFF' TITLE_TEXT = 'GARBAGE' TITLE_COLOR = (1.0, 1.0, 1.0, 0.08) # --- Setup Directories --- FRAMES_DIR = "temp_visualization_frames" if os.path.exists(FRAMES_DIR): shutil.rmtree(FRAMES_DIR) os.makedirs(FRAMES_DIR, exist_ok=True) # --- Audio Processing --- try: with contextlib.closing(wave.open(WAV_PATH, 'r')) as wf: num_channels = wf.getnchannels() sampwidth = wf.getsampwidth() framerate = wf.getframerate() num_frames = wf.getnframes() audio_data = wf.readframes(num_frames) dtype_map = {1: np.int8, 2: np.int16, 4: np.int32} if sampwidth not in dtype_map: raise ValueError("Unsupported sample width") audio_np = np.frombuffer(audio_data, dtype=dtype_map[sampwidth]) if num_channels == 2: audio_np = audio_np.reshape(-1, 2).mean(axis=1) print("Audio file loaded successfully.") print(f"Duration: {num_frames / float(framerate):.2f}s, Framerate: {framerate}Hz") except FileNotFoundError: print(f"Error: The file '{WAV_PATH}' was not found.") exit() except Exception as e: print(f"An error occurred while reading the audio file: {e}") exit() # --- Visualization Frame Generation --- samples_per_frame = framerate // FPS num_frames_to_generate = int(num_frames / samples_per_frame) max_amplitude = np.max(np.abs(audio_np)) if len(audio_np) > 0 else 1.0 print(f"Generating {num_frames_to_generate} frames...") for i in range(num_frames_to_generate): start = i * samples_per_frame end = start + samples_per_frame frame_audio = audio_np[start:end] if frame_audio.size == 0: continue # --- Create the Radial Visualization --- fig = plt.figure(figsize=FIG_SIZE, facecolor=BG_COLOR) ax = plt.subplot(111, polar=True, facecolor=BG_COLOR) fig.text(0.5, 0.5, TITLE_TEXT, fontsize=120, color=TITLE_COLOR, ha='center', va='center', weight='bold') # Calculate RMS for intensity and get the dynamic color for this frame rms = np.sqrt(np.mean(np.square(frame_audio.astype(np.float64)))) normalized_rms = rms / max_amplitude if max_amplitude > 0 else 0 if not np.isfinite(normalized_rms): normalized_rms = 0 # The color is determined by the loudness of the frame dynamic_color = COLORMAP(normalized_rms) # A slightly brighter color for the main line glow_color = COLORMAP(min(normalized_rms * 1.2, 1.0)) num_samples = len(frame_audio) theta = np.linspace(0, 2 * np.pi, num_samples) # --- Add Particle Effects --- num_particles = int(150 * normalized_rms) particle_thetas = np.random.uniform(0, 2 * np.pi, num_particles) particle_radii = np.random.uniform(0, 1.5, num_particles) * (1 + normalized_rms) particle_sizes = (np.random.rand(num_particles) * 30) * (0.5 + normalized_rms) ax.scatter(particle_thetas, particle_radii, s=particle_sizes, color=PARTICLE_COLOR, alpha=0.4 * normalized_rms, zorder=2) # --- Plot Multiple Concentric Loops --- for j in range(NUM_LOOPS): loop_base_radius = 0.4 * (j + 1) # Modulate radius based on audio waveform radius_modulation = (np.abs(frame_audio) / max_amplitude) * 0.2 * (1 + normalized_rms) if max_amplitude > 0 else np.zeros_like(frame_audio) radii = loop_base_radius + radius_modulation # Ensure smooth wrap-around loop_theta = np.append(theta, theta[0]) loop_radii = np.append(radii, radii[0]) # Plot glow effect - increased alpha for more intensity ax.plot(loop_theta, loop_radii, color=glow_color, linewidth=5 + j*2, alpha=0.7 * (0.3 + normalized_rms), zorder=3) # Plot main line - increased linewidth and always visible ax.plot(loop_theta, loop_radii, color=dynamic_color, linewidth=2.5, alpha=0.9, zorder=4) # --- Final Touches on the Plot --- ax.set_ylim(0, 2.5) # Increased limit for multiple loops ax.grid(False) ax.set_xticks([]) ax.set_yticks([]) ax.spines['polar'].set_visible(False) plt.tight_layout() frame_path = os.path.join(FRAMES_DIR, f"frame_{i:05d}.png") plt.savefig(frame_path, dpi=DPI, facecolor=BG_COLOR) plt.close(fig) if (i + 1) % 10 == 0: print(f" ... {i+1}/{num_frames_to_generate} frames rendered") # --- Video Compilation --- print("\nAll frames generated. Compiling video...") first_frame_path = os.path.join(FRAMES_DIR, "frame_00000.png") if not os.path.exists(first_frame_path): print("Error: No frames were generated. Cannot create video.") exit() frame_example = cv2.imread(first_frame_path) h, w, _ = frame_example.shape temp_video_path = os.path.join(FRAMES_DIR, "visual.avi") # Use MJPEG codec which is more compatible fourcc = cv2.VideoWriter_fourcc(*'MJPG') video = cv2.VideoWriter(temp_video_path, fourcc, FPS, (w, h)) for i in range(num_frames_to_generate): frame_path = os.path.join(FRAMES_DIR, f"frame_{i:05d}.png") if os.path.exists(frame_path): frame = cv2.imread(frame_path) video.write(frame) video.release() # --- Combine Video and Audio using ffmpeg-python --- print("Combining video and audio...") try: import ffmpeg # Use ffmpeg-python to combine video and audio video_stream = ffmpeg.input(temp_video_path) audio_stream = ffmpeg.input(WAV_PATH) output = ffmpeg.output( video_stream, audio_stream, OUTPUT_MP4, vcodec='libx264', acodec='aac', shortest=None, **{'b:v': '5000k'} # Video bitrate for quality ) # Overwrite output file if it exists output = ffmpeg.overwrite_output(output) # Run the ffmpeg command ffmpeg.run(output, capture_stdout=True, capture_stderr=True) print(f"\nSuccessfully created video: {OUTPUT_MP4}") except ImportError: print("\nError: ffmpeg-python library not found.") print("Please install it with: pip install ffmpeg-python") print("You can find the silent video at:", temp_video_path) except Exception as e: print(f"\nAn error occurred during the final video compilation: {e}") import traceback traceback.print_exc() print("You can find the silent video at:", temp_video_path) finally: print("Cleaning up temporary files...") if os.path.exists(FRAMES_DIR): shutil.rmtree(FRAMES_DIR)