Ich habe durch debuggen einiges an chaos in diesen code der anwendung gebracht und alles unordentlich gemacht. Sorge dafür das an den wichtigen schlüssel punkten im skript debug prints exisiteren und entferne sie dort wo sie nicht benötigt werden. Ordne und strukturiere den code wieder vernünftig und korrigiere alle fehler die du findest. Die anwendung startet auch immer noch nich, die soudn device bibliothek scheint grundsetzlich probleme zu machen daher ist sie optional integriert. Trotzdem startet weiterhin das skript nicht wie man dem folgenden fehler log entnehmen kann. Behebe auch diese fehler und sorge dafür das die anwendung problemfrei ausführbar ist. nenne mir dann den vollständigen überarbeiteten code der anwendung.


(.venv) D:\_Projekte\_MyCodes\VoicePreprocessor>d:/_Projekte/_MyCodes/VoicePreprocessor/.venv/Scripts/python.exe d:/_Projekte/_MyCodes/VoicePreprocessor/voice_preprocessor.py
Debug: Starting imports
Debug: Python interpreter started
Debug: Starting scientific imports
Debug: numpy ok
Debug: librosa ok
Debug: soundfile ok
Debug: noisereduce ok
Debug: pyloudnorm ok
Debug: scipy ok
Debug: Starting Qt imports
Debug: QApplication ok
Debug: QtWidgets ok
Debug: QtCore ok
Debug: QtGui ok
Debug: Testing additional libraries
Debug: pyqtgraph ok
Debug: psutil ok
Debug: requests ok
Debug: Testing additional libraries
Debug: pyqtgraph ok
Debug: psutil ok
Debug: requests ok
Debug: All imports completed
Debug: Starting class definitions
Debug: After minimal ProcessingOptions
Debug: After complete ProcessingOptions comment
Debug: Starting class definitions
Debug: MainWindow defined
Debug: StyleSheet defined
Debug: DropArea defined
Debug: DetailedProgressBar defined
Debug: Reached program entry point
Debug: Program start
Starting application...
Initializing QApplication...
Setting up DPI scaling...
Critical error: AA_EnableHighDpiScaling
2024-10-30 00:10:28,724 - ERROR - Critical error during startup
Traceback (most recent call last):
  File "d:\_Projekte\_MyCodes\VoicePreprocessor\voice_preprocessor.py", line 1597, in main
    app.setAttribute(Qt.ApplicationAttribute.AA_EnableHighDpiScaling, True)
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.3568.0_x64__qbz5n2kfra8p0\lib\enum.py", line 429, in __getattr__
    raise AttributeError(name) from None
AttributeError: AA_EnableHighDpiScaling
Debug: Program end with code 1



# System Imports
import sys
sys.stderr.write("Debug: Starting imports\n")
sys.stderr.flush()


sys.stderr.write("Debug: Python interpreter started\n")
sys.stderr.flush()

import os
import queue
import time
import json
import shutil
import gc
import logging
from pathlib import Path
from dataclasses import dataclass
from typing import Dict, List, Tuple, Optional

# Wissenschaftliche Bibliotheken
sys.stderr.write("Debug: Starting scientific imports\n")
sys.stderr.flush()

import numpy as np
sys.stderr.write("Debug: numpy ok\n")
sys.stderr.flush()

import librosa
sys.stderr.write("Debug: librosa ok\n")
sys.stderr.flush()

import soundfile as sf
sys.stderr.write("Debug: soundfile ok\n")
sys.stderr.flush()

import noisereduce as nr
sys.stderr.write("Debug: noisereduce ok\n")
sys.stderr.flush()

import pyloudnorm as pyln
sys.stderr.write("Debug: pyloudnorm ok\n")
sys.stderr.flush()

from scipy.signal import butter, lfilter
sys.stderr.write("Debug: scipy ok\n")
sys.stderr.flush()

# Qt Imports
sys.stderr.write("Debug: Starting Qt imports\n")
sys.stderr.flush()

from PyQt6.QtWidgets import QApplication
sys.stderr.write("Debug: QApplication ok\n")
sys.stderr.flush()

from PyQt6.QtWidgets import (
    QMainWindow, QWidget,
    QVBoxLayout, QHBoxLayout, QGridLayout,
    QPushButton, QLabel, QFileDialog, QProgressBar, QComboBox,
    QCheckBox, QTextEdit, QGroupBox, QSizePolicy,
    QMenu, QMenuBar, QMessageBox, QSpinBox, QDoubleSpinBox,
    QListWidget, QListWidgetItem
)
sys.stderr.write("Debug: QtWidgets ok\n")
sys.stderr.flush()

from PyQt6.QtCore import (
    Qt, QThreadPool, QRunnable, pyqtSignal, pyqtSlot, QObject,
    QTimer, QPropertyAnimation, QRect, QSettings, QUrl
)
sys.stderr.write("Debug: QtCore ok\n")
sys.stderr.flush()

from PyQt6.QtGui import (
    QDragEnterEvent, QDropEvent, QIcon, QFont, 
    QDoubleValidator, QPalette, QAction, QDesktopServices
)
sys.stderr.write("Debug: QtGui ok\n")
sys.stderr.flush()

# Zusätzliche Bibliotheken Test
sys.stderr.write("Debug: Testing additional libraries\n")
sys.stderr.flush()

try:
    import pyqtgraph as pg
    sys.stderr.write("Debug: pyqtgraph ok\n")
except Exception as e:
    sys.stderr.write(f"Debug: pyqtgraph failed - {str(e)}\n")
sys.stderr.flush()

try:
    import psutil
    sys.stderr.write("Debug: psutil ok\n")
except Exception as e:
    sys.stderr.write(f"Debug: psutil failed - {str(e)}\n")
sys.stderr.flush()

try:
    import requests
    sys.stderr.write("Debug: requests ok\n")
except Exception as e:
    sys.stderr.write(f"Debug: requests failed - {str(e)}\n")
sys.stderr.flush()




# Zusätzliche Bibliotheken Test
sys.stderr.write("Debug: Testing additional libraries\n")
sys.stderr.flush()

try:
    import pyqtgraph as pg
    sys.stderr.write("Debug: pyqtgraph ok\n")
except Exception as e:
    sys.stderr.write(f"Debug: pyqtgraph failed - {str(e)}\n")
sys.stderr.flush()

try:
    import psutil
    sys.stderr.write("Debug: psutil ok\n")
except Exception as e:
    sys.stderr.write(f"Debug: psutil failed - {str(e)}\n")
sys.stderr.flush()

try:
    import requests
    sys.stderr.write("Debug: requests ok\n")
except Exception as e:
    sys.stderr.write(f"Debug: requests failed - {str(e)}\n")
sys.stderr.flush()

# HIER kommt die Meldung für alle Imports
sys.stderr.write("Debug: All imports completed\n")
sys.stderr.flush()

# Jetzt erst die Klassendefinitionen
sys.stderr.write("Debug: Starting class definitions\n")
sys.stderr.flush()

# Audio Preview Handling
PREVIEW_AVAILABLE = False  # Globale Variable für Preview-Status

def init_audio_preview():
    """Initialisiert Audio Preview wenn möglich"""
    global PREVIEW_AVAILABLE
    try:
        import sounddevice as sd
        PREVIEW_AVAILABLE = True
        sys.stderr.write("Debug: sounddevice ok\n")
        return sd
    except Exception as e:
        sys.stderr.write(f"Debug: sounddevice nicht verfügbar - {str(e)}\n")
        return None



# --- Logging Configuration ---
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('audio_processor.log'),
        logging.StreamHandler(sys.stdout)
    ]
)
logger = logging.getLogger(__name__)

# --- Constants ---
SAMPLE_RATES = [22050, 44100, 48000]
CHUNK_SIZE = 32768
MAX_FILE_SIZE = 500 * 1024 * 1024  # 500MB
SUPPORTED_FORMATS = {'.wav', '.mp3', '.ogg', '.flac', '.m4a'}  # Erweiterte Formate
LATEST_VERSION_URL = "https://example.com/latest_version.json"  # Platzhalter-URL für Auto-Updates


