Ethereal Spectrum Analyzer Python GUI
👤 Sharing: AI
import tkinter as tk
from tkinter import ttk
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import sounddevice as sd
import threading
import time
class SpectrumAnalyzerApp:
def __init__(self, master):
self.master = master
master.title("Ethereal Spectrum Analyzer")
self.sample_rate = 44100 # Sample rate
self.fft_size = 2048 # FFT window size
self.running = False
# --- GUI Elements ---
self.start_button = ttk.Button(master, text="Start", command=self.start_analysis)
self.start_button.pack(pady=5)
self.stop_button = ttk.Button(master, text="Stop", command=self.stop_analysis, state=tk.DISABLED)
self.stop_button.pack(pady=5)
# Frame for the plot and info button
self.plot_frame = tk.Frame(master)
self.plot_frame.pack(fill=tk.BOTH, expand=True)
# Matplotlib plot setup
self.fig, self.ax = plt.subplots()
self.canvas = FigureCanvasTkAgg(self.fig, master=self.plot_frame)
self.canvas_widget = self.canvas.get_tk_widget()
self.canvas_widget.pack(fill=tk.BOTH, expand=True, side=tk.LEFT)
# Information Button setup
self.info_button = ttk.Button(self.plot_frame, text="Info", command=self.show_info)
self.info_button.pack(side=tk.RIGHT, padx=5)
# Status Label
self.status_label = tk.Label(master, text="Idle", bd=1, relief=tk.SUNKEN, anchor=tk.W)
self.status_label.pack(side=tk.BOTTOM, fill=tk.X)
self.stream = None # Audio stream object
self.audio_thread = None # Thread for audio analysis
def show_info(self):
info_window = tk.Toplevel(self.master)
info_window.title("About Ethereal Spectrum Analyzer")
info_text = tk.Text(info_window, wrap=tk.WORD)
info_text.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)
info_text.insert(tk.END, """
Ethereal Spectrum Analyzer is a real-time audio analysis tool that visualizes the frequency spectrum of sound.
Key Features:
- Real-time Spectrum Display: Shows the frequency components of the incoming audio.
- Adjustable Parameters: Sample rate and FFT size can be configured (currently fixed in code).
- User-Friendly Interface: Simple start and stop controls.
- Informational Details: Provides insights into audio characteristics.
How to Use:
1. Click 'Start' to begin audio analysis. Ensure your microphone is active.
2. Observe the spectrum display for real-time frequency information.
3. Click 'Stop' to halt the analysis.
Technical Details:
The program uses the sounddevice library for audio input, numpy for FFT calculations, and matplotlib for visualization.
Potential Applications:
- Audio engineering and music production.
- Real-time audio monitoring and analysis.
- Educational purposes for understanding frequency spectra.
Note: This is a basic version and can be extended with more features like frequency range selection, peak hold, etc.
""")
info_text.config(state=tk.DISABLED) # Make it read-only
def start_analysis(self):
self.running = True
self.start_button.config(state=tk.DISABLED)
self.stop_button.config(state=tk.NORMAL)
self.status_label.config(text="Analyzing...")
self.audio_thread = threading.Thread(target=self.audio_callback)
self.audio_thread.daemon = True # Daemonize the thread
self.audio_thread.start()
def stop_analysis(self):
self.running = False
self.start_button.config(state=tk.NORMAL)
self.stop_button.config(state=tk.DISABLED)
self.status_label.config(text="Stopping...")
time.sleep(0.1) # Give the thread some time to finish
self.status_label.config(text="Idle")
def audio_callback(self):
try:
with sd.InputStream(samplerate=self.sample_rate, channels=1, callback=self.process_audio):
while self.running:
time.sleep(0.1) # Check status periodically instead of busy-waiting
except Exception as e:
print(f"Error during audio capture: {e}")
self.status_label.config(text=f"Error: {e}")
self.stop_analysis()
def process_audio(self, indata, frames, time, status):
if status:
print(status)
if self.running:
# Apply a window function to reduce spectral leakage
window = np.hamming(self.fft_size)
data = indata[:, 0] * window
# Perform FFT
fft = np.fft.fft(data, n=self.fft_size)
fft = np.abs(fft[:self.fft_size // 2]) / self.fft_size #Normalize Amplitude
# Calculate frequency axis
freq = np.fft.fftfreq(self.fft_size, d=1/self.sample_rate)[:self.fft_size // 2]
self.update_plot(freq, fft)
def update_plot(self, freq, magnitude):
self.ax.clear()
self.ax.plot(freq, magnitude)
self.ax.set_xlabel("Frequency (Hz)")
self.ax.set_ylabel("Magnitude")
self.ax.set_title("Real-time Spectrum")
self.ax.set_xlim(0, self.sample_rate / 2) # Display up to Nyquist frequency
self.ax.grid(True)
self.canvas.draw()
root = tk.Tk()
app = SpectrumAnalyzerApp(root)
root.mainloop()
👁️ Viewed: 7
Comments