python: import pyaudio import numpy as np import serial import time from scipy.fft import fft # SYSTEM CONFIGURATION CHUNK = 1024 FORMAT = pyaudio.paInt16 CHANNELS = 1 RATE = 44100 SERIAL_PORT = "COM1" # CHANGE TO YOUR ARDUINO PORT! BAUD_RATE = 9600 # AUDIO CONFIGURATION - VB-Cable AUDIO_DEVICE_INDEX = 1 # CABLE Output - CHANGE TO CORRECT ONE! # 16 FREQUENCY BANDS (Hz) FREQ_BANDS = [ (20, 60), (60, 120), (120, 250), (250, 500), (500, 1000), (1000, 2000), (2000, 4000), (4000, 8000), (8000, 10000), (10000, 12000), (12000, 14000), (14000, 16000), (16000, 18000), (18000, 20000), (20000, 21000), (21000, 22050) ] class AudioEqualizer: def __init__(self): # Initialize PyAudio self.pa = pyaudio.PyAudio() self.stream = None self.serial_conn = None print("=== AUDIO EQUALIZER ===") print("System initialization...") # List audio devices self.list_audio_devices() # Setup audio self.setup_audio() # Setup Arduino self.setup_arduino() # Buffer for smoothing self.smooth_buffer = [[0] * 5 for _ in range(16)] self.buffer_index = 0 def list_audio_devices(self): """Show available audio devices""" print("\nAVAILABLE INPUT DEVICES:") for i in range(self.pa.get_device_count()): device_info = self.pa.get_device_info_by_index(i) if device_info["maxInputChannels"] > 0: name = device_info['name'] if 'cable' in name.lower() or 'vb-audio' in name.lower(): print(f" {i}: {name} ⭐ <- PROBABLY THIS ONE!") else: print(f" {i}: {name}") print(f"\nšŸŽÆ USING DEVICE: {AUDIO_DEVICE_INDEX}") print("āš ļø IF IT DOESN'T WORK - change AUDIO_DEVICE_INDEX!") print("-" * 50) def setup_audio(self): """Setup audio stream""" try: self.stream = self.pa.open( format=FORMAT, channels=CHANNELS, rate=RATE, input=True, input_device_index=AUDIO_DEVICE_INDEX, frames_per_buffer=CHUNK ) print("āœ… AUDIO: Connected successfully") except Exception as e: print(f"āŒ AUDIO ERROR: {e}") print("Check AUDIO_DEVICE_INDEX in code!") self.cleanup() exit(1) def setup_arduino(self): """Setup Arduino connection""" try: self.serial_conn = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1) time.sleep(2) # Arduino reset print(f"āœ… ARDUINO: Connected on {SERIAL_PORT}") except Exception as e: print(f"āŒ ARDUINO ERROR: {e}") print("Arduino will work in demo mode") self.serial_conn = None def analyze_audio(self): """Analyze audio into 16 frequency bands""" try: # Read audio data = self.stream.read(CHUNK, exception_on_overflow=False) audio_data = np.frombuffer(data, dtype=np.int16) # Check amplitude - silence filter max_amplitude = np.max(np.abs(audio_data)) if max_amplitude < 800: # Silence threshold return [0] * 16 # FFT fft_data = fft(audio_data) magnitude = np.abs(fft_data[:len(fft_data)//2]) freqs = np.fft.fftfreq(len(audio_data), 1/RATE)[:len(magnitude)] # Band analysis levels = [] for low_freq, high_freq in FREQ_BANDS: # Find indexes for band mask = (freqs >= low_freq) & (freqs <= high_freq) if np.any(mask): # Average energy in band energy = np.mean(magnitude[mask]) # Convert to level 0-7 if energy > 200: level = min(7, int(energy / 300)) else: level = 0 levels.append(level) else: levels.append(0) return levels except Exception as e: print(f"Audio analysis error: {e}") return [0] * 16 def smooth_levels(self, levels): """Smooth levels for fluid animation""" smoothed = [] for i, level in enumerate(levels): # Add to buffer self.smooth_buffer[i][self.buffer_index] = level # Calculate average of last 5 samples avg = sum(self.smooth_buffer[i]) // 5 smoothed.append(avg) self.buffer_index = (self.buffer_index + 1) % 5 return smoothed def send_to_arduino(self, levels): """Send levels to Arduino""" if self.serial_conn: try: # Format: "L:1,3,5,2,7,4,6,1,2,5,3,7,4,2,1,6\n" data_string = "L:" + ",".join(map(str, levels)) + "\n" self.serial_conn.write(data_string.encode()) # Debug output max_level = max(levels) if max_level > 0: bars = ''.join(['ā–ˆ' if l > 3 else 'ā–Œ' if l > 0 else ' ' for l in levels]) print(f"šŸŽµ [{bars}] Max: {max_level}") except Exception as e: print(f"Arduino error: {e}") else: # Without Arduino - only console visualization max_level = max(levels) if max_level > 0: bars = ''.join(['ā–ˆ' if l > 5 else 'ā–Œ' if l > 2 else '.' if l > 0 else ' ' for l in levels]) print(f"šŸŽµ [{bars}] Max: {max_level}") def run(self): """Main equalizer loop""" print("\nšŸš€ EQUALIZER STARTED!") print("šŸŽ§ Play music and see the magic!") print("Ctrl+C to stop\n") last_activity = time.time() try: while True: # Audio analysis levels = self.analyze_audio() # Smoothing smooth_levels = self.smooth_levels(levels) # Send to Arduino self.send_to_arduino(smooth_levels) # Check activity if max(levels) > 0: last_activity = time.time() elif time.time() - last_activity > 10: print("šŸ’¤ No audio for 10s - check settings") last_activity = time.time() time.sleep(0.05) # 20 FPS except KeyboardInterrupt: print("\nā¹ļø Equalizer stopped") finally: self.cleanup() def cleanup(self): """Close connections""" if self.stream: self.stream.stop_stream() self.stream.close() self.pa.terminate() if self.serial_conn: self.serial_conn.close() print("šŸ”§ Connections closed") if __name__ == "__main__": print("šŸŽ¼ === AUDIO EQUALIZER V2.0 ===") print() print("šŸ“‹ VB-AUDIO VIRTUAL CABLE CONFIGURATION:") print("1. ā¬‡ļø Download and install VB-Audio Virtual Cable") print("2. šŸ”Š Set 'CABLE Input' as default output device") print("3. šŸŽ§ In sound panel enable 'Listen to' for CABLE Output → Headphones") print("4. šŸŽµ Play music!") print() print("šŸ”— Download: https://vb-audio.com/Cable/") print() # IMPORTANT SETTINGS TO CHECK print("āš™ļø CHECK SETTINGS:") print(f" • SERIAL_PORT = {SERIAL_PORT}") print(f" • AUDIO_DEVICE_INDEX = {AUDIO_DEVICE_INDEX}") print(" • If equalizer does not react to music - change AUDIO_DEVICE_INDEX!") print() equalizer = AudioEqualizer() equalizer.run()