@dataclass
class ProcessingOptions:
    """Minimal version for testing"""
    sample_rate: int
    noise_reduce: bool
    noise_reduction: float
    normalize: bool
    normalize_db: float
    remove_silence: bool
    silence_threshold: float
    bandpass_filter: bool
    bandpass_low: float
    bandpass_high: float
    apply_fade: bool
    fade_length: float
    equalizer: bool
    eq_low_gain: float
    eq_mid_gain: float
    eq_high_gain: float
    reverb: bool
    reverb_decay: float
    chunk_size: int = CHUNK_SIZE

sys.stderr.write("Debug: After minimal ProcessingOptions\n")
sys.stderr.flush()



# --- Data Classes ---
# @dataclass
# class ProcessingOptions:
#     """
#     Data class for processing options with validation.
#     """
#     sample_rate: int
#     noise_reduce: bool
#     noise_reduction: float
#     normalize: bool
#     normalize_db: float
#     remove_silence: bool
#     silence_threshold: float
#     bandpass_filter: bool
#     bandpass_low: float
#     bandpass_high: float
#     apply_fade: bool
#     fade_length: float
#     equalizer: bool
#     eq_low_gain: float
#     eq_mid_gain: float
#     eq_high_gain: float
#     reverb: bool
#     reverb_decay: float
#     chunk_size: int = CHUNK_SIZE
#
#     def __post_init__(self):
#         """Validate options after initialization."""
#         if self.sample_rate not in SAMPLE_RATES:
#             raise ValueError(f"Invalid sample rate. Must be one of {SAMPLE_RATES}")
#         if not 0 <= self.noise_reduction <= 1:
#             raise ValueError("Noise reduction must be between 0 and 1")
#         if not -100 <= self.normalize_db <= 0:
#             raise ValueError("Normalize dB must be between -100 and 0")
#         if not 0 <= self.silence_threshold <= 1:
#             raise ValueError("Silence threshold must be between 0 and 1")
#         if self.bandpass_low < 0 or self.bandpass_high > 20000:
#             raise ValueError("Invalid bandpass filter frequencies")
#         if self.bandpass_low >= self.bandpass_high:
#             raise ValueError("Bandpass low frequency must be less than high frequency")
#         if not -24 <= self.eq_low_gain <= 24:
#             raise ValueError("Equalizer low gain must be between -24 and 24 dB")
#         if not -24 <= self.eq_mid_gain <= 24:
#             raise ValueError("Equalizer mid gain must be between -24 and 24 dB")
#         if not -24 <= self.eq_high_gain <= 24:
#             raise ValueError("Equalizer high gain must be between -24 and 24 dB")
#         if not 0.1 <= self.reverb_decay <= 10.0:
#             raise ValueError("Reverb decay must be between 0.1 and 10.0 seconds")

sys.stderr.write("Debug: After complete ProcessingOptions comment\n")
sys.stderr.flush()


# --- Error Classes ---
class AudioProcessingError(Exception):
    """Base class for audio processing errors."""
    pass

class AudioLoadError(AudioProcessingError):
    """Raised when there's an error loading an audio file."""
    pass

class AudioSaveError(AudioProcessingError):
    """Raised when there's an error saving an audio file."""
    pass

# --- Signals Class ---
class WorkerSignals(QObject):
    """
    Defines the signals available from a running worker thread.

    Supported signals are:
    - progress: int, str, str for progress percentage, message, and ETA.
    - result: np.ndarray, int for processed audio data and sample rate.
    - error: str for error messages.
    - finished: bool, str for success status and message.
    """
    progress = pyqtSignal(int, str, str)  # percent, message, eta
    result = pyqtSignal(np.ndarray, int)  # processed audio, sample rate
    error = pyqtSignal(str)
    finished = pyqtSignal(bool, str)  # success, message

# --- Audio Processing Worker ---
class AudioProcessingWorker(QRunnable):
    """
    Worker thread for processing a single audio file.

    Inherits from QRunnable to handle worker thread setup, signals, and wrap-up.
    """
    def __init__(self, input_path: str, output_path: str, options: ProcessingOptions):
        super().__init__()
        self.input_path = input_path
        self.output_path = output_path
        self.options = options
        self.signals = WorkerSignals()

    @pyqtSlot()
    def run(self):
        """Execute the audio processing."""
        try:
            logger.debug(f"Started processing {self.input_path}")
            # Resource check
            resource_monitor = ResourceMonitor()
            resources_ok, msg = resource_monitor.check_resources()
            if not resources_ok:
                raise AudioProcessingError(msg)

            # Load audio
            y, sr = self._load_audio(self.input_path)

            # Resample if needed
            if sr != self.options.sample_rate:
                y = librosa.resample(y, orig_sr=sr, target_sr=self.options.sample_rate)
                sr = self.options.sample_rate
                logger.debug(f"Resampled {self.input_path} to {sr} Hz")

            # Apply processing steps
            y = self._apply_processing_chain(y, sr)

            # Save processed audio
            self._save_audio(y, sr, self.output_path)
            logger.debug(f"Finished processing {self.input_path}, saved to {self.output_path}")

            # Emit result for visualization
            self.signals.result.emit(y, sr)

            self.signals.progress.emit(100, "Processing Complete", "0:00")
            self.signals.finished.emit(True, "Processing completed successfully.")

        except AudioProcessingError as e:
            logger.error(f"Processing error: {str(e)}")
            self.signals.error.emit(str(e))
            self.signals.finished.emit(False, f"Processing failed: {str(e)}")

        except Exception as e:
            logger.exception("Unexpected error during processing")
            self.signals.error.emit(f"Unexpected error: {str(e)}")
            self.signals.finished.emit(False, f"Processing failed: {str(e)}")

        finally:
            del y
            gc.collect()

    def _load_audio(self, path: str) -> Tuple[np.ndarray, int]:
        """Loads an audio file and ensures it is mono."""
        try:
            y, sr = sf.read(path)
            # Ensure mono
            if y.ndim > 1:
                y = librosa.to_mono(y.T)
            return y, sr
        except Exception as e:
            raise AudioLoadError(f"Error loading {path}: {str(e)}")

    def _apply_processing_chain(self, y: np.ndarray, sr: int) -> np.ndarray:
        """Applies the selected audio processing steps."""
        steps = []
        if self.options.noise_reduce:
            y = self._apply_noise_reduction(y, sr)
            steps.append("Noise Reduction")
        if self.options.equalizer:
            y = self._apply_equalizer(y, sr)
            steps.append("Equalizer")
        if self.options.reverb:
            y = self._apply_reverb(y, sr)
            steps.append("Reverb")
        if self.options.normalize:
            y = self._normalize_audio(y, sr)
            steps.append("Normalization")
        if self.options.remove_silence:
            y = self._remove_silence(y, sr)
            steps.append("Silence Removal")
        if self.options.bandpass_filter:
            y = self._apply_bandpass_filter(y, sr)
            steps.append("Bandpass Filtering")
        if self.options.apply_fade:
            y = self._apply_fade_in_out(y, sr)
            steps.append("Fade In/Out")
        logger.debug(f"Applied steps: {', '.join(steps) if steps else 'None'}")
        return y

    def _apply_noise_reduction(self, y: np.ndarray, sr: int) -> np.ndarray:
        """Applies noise reduction to the audio data."""
        try:
            # Estimate noise from the first 0.5 seconds
            noise_clip = y[:int(0.5 * sr)]
            reduced_noise = nr.reduce_noise(
                y=y,
                sr=sr,
                y_noise=noise_clip,
                prop_decrease=self.options.noise_reduction,
                stationary=True
            )
            logger.debug("Noise reduction applied")
            return reduced_noise
        except Exception as e:
            raise AudioProcessingError(f"Noise reduction failed: {str(e)}")

    def _apply_equalizer(self, y: np.ndarray, sr: int) -> np.ndarray:
        """Applies a simple equalizer to the audio data."""
        try:
            # Simple three-band equalizer: low, mid, high
            # Design filters for each band
            def band_gain(y, sr, low_freq, high_freq, gain_db):
                nyquist = sr / 2
                low = low_freq / nyquist
                high = high_freq / nyquist
                b, a = butter(2, [low, high], btype='band')
                filtered = lfilter(b, a, y)
                gain = 10 ** (gain_db / 20)
                return filtered * gain

            y_low = band_gain(y, sr, 20, 250, self.options.eq_low_gain)
            y_mid = band_gain(y, sr, 250, 4000, self.options.eq_mid_gain)
            y_high = band_gain(y, sr, 4000, 20000, self.options.eq_high_gain)
            y_eq = y_low + y_mid + y_high
            # Normalize to prevent clipping
            y_eq = y_eq / np.max(np.abs(y_eq)) * np.max(np.abs(y))
            logger.debug("Equalizer applied")
            return y_eq
        except Exception as e:
            raise AudioProcessingError(f"Equalizer failed: {str(e)}")

    def _apply_reverb(self, y: np.ndarray, sr: int) -> np.ndarray:
        """Applies a simple reverb effect to the audio data."""
        try:
            reverb_decay = self.options.reverb_decay
            # Simple reverb using convolution with an impulse response
            ir_length = int(sr * reverb_decay)
            impulse_response = np.random.randn(ir_length) * np.exp(-np.linspace(0, reverb_decay, ir_length))
            y_reverb = np.convolve(y, impulse_response, mode='full')[:len(y)]
            # Normalize
            y_reverb = y_reverb / np.max(np.abs(y_reverb)) * np.max(np.abs(y))
            logger.debug("Reverb applied")
            return y_reverb
        except Exception as e:
            raise AudioProcessingError(f"Reverb failed: {str(e)}")

    def _normalize_audio(self, y: np.ndarray, sr: int) -> np.ndarray:
        """Normalizes audio to the target dB level."""
        try:
            meter = pyln.Meter(sr)
            loudness = meter.integrated_loudness(y)
            normalized_audio = pyln.normalize.loudness(y, loudness, self.options.normalize_db)
            logger.debug("Audio normalization applied")
            return normalized_audio
        except Exception as e:
            raise AudioProcessingError(f"Normalization failed: {str(e)}")

    def _remove_silence(self, y: np.ndarray, sr: int) -> np.ndarray:
        """Removes silence from the audio based on the silence threshold."""
        try:
            intervals = librosa.effects.split(
                y,
                top_db=self.options.silence_threshold * 60,
                frame_length=2048,
                hop_length=512
            )
            if intervals.size > 0:
                y_trimmed = np.concatenate([y[start:end] for start, end in intervals])
                logger.debug("Silence removal applied")
                return y_trimmed
            else:
                logger.debug("No silence detected to remove")
                return y
        except Exception as e:
            raise AudioProcessingError(f"Silence removal failed: {str(e)}")

    def _apply_bandpass_filter(self, y: np.ndarray, sr: int) -> np.ndarray:
        """Applies a bandpass filter to the audio."""
        try:
            nyquist = sr / 2
            low = self.options.bandpass_low / nyquist
            high = self.options.bandpass_high / nyquist
            b, a = butter(4, [low, high], btype='band')
            filtered_audio = lfilter(b, a, y)
            logger.debug("Bandpass filter applied")
            return filtered_audio
        except Exception as e:
            raise AudioProcessingError(f"Bandpass filter failed: {str(e)}")

    def _apply_fade_in_out(self, y: np.ndarray, sr: int) -> np.ndarray:
        """Applies fade in and fade out to the audio."""
        try:
            fade_length = int(self.options.fade_length * sr)
            if fade_length <= 0:
                logger.debug("Fade length is zero or negative; skipping fade.")
                return y
            fade_in = np.linspace(0, 1, fade_length)
            fade_out = np.linspace(1, 0, fade_length)
            y[:fade_length] *= fade_in
            y[-fade_length:] *= fade_out
            logger.debug("Fade in/out applied")
            return y
        except Exception as e:
            raise AudioProcessingError(f"Fade in/out failed: {str(e)}")

    def _save_audio(self, y: np.ndarray, sr: int, output_path: str):
        """Saves the processed audio to the specified path."""
        try:
            sf.write(output_path, y, sr, subtype='PCM_24', format='WAV')
            logger.debug(f"Audio saved to {output_path}")
        except Exception as e:
            raise AudioSaveError(f"Error saving audio: {str(e)}")


