Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c0b3619bcc |
+7
-62
@@ -9,7 +9,6 @@ Audio-Passthrough und Physik-Visualisierung.
|
|||||||
|
|
||||||
import requests, time, argparse, numpy as np, sys, math
|
import requests, time, argparse, numpy as np, sys, math
|
||||||
import threading, json, psutil
|
import threading, json, psutil
|
||||||
from pathlib import Path
|
|
||||||
from flask import Flask, render_template_string, jsonify, request as flask_request
|
from flask import Flask, render_template_string, jsonify, request as flask_request
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -29,7 +28,6 @@ disk_dial_uid = None
|
|||||||
running = False
|
running = False
|
||||||
current_level = 0
|
current_level = 0
|
||||||
current_peak = 0
|
current_peak = 0
|
||||||
SETTINGS_FILE = Path(__file__).with_name("vu1_audio_settings.json")
|
|
||||||
|
|
||||||
# ══════════════════════════════════════════════════════════════
|
# ══════════════════════════════════════════════════════════════
|
||||||
# HTML / CSS / JS — Skeuomorphes VU-Meter
|
# HTML / CSS / JS — Skeuomorphes VU-Meter
|
||||||
@@ -458,11 +456,6 @@ body {
|
|||||||
Hüllkurve mit separatem Attack/Release + 2.-Ordnung Nadelmodell<br>
|
Hüllkurve mit separatem Attack/Release + 2.-Ordnung Nadelmodell<br>
|
||||||
Natürliches Einschwingen, weniger Zappeln, weicher Rücklauf.
|
Natürliches Einschwingen, weniger Zappeln, weicher Rücklauf.
|
||||||
</div>
|
</div>
|
||||||
<div class="iec-box" id="natural-box" style="display:none">
|
|
||||||
<b>Natural+</b> — neue Ballistikformel<br>
|
|
||||||
Hüllkurve mit separatem Attack/Release + 2.-Ordnung Nadelmodell<br>
|
|
||||||
Natürliches Einschwingen, weniger Zappeln, weicher Rücklauf.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Physics sliders -->
|
<!-- Physics sliders -->
|
||||||
<div id="physics-ctrls">
|
<div id="physics-ctrls">
|
||||||
@@ -676,7 +669,7 @@ function drawVU(level, peak){
|
|||||||
|
|
||||||
// Center pivot point (inside canvas so needle is always visible)
|
// Center pivot point (inside canvas so needle is always visible)
|
||||||
const cx = w/2;
|
const cx = w/2;
|
||||||
const cy = h - 22;
|
const cy = h - 12;
|
||||||
const radius = Math.min(w * 0.45, h * 0.78);
|
const radius = Math.min(w * 0.45, h * 0.78);
|
||||||
|
|
||||||
// Scale arc (immer obere Hälfte, links -> rechts)
|
// Scale arc (immer obere Hälfte, links -> rechts)
|
||||||
@@ -1083,9 +1076,6 @@ class PhysicsVU:
|
|||||||
# Natural+ Formel (neue Ballistik)
|
# Natural+ Formel (neue Ballistik)
|
||||||
self._natural_env = 0.0
|
self._natural_env = 0.0
|
||||||
|
|
||||||
# Natural+ Formel (neue Ballistik)
|
|
||||||
self._natural_env = 0.0
|
|
||||||
|
|
||||||
# ── Biquad helpers ──
|
# ── Biquad helpers ──
|
||||||
def _calc_biquad(self, fc):
|
def _calc_biquad(self, fc):
|
||||||
w0 = 2.0 * math.pi * fc / self.sample_rate
|
w0 = 2.0 * math.pi * fc / self.sample_rate
|
||||||
@@ -1382,34 +1372,6 @@ class PhysicsVU:
|
|||||||
return self.needle_pos, self.peak_pos
|
return self.needle_pos, self.peak_pos
|
||||||
|
|
||||||
|
|
||||||
# ── Persistenz: zuletzt gewählte Audio-Geräte ──
|
|
||||||
def load_audio_settings():
|
|
||||||
defaults = {"audio_device_in": None, "audio_device_out": -1}
|
|
||||||
try:
|
|
||||||
if not SETTINGS_FILE.exists():
|
|
||||||
return defaults
|
|
||||||
data = json.loads(SETTINGS_FILE.read_text(encoding="utf-8"))
|
|
||||||
in_dev = data.get("audio_device_in", None)
|
|
||||||
out_dev = data.get("audio_device_out", -1)
|
|
||||||
if out_dev is None:
|
|
||||||
out_dev = -1
|
|
||||||
return {"audio_device_in": in_dev, "audio_device_out": out_dev}
|
|
||||||
except Exception as e:
|
|
||||||
print(f"⚠️ Konnte Audio-Settings nicht laden: {e}")
|
|
||||||
return defaults
|
|
||||||
|
|
||||||
|
|
||||||
def save_audio_settings(in_dev, out_dev):
|
|
||||||
try:
|
|
||||||
payload = {
|
|
||||||
"audio_device_in": in_dev,
|
|
||||||
"audio_device_out": out_dev if out_dev is not None else -1
|
|
||||||
}
|
|
||||||
SETTINGS_FILE.write_text(json.dumps(payload, indent=2), encoding="utf-8")
|
|
||||||
except Exception as e:
|
|
||||||
print(f"⚠️ Konnte Audio-Settings nicht speichern: {e}")
|
|
||||||
|
|
||||||
|
|
||||||
# ══════════════════════════════════════════════════════════════
|
# ══════════════════════════════════════════════════════════════
|
||||||
# Flask Routes
|
# Flask Routes
|
||||||
# ══════════════════════════════════════════════════════════════
|
# ══════════════════════════════════════════════════════════════
|
||||||
@@ -1457,7 +1419,6 @@ def set_device(which, dev_id):
|
|||||||
if meter.start():
|
if meter.start():
|
||||||
running = True
|
running = True
|
||||||
threading.Thread(target=update_loop, daemon=True).start()
|
threading.Thread(target=update_loop, daemon=True).start()
|
||||||
save_audio_settings(app.config.get('audio_device_in'), app.config.get('audio_device_out', -1))
|
|
||||||
return jsonify({"ok": True})
|
return jsonify({"ok": True})
|
||||||
|
|
||||||
@app.route('/toggle')
|
@app.route('/toggle')
|
||||||
@@ -1523,6 +1484,7 @@ def set_param(param, value):
|
|||||||
meter.mode = value
|
meter.mode = value
|
||||||
if value == 'iec_true':
|
if value == 'iec_true':
|
||||||
meter._iec_z[:] = 0
|
meter._iec_z[:] = 0
|
||||||
|
meter._iec_fast = meter._latest_peak
|
||||||
if value == 'natural_formula':
|
if value == 'natural_formula':
|
||||||
meter._natural_env = meter.needle_pos
|
meter._natural_env = meter.needle_pos
|
||||||
elif param == 'monitor':
|
elif param == 'monitor':
|
||||||
@@ -1557,7 +1519,7 @@ def reset():
|
|||||||
meter.needle_pos=0; meter.needle_vel=0; meter.peak_pos=0
|
meter.needle_pos=0; meter.needle_vel=0; meter.peak_pos=0
|
||||||
meter.mode='full'; meter.monitor=False; meter.bypass=False; meter.solo='off'
|
meter.mode='full'; meter.monitor=False; meter.bypass=False; meter.solo='off'
|
||||||
meter.band_crossover=250; meter.band_lo_weight=0.6; meter.band_hi_weight=0.4
|
meter.band_crossover=250; meter.band_lo_weight=0.6; meter.band_hi_weight=0.4
|
||||||
meter._iec_z[:]=0; meter._iec_level=0; meter._natural_env=0
|
meter._iec_z[:]=0; meter._iec_level=0; meter._iec_fast=0; meter._natural_env=0
|
||||||
return jsonify({"ok": True})
|
return jsonify({"ok": True})
|
||||||
|
|
||||||
|
|
||||||
@@ -1597,7 +1559,7 @@ def update_loop():
|
|||||||
# ── Main ──
|
# ── Main ──
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
global client, dial_uid, meter, running
|
global client, dial_uid, meter
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("--api-key", required=True)
|
parser.add_argument("--api-key", required=True)
|
||||||
@@ -1607,13 +1569,8 @@ def main():
|
|||||||
parser.add_argument("--port", type=int, default=8080)
|
parser.add_argument("--port", type=int, default=8080)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
saved = load_audio_settings()
|
app.config['audio_device_in'] = args.audio_device
|
||||||
chosen_in = args.audio_device if args.audio_device is not None else saved.get('audio_device_in')
|
app.config['audio_device_out'] = args.output_device
|
||||||
chosen_out = args.output_device if args.output_device is not None else saved.get('audio_device_out', -1)
|
|
||||||
|
|
||||||
app.config['audio_device_in'] = chosen_in
|
|
||||||
app.config['audio_device_out'] = chosen_out if chosen_out is not None else -1
|
|
||||||
save_audio_settings(app.config['audio_device_in'], app.config['audio_device_out'])
|
|
||||||
|
|
||||||
client = VU1Client(api_key=args.api_key)
|
client = VU1Client(api_key=args.api_key)
|
||||||
dials = client.get_dials()
|
dials = client.get_dials()
|
||||||
@@ -1637,19 +1594,7 @@ def main():
|
|||||||
globals()['disk_dial_uid'] = others[1]
|
globals()['disk_dial_uid'] = others[1]
|
||||||
print(f"✅ Disk-Dial: ({others[1][:8]}…)")
|
print(f"✅ Disk-Dial: ({others[1][:8]}…)")
|
||||||
|
|
||||||
out_for_meter = app.config['audio_device_out']
|
meter = PhysicsVU(device_in=args.audio_device, device_out=args.output_device)
|
||||||
meter = PhysicsVU(
|
|
||||||
device_in=app.config['audio_device_in'],
|
|
||||||
device_out=out_for_meter if out_for_meter is not None and out_for_meter >= 0 else None
|
|
||||||
)
|
|
||||||
|
|
||||||
# Auto-Start mit gespeicherten Geräten
|
|
||||||
if meter.start():
|
|
||||||
running = True
|
|
||||||
threading.Thread(target=update_loop, daemon=True).start()
|
|
||||||
print("▶ Auto-Start aktiv (gespeicherte Audio-Ein-/Ausgänge)")
|
|
||||||
else:
|
|
||||||
print("⚠️ Auto-Start fehlgeschlagen; bitte Geräte prüfen und manuell starten.")
|
|
||||||
|
|
||||||
print(f"\n🎛️ VU1 Meter Web GUI v3")
|
print(f"\n🎛️ VU1 Meter Web GUI v3")
|
||||||
print(f"{'='*40}")
|
print(f"{'='*40}")
|
||||||
|
|||||||
Reference in New Issue
Block a user