From 2e311119b0dcef285522df1a7cc60c96a131ac3f Mon Sep 17 00:00:00 2001 From: oberon Date: Mon, 5 Oct 2026 11:33:37 +0200 Subject: [PATCH] fixxed alsa sound problems --- __pycache__/app.cpython-314.pyc | Bin 0 -> 338 bytes __pycache__/config.cpython-314.pyc | Bin 0 -> 1907 bytes app.py | 5 +-- app/__init__.py | 35 +++++++++++++-------- app/__pycache__/__init__.cpython-314.pyc | Bin 2753 -> 3092 bytes app/routes/__pycache__/api.cpython-314.pyc | Bin 37079 -> 37178 bytes app/routes/api.py | 15 +++++---- config.py | 10 ++++-- other/.DS_Store | Bin 0 -> 6148 bytes templates/base.html | 6 +--- 10 files changed, 42 insertions(+), 29 deletions(-) create mode 100644 __pycache__/app.cpython-314.pyc create mode 100644 __pycache__/config.cpython-314.pyc create mode 100644 other/.DS_Store diff --git a/__pycache__/app.cpython-314.pyc b/__pycache__/app.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..491efa81e7e94754490afb414b191d95cbe210f6 GIT binary patch literal 338 zcmdPq1FEKYYKK>SSQEA>vhR-0|Zm|L7^$IF) zaoFVMrI$>u2Q~&)j&}D( c_X&~7!R6rMF0FvdTCmmfm`r&TK}!l_fMQtZYOhQ$zIAp^v!r7*%~flcskx;vZJ zIdQ0Z=R|#Sa!M-o5cSkU50!GSh&b4qYfrsd@}Wm}mIdmhj#RH;=6mmb-<#pR+2Q8w zj2+NtNqY0hV*%h#-55RQAvnK5K^s&6WYPcw7Ayfc;RVpNHeoO@1DTJ(viUFF!wnMvK@g@p!B(1S ze(1h572KDMA^ZT7y@EMCT5~jG#|PAbE7Xol)tSAP&OEN_+_iL*W8M6 z&+{di&!Sj4k>Bqtw>yu zu%HlgZYLhs=<5tVU%9jL$1hrz!X05x#eya%n$(EY-~6UTaVbX{`SVh-ViU7t1EXtP(R;G=Z271$8+>YzRr!0|6mo zN9aJVX)PT)5c)=|wuX^8gzBQA;+7~0l1#%BvP!Ii^i))2iI^G!R`hFwn4eT}lUS>J zssU=EqG!<8sEdQVwyju^Ly0sb=0~z95j(AAGQB;P}&V=#d( zaa{>687pT?sFdPz97?9M9I+eyNYc8Ga525hky*nZPsMni%NB{lu(!&|BnOGhu=sKg zz0WW@OD0?Lx3ovYG~=$?Vub?YV>x|+AwtDe9+t?oZa?5)F`ehhoNgqzVjQLmCEdXy zq~aei44{>o2YMog3}czl2~X_+#_c zRNr~KeNWG*iwvKo@4VICe%EK~J69<$7&_iQ+CI)6WncMT-|YuuJ+uGRA2{|Nd5?of z!QQ7Ey}O0J|9;Qxp)2`ARN@QhgTKw6`hx8&B^$8?Pj|hu-rekM_HL~A-5V$Fc+VaG z6;lf9?e2DVyOmC*_sQn();^m$VfnW#-)9TGQu8g_Z1ZP!Fn_b1I%NYiuWPZLIrY@O z&nv5=YAsJFo)I1t)(G9EK4SaIIOLm(e&6W-QmW29GcgQvZUKz_Z*zzdm~)_y1KmFq C)2)X9 literal 0 HcmV?d00001 diff --git a/app.py b/app.py index 5114504..8465744 100644 --- a/app.py +++ b/app.py @@ -4,5 +4,6 @@ from app import create_app app = create_app() if __name__ == '__main__': - app.run(host='0.0.0.0', port=5000, debug=True) - \ No newline at end of file + # Der Werkzeug-ReLoader startet zwei Prozesse. Beide würden versuchen, + # exklusiv auf dasselbe ALSA-Gerät zuzugreifen. + app.run(host='0.0.0.0', port=5000, debug=True, use_reloader=False) diff --git a/app/__init__.py b/app/__init__.py index d0325a8..2b0dd2e 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -4,14 +4,10 @@ import logging import threading import time import os -import pygame from flask import Flask from .utils.logging import setup_logging, cleanup_old_log_dirs -from .routes.main import main_bp -from .routes.admin import admin_bp -from .routes.api import api_bp from .bluetooth.manager import init_bluetooth logger = logging.getLogger(__name__) # ← Logger für diese Datei @@ -30,16 +26,29 @@ def create_app(): # Bluetooth initialisieren (Monitor-Thread startet automatisch) init_bluetooth() - # pygame initialisieren (einmalig) + # pygame initialisieren (einmalig). Ein Audiofehler darf die Hub-Steuerung + # nicht am Start hindern; die API versucht die Initialisierung später erneut. from config import Config - pygame.mixer.pre_init(frequency=Config.AUDIO_FREQ, - size=Config.AUDIO_SIZE, - channels=Config.AUDIO_CHANNELS, - buffer=Config.AUDIO_BUFFER) - pygame.mixer.init() - pygame.mixer.set_num_channels(Config.AUDIO_NUM_CHANNELS) # genug parallele Kanäle für BG + Effekte - pygame.mixer.music.set_volume(0.8) # Standard-Lautstärke (für Legacy-Fälle) - app.logger.info("pygame initialisiert") + if Config.AUDIO_DEVICE: + os.environ['AUDIODEV'] = Config.AUDIO_DEVICE + import pygame + try: + init_args = { + 'frequency': Config.AUDIO_FREQ, + 'size': Config.AUDIO_SIZE, + 'channels': Config.AUDIO_CHANNELS, + 'buffer': Config.AUDIO_BUFFER, + } + if Config.AUDIO_DEVICE: + init_args['devicename'] = Config.AUDIO_DEVICE + pygame.mixer.init(**init_args) + pygame.mixer.set_num_channels(Config.AUDIO_NUM_CHANNELS) + pygame.mixer.music.set_volume(0.8) + app.logger.info(f"pygame initialisiert (Gerät: {Config.AUDIO_DEVICE or 'SDL-Standard'})") + except pygame.error as e: + app.logger.error(f"Audio konnte nicht initialisiert werden: {e}") + if Config.AUDIO_REQUIRED: + raise # Blueprints registrieren from .routes.main import main_bp diff --git a/app/__pycache__/__init__.cpython-314.pyc b/app/__pycache__/__init__.cpython-314.pyc index 597b17f7a3d8695e8a372e37841ad4145660cdd0..4be6c85ffc9976c4a0911a3610dc6ec587b0e6b9 100644 GIT binary patch delta 1648 zcmZux%}*Og6rb^acy_(grrHD1OkOppz&5HH4FIE;BN57Yzy{kyd-HZ zzoL3q95}b74Vxd-x&PN}x!N z+d&*DM@3KpXmR05dUZ3tSylq)T!&s}VfIwZ>X5eTRUqf-0E^%l=?sG% zWv90Gs19{7#2f=UOt)L#u(R;0^)K7K>WBsHroNz+)Mc&s@M}7L8(rxnevL1S1WV{8 z-PF}3y`pQ_O!QvS@UzF}<-{FnW@4&;##BoM6&DdklTn1%3>UShx7&FlId@jg4ue zrjyq1d|!YkET;dT!|!EkU3OmzOJj2r@+bL;$(%es>2S;XZ4Fz7`>M=o7?-i*-IFVm z({r*iIpKJ4dBxN!r)fGkK)p%(NHZxMq>$Kx3>}B8hWp&A=rF2bG{fWLR7Id=%B#3o zaiG?8)HKB*BE;=f!@IDgsihSoZ!Tg@EmUagiGzXTR7YGOB2&v#-|rK^N50B)@*vy= zKZ?EwsGc}o?@aG<)>r7%Dgs>R4jX8={9N#*)V3M1V|}$)UtJ2`|Huya)WSV=DYD7i z(f(Srzb=LE->@U;S|r^NxTE4dp&`@sZ(}pu$CIUC*NPHN!@kiU65lK(U~V)J*Ui%G3%#mlYvLH?npcU2m&=8fC2a&x5RAU*m9u1NFc895Jb=C( q;NJnB9U%My+I|HiKY{+2g5MV6TS9!(Kk&Wq&Ru?&9e}>3&;I~AA$%49 delta 1397 zcmah}-A~(A6u-8wzv6t5H6M^|HTh^+TG3Dj4T8dkRCRX6L}azu3nevR1-D6T-CWSR z7lx*ZXLS3p?uiFp_DAet|G>0#NI}k!rb*MZw@PL2^L3go6PtP^AOG&}p7T4$$H#s) z`a?2$JsJrCf3?3Nc0@XijxxuG6CXTabco?PFj$?}1T3gvoiR9F)FdovGM0lq)I*wr zl>qa4Sc~9DfCW9O#c(XZqCTRC_Rv!m(GTVP>(zaZK<3%{T9k^>RT=5uhi&E3@UD-m zOeOK3Z0aIQKIT$;en95pk-?W?pH;zIig^EG^vrAOt+6T~&)J*d;SA(Qc7YK{h@0IL z2i*+XE$K-u<+1^m^|UtXasdwMV_L?ADyV`=`C=_q_8*o1@!$-_2$$Kx^A5bG{w-F8 zMr7E{h^B$dugwj-D)V#(5>?)a86yKVSEve=MRFG|#N)$t_*3x?nd0xWMM%Ep^Ec|> zKBw!?kG@E_PwQsW8n;_Ew#|m!wk?E_;AcS+HFToMqHw&tT6)m7P`kA8c-tz~D#&?k zJ;4F8cTHTX-LZD9hT}G^7B0C@@wU?{HJ@xcEsUJTr0KdP@|&>Clu1F%F&XlSXs|_< z9EsO*VVZ`HnBlBJFnI#gZ?v)Rum2?wJG7fe^fN1_Jh9=_>vpS-X8k=%`^ICPHp=^e zJW{Ugp_`PakBp|Np*=(&QbQZ$#Wxx|7IqxG?RULp)-8nS3-jcyb{1X6YGJI9#DEf?t#efApHkeIs@Zp hAa@2XpMl9=<&mzOc_C-MnfqBTd?}p6NhTKP{|%FAAI1Ox diff --git a/app/routes/__pycache__/api.cpython-314.pyc b/app/routes/__pycache__/api.cpython-314.pyc index e7fd5ee563decc48a410700bb206521e9733782c..6fc854d6930d192142ba45d98e07797341c04d81 100644 GIT binary patch delta 4666 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 delta 4769 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 diff --git a/app/routes/api.py b/app/routes/api.py index fb2cfaa..0ada348 100644 --- a/app/routes/api.py +++ b/app/routes/api.py @@ -29,13 +29,16 @@ DEFAULT_MAX_PER_HOUR = 2 DEFAULT_WINDOW_SECONDS = 3600 def _ensure_mixer(): - from config import Config if not pygame.mixer.get_init(): - pygame.mixer.pre_init(frequency=Config.AUDIO_FREQ, - size=Config.AUDIO_SIZE, - channels=Config.AUDIO_CHANNELS, - buffer=Config.AUDIO_BUFFER) - pygame.mixer.init() + init_args = { + 'frequency': Config.AUDIO_FREQ, + 'size': Config.AUDIO_SIZE, + 'channels': Config.AUDIO_CHANNELS, + 'buffer': Config.AUDIO_BUFFER, + } + if Config.AUDIO_DEVICE: + init_args['devicename'] = Config.AUDIO_DEVICE + pygame.mixer.init(**init_args) pygame.mixer.set_num_channels(Config.AUDIO_NUM_CHANNELS) def _load_sound(file_path): diff --git a/config.py b/config.py index 9dc677b..647280a 100644 --- a/config.py +++ b/config.py @@ -21,11 +21,15 @@ class Config: AUDIO_CHANNELS = 2 AUDIO_BUFFER = 2048 # größerer Buffer reduziert Knacksen AUDIO_NUM_CHANNELS = 16 + # ALSA/SDL-Gerät, z. B. "default", "plughw:CARD=PCM5102,DEV=0" + # oder ein in /etc/asound.conf definiertes Gerät. Leer = SDL-Standard. + AUDIO_DEVICE = os.environ.get('MKCONTROL_AUDIO_DEVICE') or None + AUDIO_REQUIRED = os.environ.get('MKCONTROL_AUDIO_REQUIRED', 'false').lower() in ('1', 'true', 'yes') # Optional: absolute Pfade, falls du später Docker o.ä. nutzt # CONFIG_DIR = os.path.join(os.path.dirname(__file__), 'configs') - APP_NAME = "MK Sound & Control" - APP_NAME_SHORT = "MKSC" # für Tab-Titel, wenns kurz sein soll + APP_NAME = "Mini-World Control Center" + APP_NAME_SHORT = "MWCC" # für Tab-Titel, wenns kurz sein soll APP_VERSION = "0.9.β" - APP_DESCRIPTION = "Websteuerung für MouldKing MK4/MK6-Hubs mit Soundboard" + APP_DESCRIPTION = "Websteuerung für MouldKing MK4/MK6-Hubs mit Soundboard und Aktorensteuerung" diff --git a/other/.DS_Store b/other/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..88f336cc13681ae797e508bb943de59a9d7c266e GIT binary patch literal 6148 zcmeHKF-`+P474ExnJN1t0)xIe1Ief2`S<#sISVq_!-RDR+Q*Mg=o-NvS-)p zxy?;+j?K)M@6UH;3p1O;iMD5$8qetyyQqu<;dsW@277zh4cpCbQhh!_?v=gR+CJ>{ zm_KZA!k=|R|0=^;CIzH`6p#W^Knnau0rp + @@ -70,11 +71,6 @@ -
-

{{ config.APP_NAME }}

- -
-
{% with messages = get_flashed_messages(with_categories=true) %}