# --- Resource Monitor ---
class ResourceMonitor:
    """
    Monitors system resources and provides status.

    Attributes:
        warning_threshold (int): CPU and memory usage percentage for warnings.
        critical_threshold (int): CPU and memory usage percentage for critical alerts.
    """
    def __init__(self):
        self.warning_threshold = 85  # CPU and memory usage percentage
        self.critical_threshold = 95  # CPU and memory usage percentage

    def get_system_status(self) -> Dict[str, float]:
        """
        Retrieve system resource usage.

        Returns:
            Dict[str, float]: Current usage percentages for CPU, memory, and disk.
        """
        cpu_percent = psutil.cpu_percent(interval=0.1)
        memory = psutil.virtual_memory()
        disk = psutil.disk_usage('/')
        
        return {
            'cpu_percent': cpu_percent,
            'memory_percent': memory.percent,
            'disk_percent': disk.percent
        }

    def check_resources(self) -> Tuple[bool, str]:
        """
        Checks if system resources are within acceptable limits.

        Returns:
            Tuple[bool, str]: Status and message indicating resource health.
        """
        status = self.get_system_status()
        if status['cpu_percent'] > self.critical_threshold or status['memory_percent'] > self.critical_threshold:
            return False, "System resources critically low"
        elif status['cpu_percent'] > self.warning_threshold or status['memory_percent'] > self.warning_threshold:
            return False, "System resources running high"
        return True, "Resources OK"


# --- Audio Validator ---
class AudioValidator:
    """
    Validates audio files based on size and format.
    """
    @staticmethod
    def validate_audio(file_path: str) -> Tuple[bool, str]:
        """
        Validate the audio file.

        Args:
            file_path (str): Path to the audio file.

        Returns:
            Tuple[bool, str]: (is_valid, message)
        """
        if not os.path.isfile(file_path):
            return False, "File does not exist."
        _, ext = os.path.splitext(file_path)
        if ext.lower() not in SUPPORTED_FORMATS:
            return False, f"Unsupported file format: {ext}"
        if os.path.getsize(file_path) > MAX_FILE_SIZE:
            return False, f"File exceeds maximum size of {MAX_FILE_SIZE / (1024*1024)} MB."
        return True, "Valid file."


# --- Signals Class Continued ---
class ProgressSignals(QObject):
    """
    Signals for updating per-file progress.

    Supported signals:
    - progress: int for percentage.
    - message: str for current status.
    """
    progress = pyqtSignal(int)
    message = pyqtSignal(str)

# --- Per-File Progress Bar Widget ---
class FileProgressWidget(QWidget):
    """
    Widget to display progress for a single file.
    """
    def __init__(self, file_name: str):
        super().__init__()
        layout = QHBoxLayout()
        self.label = QLabel(file_name)
        self.progress_bar = QProgressBar()
        self.progress_bar.setValue(0)
        layout.addWidget(self.label)
        layout.addWidget(self.progress_bar)
        self.setLayout(layout)

    def update_progress(self, value: int):
        self.progress_bar.setValue(value)

    def set_message(self, message: str):
        self.label.setText(f"{self.label.text()} - {message}")

