Initial Release
This commit is contained in:
126
generator.py
Executable file
126
generator.py
Executable file
@@ -0,0 +1,126 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
import sys
|
||||||
|
import numpy as np
|
||||||
|
import pyaudio
|
||||||
|
import threading
|
||||||
|
from PyQt6.QtWidgets import (QApplication, QWidget, QVBoxLayout, QPushButton,
|
||||||
|
QSlider, QLabel, QSystemTrayIcon, QMenu)
|
||||||
|
from PyQt6.QtCore import Qt
|
||||||
|
from PyQt6.QtGui import QIcon, QAction, QColor, QPixmap
|
||||||
|
|
||||||
|
class BrownNoiseGenerator(QWidget):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
# Audio-Setup
|
||||||
|
self.fs = 44100
|
||||||
|
self.chunk_size = 1024
|
||||||
|
self.volume = 0.5
|
||||||
|
self.is_playing = False
|
||||||
|
self.p = pyaudio.PyAudio()
|
||||||
|
self.stream = None
|
||||||
|
self.last_val = 0.0
|
||||||
|
|
||||||
|
self.init_ui()
|
||||||
|
self.setup_tray()
|
||||||
|
|
||||||
|
def init_ui(self):
|
||||||
|
self.setWindowTitle("Brown Noise")
|
||||||
|
self.setFixedWidth(250)
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
|
||||||
|
self.btn_toggle = QPushButton("Start", self)
|
||||||
|
self.btn_toggle.clicked.connect(self.toggle_noise)
|
||||||
|
layout.addWidget(self.btn_toggle)
|
||||||
|
|
||||||
|
layout.addWidget(QLabel("Lautstärke:"))
|
||||||
|
self.slider = QSlider(Qt.Orientation.Horizontal)
|
||||||
|
self.slider.setRange(0, 100)
|
||||||
|
self.slider.setValue(50)
|
||||||
|
self.slider.valueChanged.connect(self.update_volume)
|
||||||
|
layout.addWidget(self.slider)
|
||||||
|
|
||||||
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
def setup_tray(self):
|
||||||
|
# Erstellt ein einfaches Icon (farbiges Quadrat), falls du keine .png Datei hast
|
||||||
|
pixmap = QPixmap(64, 64)
|
||||||
|
pixmap.fill(QColor("brown"))
|
||||||
|
icon = QIcon(pixmap)
|
||||||
|
|
||||||
|
self.tray_icon = QSystemTrayIcon(icon, self)
|
||||||
|
self.tray_icon.setToolTip("Brown Noise Generator")
|
||||||
|
|
||||||
|
# Tray Menü (Rechtsklick)
|
||||||
|
tray_menu = QMenu()
|
||||||
|
show_action = QAction("Anzeigen", self)
|
||||||
|
quit_action = QAction("Beenden", self)
|
||||||
|
|
||||||
|
show_action.triggered.connect(self.show)
|
||||||
|
quit_action.triggered.connect(self.quit_app)
|
||||||
|
|
||||||
|
tray_menu.addAction(show_action)
|
||||||
|
tray_menu.addSeparator()
|
||||||
|
tray_menu.addAction(quit_action)
|
||||||
|
|
||||||
|
self.tray_icon.setContextMenu(tray_menu)
|
||||||
|
self.tray_icon.show()
|
||||||
|
|
||||||
|
# Linksklick auf Icon zeigt/versteckt Fenster
|
||||||
|
self.tray_icon.activated.connect(self.tray_icon_activated)
|
||||||
|
|
||||||
|
def tray_icon_activated(self, reason):
|
||||||
|
if reason == QSystemTrayIcon.ActivationReason.Trigger:
|
||||||
|
if self.isVisible():
|
||||||
|
self.hide()
|
||||||
|
else:
|
||||||
|
self.show()
|
||||||
|
self.raise_()
|
||||||
|
|
||||||
|
def update_volume(self, value):
|
||||||
|
self.volume = value / 100.0
|
||||||
|
|
||||||
|
def generate_brown_noise_chunk(self):
|
||||||
|
white_noise = np.random.uniform(-1, 1, self.chunk_size)
|
||||||
|
brown_noise = np.zeros_like(white_noise)
|
||||||
|
for i in range(len(white_noise)):
|
||||||
|
self.last_val = 0.99 * self.last_val + 0.02 * white_noise[i]
|
||||||
|
brown_noise[i] = self.last_val
|
||||||
|
return (brown_noise * self.volume).astype(np.float32).tobytes()
|
||||||
|
|
||||||
|
def audio_loop(self):
|
||||||
|
self.stream = self.p.open(format=pyaudio.paFloat32, channels=1, rate=self.fs, output=True)
|
||||||
|
while self.is_playing:
|
||||||
|
self.stream.write(self.generate_brown_noise_chunk())
|
||||||
|
self.stream.stop_stream()
|
||||||
|
self.stream.close()
|
||||||
|
|
||||||
|
def toggle_noise(self):
|
||||||
|
if not self.is_playing:
|
||||||
|
self.is_playing = True
|
||||||
|
self.btn_toggle.setText("Stop")
|
||||||
|
threading.Thread(target=self.audio_loop, daemon=True).start()
|
||||||
|
else:
|
||||||
|
self.is_playing = False
|
||||||
|
self.btn_toggle.setText("Start")
|
||||||
|
|
||||||
|
def closeEvent(self, event):
|
||||||
|
"""Überschreibt das Schließen: Fenster wird nur versteckt."""
|
||||||
|
if self.tray_icon.isVisible():
|
||||||
|
self.hide()
|
||||||
|
event.ignore() # Verhindert das Schließen der App
|
||||||
|
|
||||||
|
def quit_app(self):
|
||||||
|
"""Beendet die App wirklich."""
|
||||||
|
self.is_playing = False
|
||||||
|
self.p.terminate()
|
||||||
|
QApplication.quit()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app = QApplication(sys.argv)
|
||||||
|
# Verhindert, dass die App schließt, wenn das Fenster versteckt wird
|
||||||
|
app.setQuitOnLastWindowClosed(False)
|
||||||
|
|
||||||
|
ex = BrownNoiseGenerator()
|
||||||
|
ex.show()
|
||||||
|
sys.exit(app.exec())
|
||||||
Reference in New Issue
Block a user