предложи идеи как улучшить: import numpy as np
import sounddevice as sd
from scipy import signal
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import tkinter as tk
from tkinter import ttk

class TomatisMethodController:
    def __init__(self, ax: plt.Axes, canvas: FigureCanvasTkAgg, root: tk.Tk):
        self.ax = ax
        self.canvas = canvas
        self.root = root
        self.is_playing = False

        self.base_freq = 440.0
        self.beat_freq = 15.0
        self.volume = 0.5

        self.filter_switch_rate = 0.5
        self.filter_timer = 0.0
        self.current_filter = 'lowpass'

        self.saturation_level = 0.5

        self.sample_rate = 44100
        self.buffer_size = 1024
        self.phase_left = 0.0
        self.phase_right = 0.0

        self.lowpass_b, self.lowpass_a = self.create_filter('lowpass')
        self.highpass_b, self.highpass_a = self.create_filter('highpass')
        self.filter_state_left = np.zeros(max(len(self.lowpass_b), len(self.lowpass_a)) - 1)
        self.filter_state_right = np.zeros(max(len(self.highpass_b), len(self.highpass_a)) - 1)

    def create_filter(self, filter_type):
        cutoff_freq = 1000
        nyquist = 0.5 * self.sample_rate
        normal_cutoff = cutoff_freq / nyquist
        if filter_type == 'lowpass':
            b, a = signal.butter(2, normal_cutoff, btype='low', analog=False)
        elif filter_type == 'highpass':
            b, a = signal.butter(2, normal_cutoff, btype='high', analog=False)
        return b, a

    def soft_clip(self, x):
        saturation = self.saturation_level
        return np.tanh(saturation * x)

    def generate_binaural_beats(self, num_frames):
        t = (np.arange(num_frames) + self.phase_left) / self.sample_rate
        left_tone = np.sin(2 * np.pi * self.base_freq * t)
        right_tone = np.sin(2 * np.pi * (self.base_freq + self.beat_freq) * t)

        self.phase_left += num_frames
        self.phase_right += num_frames

        self.phase_left %= self.sample_rate
        self.phase_right %= self.sample_rate

        output = np.column_stack((left_tone, right_tone))
        output_filtered = self.apply_dynamic_filter(output)
        output_saturated = self.soft_clip(output_filtered) * self.volume

        return output_saturated.astype(np.float32)

    def apply_dynamic_filter(self, signal_data):
        switch_interval = 1.0 / self.filter_switch_rate
        self.filter_timer += self.buffer_size / self.sample_rate

        if self.filter_timer >= switch_interval:
            self.filter_timer -= switch_interval
            self.current_filter = 'highpass' if self.current_filter == 'lowpass' else 'lowpass'

        b, a = (self.lowpass_b, self.lowpass_a) if self.current_filter == 'lowpass' else (self.highpass_b, self.highpass_a)
        left_filtered, self.filter_state_left = signal.lfilter(b, a, signal_data[:, 0], zi=self.filter_state_left)
        right_filtered, self.filter_state_right = signal.lfilter(b, a, signal_data[:, 1], zi=self.filter_state_right)

        return np.column_stack((left_filtered, right_filtered))

    def audio_callback(self, outdata, frames, time_info, status):
        data = self.generate_binaural_beats(frames)
        outdata[:] = data

    def start(self):
        if not self.is_playing:
            self.stream = sd.OutputStream(
                channels=2,
                callback=self.audio_callback,
                samplerate=self.sample_rate,
                blocksize=self.buffer_size,
                dtype='float32'
            )
            self.stream.start()
            self.is_playing = True
            self.update_plot()

    def stop(self):
        if self.is_playing and self.stream is not None:
            self.stream.stop()
            self.stream.close()
            self.stream = None
            self.is_playing = False
            self.ax.clear()
            self.canvas.draw()

    def update_settings(self):
        self.lowpass_b, self.lowpass_a = self.create_filter('lowpass')
        self.highpass_b, self.highpass_a = self.create_filter('highpass')
        if self.is_playing:
            self.update_plot()

    def update_plot(self):
        if self.is_playing:
            num_frames = self.buffer_size
            sound = self.generate_binaural_beats(num_frames)
            t = np.linspace(0, num_frames / self.sample_rate, num_frames)
            self.ax.clear()
            self.ax.plot(t, sound[:, 0], label='Left', color='blue')
            self.ax.plot(t, sound[:, 1], label='Right', color='red')
            self.ax.set_title('Tomatis Method with Binaural Beats')
            self.ax.set_xlabel('Time (s)')
            self.ax.set_ylabel('Amplitude')
            self.ax.legend()
            self.canvas.draw()
            self.root.after(100, self.update_plot)