# --- Main Application Window ---
class MainWindow(QMainWindow):
    """
    Main application window for the Advanced Audio Processor.

    This class handles the user interface and coordinates the audio processing tasks.
    It provides options for various audio processing techniques and displays progress, logs, and visualizations.
    """
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Advanced Audio Processor")
        self.setMinimumSize(1400, 1000)  # Increased size for additional UI elements
        self.setStyleSheet(StyleSheet.MAIN)
        self.setWindowIcon(QIcon.fromTheme("audio-x-generic"))  # Fallback icon

        # Initialize settings
        self.settings = QSettings("AudioProcessor", "Settings")

        # Initialize UI components
        self.init_ui()
        self.load_settings()

        # Initialize Thread Pool
        self.threadpool = QThreadPool()
        logger.debug(f"Multithreading with maximum {self.threadpool.maxThreadCount()} threads.")

        # Data for preview
        self.current_processed_audio = None
        self.current_sample_rate = None

        # Initialize processing queue
        self.processing_queue = queue.Queue()

    def init_ui(self):
        """Initialize the user interface."""
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QVBoxLayout(central_widget)

        self.status_label = QLabel("Ready")
        main_layout.addWidget(self.status_label)

        # Menu Bar for Settings Export/Import and About
        self.init_menu_bar()

        # Drop area
        self.drop_area = DropArea()
        self.drop_area.files_dropped.connect(self.handle_dropped_files)
        main_layout.addWidget(self.drop_area)

        # Visualizations
        self.init_visualizations(main_layout)

        # Processing settings
        self.init_processing_settings(main_layout)

        # Thread pool settings
        self.init_thread_pool_settings(main_layout)

        # Progress section with per-file progress
        self.init_progress_section(main_layout)

        # Buttons
        self.init_buttons(main_layout)

        # Console
        self.init_console(main_layout)

    def init_menu_bar(self):
        """Initialize the menu bar with export/import settings and About."""
        menu_bar = self.menuBar()
        file_menu = menu_bar.addMenu("File")
        
        import_settings_action = QAction("Import Settings", self)
        import_settings_action.triggered.connect(self.import_settings)
        file_menu.addAction(import_settings_action)
        
        export_settings_action = QAction("Export Settings", self)
        export_settings_action.triggered.connect(self.export_settings)
        file_menu.addAction(export_settings_action)
        
        exit_action = QAction("Exit", self)
        exit_action.triggered.connect(self.close)
        file_menu.addAction(exit_action)

        help_menu = menu_bar.addMenu("Help")
        about_action = QAction("About", self)
        about_action.triggered.connect(self.show_about)
        help_menu.addAction(about_action)

    def init_visualizations(self, parent_layout):
        """Initialize the visualizations for Waveform and Spectrogram."""
        visualization_group = QGroupBox("Audio Visualizations")
        visualization_layout = QHBoxLayout()
        visualization_group.setLayout(visualization_layout)

        # Waveform
        self.waveform_plot = pg.PlotWidget(title="Waveform")
        self.waveform_plot.setYRange(-1, 1)
        self.waveform_curve = self.waveform_plot.plot(pen=pg.mkPen('c', width=1))
        self.waveform_plot.setLabel('left', 'Amplitude')
        self.waveform_plot.setLabel('bottom', 'Time', units='s')
        visualization_layout.addWidget(self.waveform_plot)

        # Spektrogramm
        self.spectrogram_plot = pg.PlotWidget(title="Spectrogram")
        self.spectrogram_plot.setLogMode(False, False)
        self.spectrogram_plot.setLabel('left', 'Frequency', units='Hz')
        self.spectrogram_plot.setLabel('bottom', 'Time', units='s')
        self.img = pg.ImageItem()
        self.spectrogram_plot.addItem(self.img)
        visualization_layout.addWidget(self.spectrogram_plot)

        parent_layout.addWidget(visualization_group)

    def init_processing_settings(self, parent_layout):
        """Initialize the processing settings group."""
        settings_group = QGroupBox("Processing Settings")
        settings_layout = QGridLayout()
        settings_group.setLayout(settings_layout)

        # Sample rate selection
        self.sample_rate_combo = QComboBox()
        self.sample_rate_combo.addItems([str(sr) for sr in SAMPLE_RATES])
        self.sample_rate_combo.setToolTip("Select the sample rate for audio processing")
        settings_layout.addWidget(QLabel("Sample Rate (Hz):"), 0, 0)
        settings_layout.addWidget(self.sample_rate_combo, 0, 1)

        # Noise reduction
        self.noise_reduce_check = QCheckBox("Noise Reduction")
        self.noise_reduce_check.setToolTip("Enable noise reduction processing")
        self.noise_reduction_spin = QDoubleSpinBox()
        self.noise_reduction_spin.setRange(0, 1)
        self.noise_reduction_spin.setSingleStep(0.1)
        self.noise_reduction_spin.setValue(0.5)
        self.noise_reduction_spin.setToolTip("Set the strength of noise reduction (0-1)")
        settings_layout.addWidget(self.noise_reduce_check, 1, 0)
        settings_layout.addWidget(self.noise_reduction_spin, 1, 1)

        # Equalizer
        self.equalizer_check = QCheckBox("Enable Equalizer")
        self.equalizer_check.setToolTip("Enable equalizer adjustments")
        settings_layout.addWidget(self.equalizer_check, 2, 0)

        self.eq_low_spin = QDoubleSpinBox()
        self.eq_low_spin.setRange(-24, 24)
        self.eq_low_spin.setValue(0)
        self.eq_low_spin.setSingleStep(1)
        self.eq_low_spin.setToolTip("Low frequency gain (dB)")
        settings_layout.addWidget(QLabel("EQ Low Gain (dB):"), 3, 0)
        settings_layout.addWidget(self.eq_low_spin, 3, 1)

        self.eq_mid_spin = QDoubleSpinBox()
        self.eq_mid_spin.setRange(-24, 24)
        self.eq_mid_spin.setValue(0)
        self.eq_mid_spin.setSingleStep(1)
        self.eq_mid_spin.setToolTip("Mid frequency gain (dB)")
        settings_layout.addWidget(QLabel("EQ Mid Gain (dB):"), 4, 0)
        settings_layout.addWidget(self.eq_mid_spin, 4, 1)

        self.eq_high_spin = QDoubleSpinBox()
        self.eq_high_spin.setRange(-24, 24)
        self.eq_high_spin.setValue(0)
        self.eq_high_spin.setSingleStep(1)
        self.eq_high_spin.setToolTip("High frequency gain (dB)")
        settings_layout.addWidget(QLabel("EQ High Gain (dB):"), 5, 0)
        settings_layout.addWidget(self.eq_high_spin, 5, 1)

        # Reverb
        self.reverb_check = QCheckBox("Enable Reverb")
        self.reverb_check.setToolTip("Enable reverb effect")
        self.reverb_decay_spin = QDoubleSpinBox()
        self.reverb_decay_spin.setRange(0.1, 10.0)
        self.reverb_decay_spin.setValue(1.0)
        self.reverb_decay_spin.setSingleStep(0.1)
        self.reverb_decay_spin.setToolTip("Set reverb decay time (seconds)")
        settings_layout.addWidget(self.reverb_check, 6, 0)
        settings_layout.addWidget(self.reverb_decay_spin, 6, 1)

        # Normalization
        self.normalize_check = QCheckBox("Normalize Audio")
        self.normalize_check.setToolTip("Enable audio normalization")
        self.normalize_spin = QDoubleSpinBox()
        self.normalize_spin.setRange(-100, 0)
        self.normalize_spin.setValue(-14)
        self.normalize_spin.setToolTip("Set the target dB level for normalization")
        settings_layout.addWidget(self.normalize_check, 7, 0)
        settings_layout.addWidget(self.normalize_spin, 7, 1)

        # Silence removal
        self.silence_check = QCheckBox("Remove Silence")
        self.silence_check.setToolTip("Enable silence removal")
        self.silence_threshold_spin = QDoubleSpinBox()
        self.silence_threshold_spin.setRange(0, 1)
        self.silence_threshold_spin.setSingleStep(0.1)
        self.silence_threshold_spin.setValue(0.3)
        self.silence_threshold_spin.setToolTip("Set the silence threshold (0-1)")
        settings_layout.addWidget(self.silence_check, 8, 0)
        settings_layout.addWidget(self.silence_threshold_spin, 8, 1)

        # Bandpass filter
        self.bandpass_check = QCheckBox("Bandpass Filter")
        self.bandpass_check.setToolTip("Enable bandpass filter")
        bandpass_layout = QHBoxLayout()
        self.bandpass_low_spin = QSpinBox()
        self.bandpass_low_spin.setRange(20, 20000)
        self.bandpass_low_spin.setValue(50)
        self.bandpass_low_spin.setToolTip("Set the low frequency for bandpass filter")
        self.bandpass_high_spin = QSpinBox()
        self.bandpass_high_spin.setRange(20, 20000)
        self.bandpass_high_spin.setValue(15000)
        self.bandpass_high_spin.setToolTip("Set the high frequency for bandpass filter")
        bandpass_layout.addWidget(QLabel("Low (Hz):"))
        bandpass_layout.addWidget(self.bandpass_low_spin)
        bandpass_layout.addWidget(QLabel(" - High (Hz):"))
        bandpass_layout.addWidget(self.bandpass_high_spin)
        settings_layout.addWidget(self.bandpass_check, 9, 0)
        settings_layout.addLayout(bandpass_layout, 9, 1)

        # Fade In/Out
        self.fade_check = QCheckBox("Apply Fade In/Out")
        self.fade_check.setToolTip("Enable fade in and fade out")
        self.fade_length_spin = QDoubleSpinBox()
        self.fade_length_spin.setRange(0, 5)
        self.fade_length_spin.setSingleStep(0.01)
        self.fade_length_spin.setValue(0.01)
        self.fade_length_spin.setToolTip("Set the fade length in seconds")
        settings_layout.addWidget(self.fade_check, 10, 0)
        settings_layout.addWidget(self.fade_length_spin, 10, 1)

        parent_layout.addWidget(settings_group)

    def init_thread_pool_settings(self, parent_layout):
        """Initialize thread pool settings."""
        thread_group = QGroupBox("Thread Pool Settings")
        thread_layout = QHBoxLayout()
        thread_group.setLayout(thread_layout)

        self.max_threads_spin = QSpinBox()
        self.max_threads_spin.setRange(1, psutil.cpu_count(logical=True) or 4)
        self.max_threads_spin.setValue(self.threadpool.maxThreadCount())
        self.max_threads_spin.setToolTip("Set the maximum number of threads for processing")
        thread_layout.addWidget(QLabel("Max Threads:"))
        thread_layout.addWidget(self.max_threads_spin)

        set_threads_button = QPushButton("Set Threads")
        set_threads_button.clicked.connect(self.set_max_threads)
        set_threads_button.setToolTip("Apply the maximum number of threads")
        thread_layout.addWidget(set_threads_button)

        parent_layout.addWidget(thread_group)

    def init_progress_section(self, parent_layout):
        """Initialize the progress section with per-file progress."""
        progress_group = QGroupBox("Processing Progress")
        progress_layout = QVBoxLayout()
        progress_group.setLayout(progress_layout)

        # Overall progress bar
        self.overall_progress_bar = DetailedProgressBar()
        self.overall_progress_bar.setMaximum(100)
        self.overall_progress_bar.setValue(0)
        self.overall_progress_bar.setToolTip("Overall processing progress")

        # Per-file progress list
        self.per_file_progress = QListWidget()
        self.per_file_widgets = {}  # Map file path to widget

        progress_layout.addWidget(self.overall_progress_bar)
        progress_layout.addWidget(self.per_file_progress)

        parent_layout.addWidget(progress_group)

    def init_buttons(self, parent_layout):
        """Initialize the buttons for processing, preview, and settings export/import."""
        button_layout = QHBoxLayout()

        self.process_button = QPushButton("Process Files")
        self.process_button.clicked.connect(self.start_processing)
        self.process_button.setToolTip("Start processing the selected audio files")

        self.cancel_button = QPushButton("Cancel")
        self.cancel_button.clicked.connect(self.cancel_processing)
        self.cancel_button.setEnabled(False)
        self.cancel_button.setToolTip("Cancel the ongoing processing")

        self.preview_button = QPushButton("Preview Audio")
        self.preview_button.clicked.connect(self.preview_audio)
        self.preview_button.setEnabled(False)
        self.preview_button.setToolTip("Play the most recently processed audio file")

        self.export_settings_button = QPushButton("Export Settings")
        self.export_settings_button.clicked.connect(self.export_settings)
        self.export_settings_button.setToolTip("Export current processing settings to a JSON file")

        self.import_settings_button = QPushButton("Import Settings")
        self.import_settings_button.clicked.connect(self.import_settings)
        self.import_settings_button.setToolTip("Import processing settings from a JSON file")

        button_layout.addWidget(self.process_button)
        button_layout.addWidget(self.cancel_button)
        button_layout.addWidget(self.preview_button)
        button_layout.addWidget(self.export_settings_button)
        button_layout.addWidget(self.import_settings_button)

        parent_layout.addLayout(button_layout)

    def init_console(self, parent_layout):
        """Initialize the console for logs and error messages."""
        self.console = QTextEdit()
        self.console.setReadOnly(True)
        self.console.setMaximumHeight(200)  # Increased height for better visibility
        self.console.setStyleSheet("""
            QTextEdit {
                background-color: #2c3e50;
                color: #ecf0f1;
                font-family: Consolas;
                font-size: 10px;
                border: none;
            }
        """)

        # Animation for opening/closing
        self.console_animation = QPropertyAnimation(self.console, b"maximumHeight")
        self.console_animation.setDuration(300)

        # Toggle button
        self.toggle_console_button = QPushButton("\u21e9")  # Down arrow
        self.toggle_console_button.setFixedSize(20, 20)
        self.toggle_console_button.setStyleSheet("""
            QPushButton {
                background-color: #34495e;
                color: white;
                border: none;
            }
            QPushButton:hover {
                background-color: #3c5973;
            }
        """)
        self.toggle_console_button.setToolTip("Toggle console visibility")
        self.toggle_console_button.clicked.connect(self.toggle_console)

        # Layout for console and button
        console_layout = QHBoxLayout()
        console_layout.addWidget(self.console)
        console_layout.addWidget(self.toggle_console_button)

        console_widget = QWidget()
        console_widget.setLayout(console_layout)

        parent_layout.addWidget(console_widget)

    def toggle_console(self):
        """Toggle the visibility of the console with animation."""
        if self.console.maximumHeight() == 0:
            self.console_animation.setStartValue(0)
            self.console_animation.setEndValue(200)  # Expanded height
            self.toggle_console_button.setText("\u21e7")  # Up arrow
        else:
            self.console_animation.setStartValue(self.console.maximumHeight())
            self.console_animation.setEndValue(0)
            self.toggle_console_button.setText("\u21e9")  # Down arrow
        self.console_animation.start()

    def log_message(self, message: str, msg_type: str = "INFO"):
        """
        Log messages to the console with different styles.

        Args:
            message (str): The message to display.
            msg_type (str): Type of message ('INFO', 'WARNING', 'ERROR').
        """
        color = {
            "INFO": "#ecf0f1",
            "WARNING": "#f1c40f",
            "ERROR": "#e74c3c"
        }.get(msg_type, "#ecf0f1")
        formatted_message = f'<span style="color:{color};">{message}</span>'
        self.console.append(formatted_message)
        # Auto-scroll to bottom
        scrollbar = self.console.verticalScrollBar()
        scrollbar.setValue(scrollbar.maximum())

    @pyqtSlot(str)
    def show_error(self, error_message):
        """Display error message and log it."""
        QMessageBox.critical(self, "Error", error_message)
        self.log_message(f"ERROR: {error_message}", "ERROR")

    @pyqtSlot(bool, str)
    def processing_finished(self, success, message):
        """Handle completion of processing."""
        self.reset_ui()
        if success:
            QMessageBox.information(self, "Processing Complete", message)
            self.log_message(f"INFO: {message}", "INFO")
        else:
            QMessageBox.warning(self, "Processing Failed", message)
            self.log_message(f"WARNING: {message}", "WARNING")

    def display_audio_visualization(self, y: np.ndarray, sr: int):
        """Display waveform and spectrogram of the processed audio."""
        self.current_processed_audio = y
        self.current_sample_rate = sr

        # Update Waveform
        self.waveform_curve.setData(y)
        duration = librosa.get_duration(y=y, sr=sr)
        times = np.linspace(0, duration, num=len(y))
        self.waveform_plot.setXRange(0, duration)
        self.waveform_plot.setLabel('bottom', 'Time', units='s')

        # Update Spectrogram
        D = librosa.stft(y)
        S_db = librosa.amplitude_to_db(np.abs(D), ref=np.max)
        self.img.setImage(S_db, autoLevels=False)
        freqs = librosa.fft_frequencies(sr=sr)
        times_spec = librosa.frames_to_time(np.arange(S_db.shape[1]), sr=sr)
        self.spectrogram_plot.setLimits(xMin=0, yMin=0, yMax=sr / 2)
        self.spectrogram_plot.setRange(xRange=(0, duration), yRange=(0, sr / 2))
        self.spectrogram_plot.show()

        # Enable preview button
        self.preview_button.setEnabled(True)

    def start_processing(self):
        """Start the audio processing."""
        if not self.validate_inputs():
            return

        options = self.get_processing_options()
        files_to_process = []

        # Collect all files in the queue
        while not self.processing_queue.empty():
            input_path, output_path = self.processing_queue.get()
            files_to_process.append((input_path, output_path))

        if not files_to_process:
            QMessageBox.information(self, "No Files", "No audio files to process.")
            return

        total_files = len(files_to_process)
        self.overall_progress_bar.setMaximum(total_files * 100)
        self.overall_progress_bar.setValue(0)
        self.overall_progress_bar.setText("Starting processing...")
        self.status_label.setText("Starting processing...")

        # Start processing each file
        for idx, (input_path, output_path) in enumerate(files_to_process, 1):
            file_name = os.path.basename(input_path)
            file_progress_widget = FileProgressWidget(file_name)
            list_item = QListWidgetItem()
            list_item.setSizeHint(file_progress_widget.sizeHint())
            self.per_file_progress.addItem(list_item)
            self.per_file_progress.setItemWidget(list_item, file_progress_widget)
            self.per_file_widgets[input_path] = file_progress_widget

            worker = AudioProcessingWorker(input_path, output_path, options)
            worker.signals.progress.connect(lambda val, p=input_path: self.update_file_progress(p, val))
            worker.signals.result.connect(self.display_audio_visualization)
            worker.signals.error.connect(self.show_error)
            worker.signals.finished.connect(lambda success, msg, p=input_path: self.file_finished(p, success, msg))
            self.threadpool.start(worker)
            self.cancel_button.setEnabled(True)
            self.log_message(f"INFO: Started processing {input_path}", "INFO")

    def update_file_progress(self, file_path: str, value: int):
        """Update progress for a specific file."""
        if file_path in self.per_file_widgets:
            self.per_file_widgets[file_path].update_progress(value)
            # Update overall progress
            current_overall = self.overall_progress_bar.value()
            self.overall_progress_bar.setValue(current_overall + value)
            self.overall_progress_bar.setText(f"Processing {os.path.basename(file_path)}")

    def file_finished(self, file_path: str, success: bool, message: str):
        """Handle individual file processing completion."""
        if success:
            self.per_file_widgets[file_path].set_message("Completed")
            self.log_message(f"INFO: {file_path} processed successfully.", "INFO")
        else:
            self.per_file_widgets[file_path].set_message("Failed")
            self.log_message(f"ERROR: {file_path} processing failed - {message}", "ERROR")

    def cancel_processing(self):
        """Cancel all ongoing processing."""
        if self.threadpool.activeThreadCount() > 0:
            self.threadpool.clear()
            self.log_message("INFO: Processing cancelled by user.", "INFO")
            QMessageBox.information(self, "Cancelled", "Processing has been cancelled.")
        self.reset_ui()

    # In der MainWindow Klasse die preview_audio Methode anpassen:
    # Nach den Imports:
    def preview_audio(self):
        """Spielt Audio Preview ab wenn verfügbar"""
        if not PREVIEW_AVAILABLE:
            QMessageBox.warning(self, "Preview nicht verfügbar", 
                "Audio Preview ist auf diesem System nicht verfügbar.")
            return
                
        if self.current_processed_audio is not None and self.current_sample_rate is not None:
            try:
                sd = init_audio_preview()
                if sd:
                    sd.stop()  # Stoppt eventuell laufende Wiedergabe
                    sd.play(self.current_processed_audio, self.current_sample_rate)
                    self.log_message("INFO: Audio wird abgespielt", "INFO")
            except Exception as e:
                QMessageBox.critical(self, "Wiedergabe-Fehler", f"Fehler beim Abspielen: {str(e)}")
                self.log_message(f"ERROR: Wiedergabe fehlgeschlagen - {str(e)}", "ERROR")
        else:
            QMessageBox.information(self, "Keine Audio", "Keine verarbeitete Audio verfügbar.")
            self.log_message("WARNING: Keine Audio zum Abspielen.", "WARNING")


    sys.stderr.write("Debug: Starting class definitions\n")
    sys.stderr.flush()


    def export_settings(self):
        """Export current settings to a JSON file."""
        options = QFileDialog.Options()
        file_path, _ = QFileDialog.getSaveFileName(
            self,
            "Export Settings",
            "",
            "JSON Files (*.json)",
            options=options
        )
        if file_path:
            settings = {
                "sample_rate": self.sample_rate_combo.currentText(),
                "noise_reduce": self.noise_reduce_check.isChecked(),
                "noise_reduction": self.noise_reduction_spin.value(),
                "equalizer": self.equalizer_check.isChecked(),
                "eq_low_gain": self.eq_low_spin.value(),
                "eq_mid_gain": self.eq_mid_spin.value(),
                "eq_high_gain": self.eq_high_spin.value(),
                "reverb": self.reverb_check.isChecked(),
                "reverb_decay": self.reverb_decay_spin.value(),
                "normalize": self.normalize_check.isChecked(),
                "normalize_db": self.normalize_spin.value(),
                "remove_silence": self.silence_check.isChecked(),
                "silence_threshold": self.silence_threshold_spin.value(),
                "bandpass_filter": self.bandpass_check.isChecked(),
                "bandpass_low": self.bandpass_low_spin.value(),
                "bandpass_high": self.bandpass_high_spin.value(),
                "apply_fade": self.fade_check.isChecked(),
                "fade_length": self.fade_length_spin.value()
            }
            try:
                with open(file_path, 'w') as f:
                    json.dump(settings, f, indent=4)
                self.log_message(f"INFO: Settings exported to {file_path}", "INFO")
            except Exception as e:
                QMessageBox.critical(self, "Export Error", f"Failed to export settings: {str(e)}")
                self.log_message(f"ERROR: Failed to export settings - {str(e)}", "ERROR")

    def import_settings(self):
        """Import settings from a JSON file."""
        options = QFileDialog.Options()
        file_path, _ = QFileDialog.getOpenFileName(
            self,
            "Import Settings",
            "",
            "JSON Files (*.json)",
            options=options
        )
        if file_path:
            try:
                with open(file_path, 'r') as f:
                    settings = json.load(f)
                # Apply settings with validation
                self.sample_rate_combo.setCurrentText(settings.get("sample_rate", "44100"))
                self.noise_reduce_check.setChecked(settings.get("noise_reduce", False))
                self.noise_reduction_spin.setValue(settings.get("noise_reduction", 0.5))
                self.equalizer_check.setChecked(settings.get("equalizer", False))
                self.eq_low_spin.setValue(settings.get("eq_low_gain", 0))
                self.eq_mid_spin.setValue(settings.get("eq_mid_gain", 0))
                self.eq_high_spin.setValue(settings.get("eq_high_gain", 0))
                self.reverb_check.setChecked(settings.get("reverb", False))
                self.reverb_decay_spin.setValue(settings.get("reverb_decay", 1.0))
                self.normalize_check.setChecked(settings.get("normalize", False))
                self.normalize_spin.setValue(settings.get("normalize_db", -14))
                self.silence_check.setChecked(settings.get("remove_silence", False))
                self.silence_threshold_spin.setValue(settings.get("silence_threshold", 0.3))
                self.bandpass_check.setChecked(settings.get("bandpass_filter", False))
                self.bandpass_low_spin.setValue(settings.get("bandpass_low", 50))
                self.bandpass_high_spin.setValue(settings.get("bandpass_high", 15000))
                self.fade_check.setChecked(settings.get("apply_fade", False))
                self.fade_length_spin.setValue(settings.get("fade_length", 0.01))
                self.log_message(f"INFO: Settings imported from {file_path}", "INFO")
            except KeyError as e:
                QMessageBox.critical(self, "Import Error", f"Missing key in settings file: {e}")
                self.log_message(f"ERROR: Missing key in settings file - {e}", "ERROR")
            except ValueError as e:
                QMessageBox.critical(self, "Import Error", f"Invalid value in settings file: {e}")
                self.log_message(f"ERROR: Invalid value in settings file - {e}", "ERROR")
            except Exception as e:
                QMessageBox.critical(self, "Import Error", f"Failed to import settings: {str(e)}")
                self.log_message(f"ERROR: Failed to import settings - {str(e)}", "ERROR")

    def show_about(self):
        """Display the About dialog."""
        about_text = """
        <h2>Advanced Audio Processor</h2>
        <p>Version 1.2</p>
        <p>Developed als das ultimative Tool für die Audio-Bearbeitung, speziell zur Vorbereitung von Audiodateien mit Stimmen und zum Training von RVC-Sprachmodellen.</p>
        <p>Funktionen umfassen Rauschreduktion, Normalisierung, Stilleentfernung, Bandpassfilterung, Fade ein/aus, Audio-Visualisierungen, Einstellungen import/export, Stapelverarbeitung und mehr.</p>
        <p>&copy; 2023 Ihr Unternehmen</p>
        """
        QMessageBox.about(self, "About Advanced Audio Processor", about_text)

    def update_progress_bar(self, percent: int, message: str, eta: str):
        """Update the progress bar and status label."""
        self.overall_progress_bar.setValue(percent)
        self.overall_progress_bar.setText(message, eta)
        self.status_label.setText(f"{message} | ETA: {eta}")

    def reset_ui(self):
        """Reset the UI to its initial state."""
        self.process_button.setEnabled(True)
        self.cancel_button.setEnabled(False)
        self.preview_button.setEnabled(True if self.current_processed_audio is not None else False)
        self.overall_progress_bar.setValue(0)
        self.overall_progress_bar.setText("", "")
        self.status_label.setText("Ready")

    def handle_dropped_files(self, file_paths: List[str]):
        """
        Handle files dropped into the drop area.

        Only valid audio files are enqueued for processing.

        Args:
            file_paths (List[str]): List of file paths dropped by the user.
        """
        valid_files = []
        skipped_files = 0
        for file_path in file_paths:
            is_valid, msg = AudioValidator.validate_audio(file_path)
            if is_valid:
                valid_files.append(file_path)
            else:
                skipped_files += 1
                self.log_message(f"WARNING: {file_path} skipped - {msg}", "WARNING")
        if skipped_files > 0:
            QMessageBox.warning(
                self,
                "Invalid Files Skipped",
                f"{skipped_files} Datei(en) wurden aufgrund ungültiger Formate oder anderer Probleme übersprungen."
            )
        if valid_files:
            self.enqueue_files(valid_files)

    def enqueue_files(self, file_paths: List[str]):
        """
        Add valid files to the processing queue.

        Args:
            file_paths (List[str]): List of valid file paths to process.
        """
        for file_path in file_paths:
            output_path = self.generate_output_path(file_path)
            self.processing_queue.put((file_path, output_path))
            self.log_message(f"INFO: Enqueued {file_path} for processing.", "INFO")
        self.process_button.setEnabled(True)
        self.preview_button.setEnabled(False)

    def generate_output_path(self, input_path: str) -> str:
        """
        Generate the output path for a processed file.

        Args:
            input_path (str): Path to the input audio file.

        Returns:
            str: Path to save the processed audio file.
        """
        directory, filename = os.path.split(input_path)
        name, ext = os.path.splitext(filename)
        return os.path.join(directory, f"{name}_processed{ext}")

    def get_processing_options(self) -> ProcessingOptions:
        """
        Retrieve processing options from the UI.

        Returns:
            ProcessingOptions: The current processing options selected by the user.
        """
        return ProcessingOptions(
            sample_rate=int(self.sample_rate_combo.currentText()),
            noise_reduce=self.noise_reduce_check.isChecked(),
            noise_reduction=self.noise_reduction_spin.value(),
            normalize=self.normalize_check.isChecked(),
            normalize_db=self.normalize_spin.value(),
            remove_silence=self.silence_check.isChecked(),
            silence_threshold=self.silence_threshold_spin.value(),
            bandpass_filter=self.bandpass_check.isChecked(),
            bandpass_low=self.bandpass_low_spin.value(),
            bandpass_high=self.bandpass_high_spin.value(),
            apply_fade=self.fade_check.isChecked(),
            fade_length=self.fade_length_spin.value(),
            equalizer=self.equalizer_check.isChecked(),
            eq_low_gain=self.eq_low_spin.value(),
            eq_mid_gain=self.eq_mid_spin.value(),
            eq_high_gain=self.eq_high_spin.value(),
            reverb=self.reverb_check.isChecked(),
            reverb_decay=self.reverb_decay_spin.value()
        )

    def load_settings(self):
        """Load application settings from persistent storage."""
        self.sample_rate_combo.setCurrentText(self.settings.value("sample_rate", "44100"))
        self.noise_reduce_check.setChecked(self.settings.value("noise_reduce", False, type=bool))
        self.noise_reduction_spin.setValue(self.settings.value("noise_reduction", 0.5, type=float))
        self.equalizer_check.setChecked(self.settings.value("equalizer", False, type=bool))
        self.eq_low_spin.setValue(self.settings.value("eq_low_gain", 0, type=float))
        self.eq_mid_spin.setValue(self.settings.value("eq_mid_gain", 0, type=float))
        self.eq_high_spin.setValue(self.settings.value("eq_high_gain", 0, type=float))
        self.reverb_check.setChecked(self.settings.value("reverb", False, type=bool))
        self.reverb_decay_spin.setValue(self.settings.value("reverb_decay", 1.0, type=float))
        self.normalize_check.setChecked(self.settings.value("normalize", False, type=bool))
        self.normalize_spin.setValue(self.settings.value("normalize_db", -14, type=float))
        self.silence_check.setChecked(self.settings.value("remove_silence", False, type=bool))
        self.silence_threshold_spin.setValue(self.settings.value("silence_threshold", 0.3, type=float))
        self.bandpass_check.setChecked(self.settings.value("bandpass_filter", False, type=bool))
        self.bandpass_low_spin.setValue(self.settings.value("bandpass_low", 50, type=int))
        self.bandpass_high_spin.setValue(self.settings.value("bandpass_high", 15000, type=int))
        self.fade_check.setChecked(self.settings.value("apply_fade", False, type=bool))
        self.fade_length_spin.setValue(self.settings.value("fade_length", 0.01, type=float))

    def save_settings(self):
        """Save current application settings to persistent storage."""
        self.settings.setValue("sample_rate", self.sample_rate_combo.currentText())
        self.settings.setValue("noise_reduce", self.noise_reduce_check.isChecked())
        self.settings.setValue("noise_reduction", self.noise_reduction_spin.value())
        self.settings.setValue("equalizer", self.equalizer_check.isChecked())
        self.settings.setValue("eq_low_gain", self.eq_low_spin.value())
        self.settings.setValue("eq_mid_gain", self.eq_mid_spin.value())
        self.settings.setValue("eq_high_gain", self.eq_high_spin.value())
        self.settings.setValue("reverb", self.reverb_check.isChecked())
        self.settings.setValue("reverb_decay", self.reverb_decay_spin.value())
        self.settings.setValue("normalize", self.normalize_check.isChecked())
        self.settings.setValue("normalize_db", self.normalize_spin.value())
        self.settings.setValue("remove_silence", self.silence_check.isChecked())
        self.settings.setValue("silence_threshold", self.silence_threshold_spin.value())
        self.settings.setValue("bandpass_filter", self.bandpass_check.isChecked())
        self.settings.setValue("bandpass_low", self.bandpass_low_spin.value())
        self.settings.setValue("bandpass_high", self.bandpass_high_spin.value())
        self.settings.setValue("apply_fade", self.fade_check.isChecked())
        self.settings.setValue("fade_length", self.fade_length_spin.value())

    def closeEvent(self, event):
        """Handle application close event by saving settings."""
        self.save_settings()
        event.accept()

    def validate_inputs(self) -> bool:
        """
        Validate user inputs before processing.

        Returns:
            bool: True if inputs are valid, False otherwise.
        """
        if self.bandpass_check.isChecked():
            low = self.bandpass_low_spin.value()
            high = self.bandpass_high_spin.value()
            if low >= high:
                QMessageBox.warning(self, "Invalid Input", "Bandpass low frequency must be less than high frequency.")
                self.log_message("WARNING: Bandpass low frequency >= high frequency.", "WARNING")
                return False
        return True

    def set_max_threads(self):
        """Set the maximum number of threads in the thread pool."""
        max_threads = self.max_threads_spin.value()
        self.threadpool.setMaxThreadCount(max_threads)
        self.log_message(f"INFO: Set maximum threads to {max_threads}", "INFO")

    def handle_auto_update(self):
        """Check for updates and prompt the user if an update is available."""
        try:
            response = requests.get(LATEST_VERSION_URL, timeout=5)
            if response.status_code == 200:
                latest_info = response.json()
                latest_version = latest_info.get("version")
                download_url = latest_info.get("download_url")
                current_version = "1.2"  # This should be dynamically set
                if latest_version and latest_version > current_version:
                    reply = QMessageBox.question(
                        self,
                        "Update Available",
                        f"A new version ({latest_version}) is available. Do you want to download it?",
                        QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No
                    )
                    if reply == QMessageBox.StandardButton.Yes:
                        QDesktopServices.openUrl(QUrl(download_url))
            else:
                logger.warning("Failed to check for updates.")
        except Exception as e:
            logger.error(f"Auto-update check failed: {e}")
            
