Untitled
import tkinter as tk from tkinter import ttk import numpy as np import sounddevice as sd import threading class ToneGenerator: def __init__(self): self.sample_rate = 44100 self.frequency = 200 # Default frequency in Hz self.phase_shift = 0 # Phase shift in radians self.is_playing = False self.stream = None def generate_tone(self): def callback(outdata, frames, time, status): t = (np.arange(frames) + self.sample_rate * time.inputBufferAdcTime) / self.sample_rate tone = np.sin(2 * np.pi * self.frequency * t + self.phase_shift) outdata[:, 0] = tone with sd.OutputStream(callback=callback, samplerate=self.sample_rate, channels=1): while self.is_playing: sd.sleep(100) def start(self): if not self.is_playing: self.is_playing = True self.stream = threading.Thread(target=self.generate_tone) self.stream.start() def stop(self): if self.is_playing: self.is_playing = False if self.stream is not None: self.stream.join() self.stream = None def set_frequency(self, freq): self.frequency = freq def set_phase_shift(self, shift): self.phase_shift = shift def main(): generator = ToneGenerator() def start_stop_tone(): if generator.is_playing: generator.stop() start_button.config(text="Включить") else: generator.start() start_button.config(text="Выключить") def update_frequency(val): generator.set_frequency(float(val)) freq_label.config(text=f"Частота: {float(val):.1f} Hz") def update_phase(val): generator.set_phase_shift(float(val)) phase_label.config(text=f"Фаза: {float(val):.2f} радиан") def increment_frequency(): freq = frequency_slider.get() + 0.5 frequency_slider.set(freq) update_frequency(freq) def decrement_frequency(): freq = frequency_slider.get() - 0.5 frequency_slider.set(freq) update_frequency(freq) root = tk.Tk() root.title("Генератор звукового тона") frame = ttk.Frame(root, padding=10) frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) root.columnconfigure(0, weight=1) root.rowconfigure(0, weight=1) frame.columnconfigure(0, weight=1) start_button = ttk.Button(frame, text="Включить", command=start_stop_tone) start_button.grid(row=0, column=0, pady=10, sticky=(tk.W, tk.E)) freq_label = ttk.Label(frame, text=f"Частота: {generator.frequency} Hz") freq_label.grid(row=1, column=0, pady=10, sticky=(tk.W, tk.E)) frequency_slider = ttk.Scale(frame, from_=100, to=300, orient="horizontal", command=update_frequency) frequency_slider.set(generator.frequency) frequency_slider.grid(row=2, column=0, pady=10, sticky=(tk.W, tk.E)) freq_buttons = ttk.Frame(frame) freq_buttons.grid(row=3, column=0, pady=5, sticky=(tk.W, tk.E)) freq_buttons.columnconfigure(0, weight=1) freq_buttons.columnconfigure(1, weight=1) freq_down_button = ttk.Button(freq_buttons, text="-", command=decrement_frequency) freq_down_button.grid(row=0, column=0, padx=5, sticky=(tk.W, tk.E)) freq_up_button = ttk.Button(freq_buttons, text="+", command=increment_frequency) freq_up_button.grid(row=0, column=1, padx=5, sticky=(tk.W, tk.E)) phase_label = ttk.Label(frame, text=f"Фаза: {generator.phase_shift:.2f} радиан") phase_label.grid(row=4, column=0, pady=10, sticky=(tk.W, tk.E)) phase_slider = ttk.Scale(frame, from_=-np.pi, to=np.pi, orient="horizontal", command=update_phase) phase_slider.set(generator.phase_shift) phase_slider.grid(row=5, column=0, pady=10, sticky=(tk.W, tk.E)) def resize_ui(event): frame.config(padding=max(10, event.width // 50)) start_button.config(width=max(10, event.width // 20)) root.bind("<Configure>", resize_ui) root.mainloop() generator.stop() if __name__ == "__main__": main()
Leave a Comment