class Application(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("Cognitive Enhancement Audio with Tomatis Method")
        self.geometry("800x700")

        fig, ax = plt.subplots(figsize=(8, 4))
        canvas = FigureCanvasTkAgg(fig, self)
        canvas_widget = canvas.get_tk_widget()
        canvas_widget.pack(fill=tk.BOTH, expand=True)

        self.controller = TomatisMethodController(ax, canvas, self)

        settings_frame = ttk.LabelFrame(self, text="Settings")
        settings_frame.pack(fill="x", expand=True)

        ttk.Label(settings_frame, text="Base Frequency (Hz):").grid(row=0, column=0, sticky='w')
        self.base_freq_slider = ttk.Scale(settings_frame, from_=100, to=1000, orient='horizontal', command=self.update_frequencies)
        self.base_freq_slider.set(self.controller.base_freq)
        self.base_freq_slider.grid(row=0, column=1, padx=5, pady=5, sticky='ew')

        ttk.Label(settings_frame, text="Beat Frequency (Hz):").grid(row=1, column=0, sticky='w')
        self.beat_freq_slider = ttk.Scale(settings_frame, from_=0.1, to=40.0, orient='horizontal', command=self.update_frequencies)
        self.beat_freq_slider.set(self.controller.beat_freq)
        self.beat_freq_slider.grid(row=1, column=1, padx=5, pady=5, sticky='ew')

        ttk.Label(settings_frame, text="Volume:").grid(row=2, column=0, sticky='w')
        self.volume_slider = ttk.Scale(settings_frame, from_=0, to=1, orient='horizontal', command=self.update_volume)
        self.volume_slider.set(self.controller.volume)
        self.volume_slider.grid(row=2, column=1, padx=5, pady=5, sticky='ew')

        ttk.Label(settings_frame, text="Filter Switch Rate (Hz):").grid(row=3, column=0, sticky='w')
        self.filter_switch_slider = ttk.Scale(settings_frame, from_=0.1, to=5.0, orient='horizontal', command=self.update_filter_switch_rate)
        self.filter_switch_slider.set(self.controller.filter_switch_rate)
        self.filter_switch_slider.grid(row=3, column=1, padx=5, pady=5, sticky='ew')

        ttk.Label(settings_frame, text="Saturation Level:").grid(row=4, column=0, sticky='w')
        self.saturation_slider = ttk.Scale(settings_frame, from_=0.0, to=1.0, orient='horizontal', command=self.update_saturation)
        self.saturation_slider.set(self.controller.saturation_level)
        self.saturation_slider.grid(row=4, column=1, padx=5, pady=5, sticky='ew')

        for i in range(2):
            settings_frame.columnconfigure(i, weight=1)

        presets_frame = ttk.LabelFrame(self, text="Presets")
        presets_frame.pack(fill="x", expand=True)

        ttk.Button(presets_frame, text="Attention (Beta)", command=self.set_beta_preset).grid(row=0, column=0, padx=5, pady=5)
        ttk.Button(presets_frame, text="Memory (Gamma)", command=self.set_gamma_preset).grid(row=0, column=1, padx=5, pady=5)
        ttk.Button(presets_frame, text="Relaxation (Alpha)", command=self.set_alpha_preset).grid(row=0, column=2, padx=5, pady=5)
        ttk.Button(presets_frame, text="Meditation (Theta)", command=self.set_theta_preset).grid(row=0, column=3, padx=5, pady=5)

        controls_frame = ttk.Frame(self)
        controls_frame.pack(fill="x", expand=True, pady=10)

        start_button = ttk.Button(controls_frame, text="Start", command=self.controller.start)
        start_button.pack(side=tk.LEFT, padx=5)

        stop_button = ttk.Button(controls_frame, text="Stop", command=self.controller.stop)
        stop_button.pack(side=tk.LEFT, padx=5)

    def update_frequencies(self, _):
        self.controller.base_freq = self.base_freq_slider.get()
        self.controller.beat_freq = self.beat_freq_slider.get()
        self.controller.update_settings()

    def update_volume(self, _):
        self.controller.volume = self.volume_slider.get()
        self.controller.update_settings()

    def update_filter_switch_rate(self, _):
        self.controller.filter_switch_rate = self.filter_switch_slider.get()
        self.controller.update_settings()

    def update_saturation(self, _):
        self.controller.saturation_level = self.saturation_slider.get()
        self.controller.update_settings()

    def set_beta_preset(self):
        self.beat_freq_slider.set(20.0)
        self.update_frequencies(None)

    def set_gamma_preset(self):
        self.beat_freq_slider.set(40.0)
        self.update_frequencies(None)

    def set_alpha_preset(self):
        self.beat_freq_slider.set(10.0)
        self.update_frequencies(None)

    def set_theta_preset(self):
        self.beat_freq_slider.set(5.0)
        self.update_frequencies(None)

if __name__ == "__main__":
    app = Application()
    app.mainloop()