sys.stderr.write("Debug: MainWindow defined\n")
sys.stderr.flush()

# --- Style Sheet ---
class StyleSheet:
    """Central style definitions."""
    MAIN = """
        QMainWindow {
            background-color: #f0f0f0;
        }
        QLabel {
            font-size: 12px;
            color: #2c3e50;
        }
        QPushButton {
            background-color: #3498db;
            color: white;
            border: none;
            padding: 8px 16px;
            border-radius: 4px;
            font-weight: bold;
            transition: background-color 0.3s, transform 0.2s;
        }
        QPushButton:hover {
            background-color: #2980b9;
            transform: scale(1.05);
        }
        QPushButton:pressed {
            transform: scale(0.95);
        }
        QPushButton:disabled {
            background-color: #bdc3c7;
        }
        QProgressBar {
            border: 2px solid #bdc3c7;
            border-radius: 5px;
            text-align: center;
            transition: border-color 0.3s;
        }
        QProgressBar::chunk {
            background-color: #2ecc71;
            transition: width 0.5s;
        }
        QTextEdit {
            background-color: #2c3e50;
            color: #ecf0f1;
            font-family: Consolas;
            font-size: 10px;
            border: none;
        }
    """

sys.stderr.write("Debug: StyleSheet defined\n")
sys.stderr.flush()

# --- Drop Area Widget ---
class DropArea(QLabel):
    """
    Enhanced drag-drop area with visual feedback.
    Emits a signal when files are dropped or selected via dialog.
    """
    files_dropped = pyqtSignal(list)

    def __init__(self):
        super().__init__()
        self.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.setMinimumSize(500, 250)
        self.setStyleSheet("""
            QLabel {
                border: 2px dashed #bdc3c7;
                border-radius: 8px;
                background-color: #ecf0f1;
                padding: 20px;
            }
            QLabel:hover {
                border-color: #3498db;
                background-color: #e8f6ff;
            }
        """)
        self.setText("<h3>Drag and Drop Audio Files Here<br>or Click to Select Files</h3>")
        self.setAcceptDrops(True)

    def dragEnterEvent(self, event: QDragEnterEvent):
        """Handle drag enter event."""
        if event.mimeData().hasUrls():
            event.acceptProposedAction()
            self.setStyleSheet("""
                QLabel {
                    border: 2px dashed #3498db;
                    border-radius: 8px;
                    background-color: #e8f6ff;
                    padding: 20px;
                }
            """)
    
    def dragLeaveEvent(self, event):
        """Handle drag leave event."""
        self.setStyleSheet("""
            QLabel {
                border: 2px dashed #bdc3c7;
                border-radius: 8px;
                background-color: #ecf0f1;
                padding: 20px;
            }
        """)

    def dropEvent(self, event: QDropEvent):
        """Handle drop event."""
        files = [url.toLocalFile() for url in event.mimeData().urls()]
        self.files_dropped.emit(files)
        self.setStyleSheet("""
            QLabel {
                border: 2px dashed #bdc3c7;
                border-radius: 8px;
                background-color: #ecf0f1;
                padding: 20px;
            }
        """)

    def mousePressEvent(self, event):
        """Handle clicks to open file dialog."""
        if event.button() == Qt.MouseButton.LeftButton:
            self.open_file_dialog()

    def open_file_dialog(self):
        """Open a file dialog to select audio files."""
        file_dialog = QFileDialog()
        file_dialog.setFileMode(QFileDialog.FileMode.ExistingFiles)
        file_dialog.setNameFilters(["Audio Files (*.wav *.mp3 *.ogg *.flac *.m4a)"])
        if file_dialog.exec():
            files = file_dialog.selectedFiles()
            self.files_dropped.emit(files)

sys.stderr.write("Debug: DropArea defined\n")
sys.stderr.flush()

# --- Detailed Progress Bar ---
class DetailedProgressBar(QProgressBar):
    """
    Customized ProgressBar to display detailed information including progress percentage,
    number of processed/total files, and estimated time remaining (ETA).
    """
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
        self.setTextVisible(True)
        self.setFormat("%p% - %v/%m files - %s")
        self.setText("")

    def setText(self, message: str, eta: Optional[str] = None):
        """Set the text of the progress bar with optional ETA."""
        if eta:
            self.setFormat(f"%p% - %v/%m files - {message} | ETA: {eta}")
        else:
            self.setFormat(f"%p% - %v/%m files - {message}")

sys.stderr.write("Debug: DetailedProgressBar defined\n")
sys.stderr.flush()

# --- Main Function ---
def main():
    """Main application entry point."""
    sys.stderr.write("Starting application...\n")
    sys.stderr.flush()
    
    try:
        sys.stderr.write("Initializing QApplication...\n")
        sys.stderr.flush()
        app = QApplication(sys.argv)
        app.setStyle('Fusion')
        
        sys.stderr.write("Setting up DPI scaling...\n")
        sys.stderr.flush()
        app.setAttribute(Qt.ApplicationAttribute.AA_EnableHighDpiScaling, True)
        app.setAttribute(Qt.ApplicationAttribute.AA_UseHighDpiPixmaps, True)

        sys.stderr.write("Creating main window...\n")
        sys.stderr.flush()
        window = MainWindow()
        
        sys.stderr.write("Showing window...\n")
        sys.stderr.flush()
        window.show()
        
        sys.stderr.write("Checking for updates...\n")
        sys.stderr.flush()
        window.handle_auto_update()
        
        sys.stderr.write("Starting event loop...\n")
        sys.stderr.flush()
        return app.exec()
        
    except Exception as e:
        sys.stderr.write(f"Critical error: {str(e)}\n")
        sys.stderr.flush()
        logger.exception("Critical error during startup")
        return 1
    
sys.stderr.write("Debug: Reached program entry point\n") 
sys.stderr.flush()
    
if __name__ == "__main__":
    sys.stderr.write("Debug: Program start\n")
    sys.stderr.flush()
    exit_code = main()
    sys.stderr.write(f"Debug: Program end with code {exit_code}\n")
    sys.stderr.flush()
    sys.exit(exit_code)