import { useState, useCallback, useRef, useEffect } from "react"; const T = { bg: "#0A0A0C", panel: "#141418", surface: "#1C1C22", border: "#2A2A32", amber: "#E8A030", amberDim: "#7A5218", blue: "#3A7BA8", blueDim: "#1E4060", green: "#3AB87A", red: "#C84040", textPrimary: "#F0EDE6", textSec: "#8888A0", textDim: "#444458", }; async function api(method, path, body) { const opts = { method, headers: { "Content-Type": "application/json" } }; if (body) opts.body = JSON.stringify(body); const res = await fetch(`${path}`, opts); if (!res.ok) throw new Error(`API ${method} ${path}: ${res.status}`); return res.json(); } const SETTINGS = { "Audio": [ { key: "master_volume", label: "Master Volume", type: "slider", min: 0, max: 100, def: 72, unit: "%", icon: "π", via: "volume" }, { key: "sample_rate", label: "Sample Rate", type: "select", def: "48000", options: [ { value: "22050", label: "22.05 kHz" }, { value: "44100", label: "44.1 kHz" }, { value: "48000", label: "48 kHz" }, { value: "88200", label: "88.2 kHz" }, { value: "96000", label: "96 kHz" }, ], icon: "π", via: "audio_profile" }, { key: "buffer_size", label: "Buffer Size", type: "select", def: "512", options: [ { value: "64", label: "64 (1.3ms)" }, { value: "128", label: "128 (2.7ms)" }, { value: "256", label: "256 (5.3ms)" }, { value: "512", label: "512 (10.6ms)" }, { value: "1024",label: "1024 (21.3ms)" }, ], icon: "π¦", via: "audio_profile" }, { key: "input_pad", label: "Input Pad", type: "select", def: "off", options: [ { value: "off", label: "Off (0 dB)" }, { value: "-6", label: "-6 dB" }, { value: "-12", label: "-12 dB" }, { value: "-18", label: "-18 dB" }, ], icon: "π₯", via: "settings" }, { key: "input_impedance", label: "Input Impedance", type: "select", def: "1m", options: [ { value: "1m", label: "1 MΞ©" }, { value: "500k", label: "500 kΞ©" }, { value: "250k", label: "250 kΞ©" }, { value: "150k", label: "150 kΞ©" }, { value: "68k", label: "68 kΞ©" }, ], icon: "β‘", via: "settings" }, ], "Routing": [ { key: "routing_mode", label: "Routing Mode", type: "select", def: "mono", options: [ { value: "mono", label: "Mono" }, { value: "4cm", label: "4CM (Stereo FX Loop)" }, ], icon: "π", via: "routing" }, { key: "routing_breakpoint", label: "FX Loop Breakpoint", type: "select", def: "7", options: [ { value: "1", label: "After block 1" }, { value: "2", label: "After block 2" }, { value: "3", label: "After block 3" }, { value: "4", label: "After block 4" }, { value: "5", label: "After block 5" }, { value: "6", label: "After block 6" }, { value: "7", label: "After block 7" }, { value: "8", label: "After block 8" }, ], icon: "β", via: "routing" }, ], "Audio Interface": [ { key: "input_device", label: "Input Device", type: "select", def: "hw:0,0", options: [ { value: "hw:0,0", label: "Default (hw:0,0)" }, { value: "hw:1,0", label: "USB Audio (hw:1,0)" }, { value: "hw:2,0", label: "HDMI Audio (hw:2,0)" }, ], icon: "π€", via: "settings" }, { key: "output_device", label: "Output Device", type: "select", def: "hw:0,0", options: [ { value: "hw:0,0", label: "Default (hw:0,0)" }, { value: "hw:1,0", label: "USB Audio (hw:1,0)" }, { value: "hw:2,0", label: "HDMI Audio (hw:2,0)" }, ], icon: "π", via: "settings" }, { key: "channel_mode", label: "Channel Mode", type: "select", def: "mono", options: [ { value: "mono", label: "Mono" }, { value: "dual-mono", label: "Dual Mono" }, { value: "stereo_4cm", label: "Stereo (4CM)" }, ], icon: "π", via: "settings" }, ], "MIDI": [ { key: "midi_channel", label: "MIDI Channel", type: "select", def: "omni", options: [ { value: "omni", label: "Omni" }, ...Array.from({ length: 16 }, (_, i) => ({ value: String(i + 1), label: `Channel ${i + 1}` })), ], icon: "πΉ", via: "settings" }, { key: "midi_clock", label: "MIDI Clock", type: "toggle", def: false, via: "settings", icon: "β±" }, { key: "midi_thru", label: "MIDI Thru", type: "toggle", def: true, via: "settings", icon: "β" }, ], "Display": [ { key: "brightness", label: "Display Brightness", type: "slider", min: 1, max: 10, def: 8, unit: "", icon: "βοΈ", via: "settings" }, { key: "auto_dim", label: "Auto Dim", type: "toggle", def: true, via: "settings", icon: "π" }, { key: "screen_saver", label: "Screen Saver", type: "select", def: "5m", options: [ { value: "off", label: "Off" }, { value: "1m", label: "1 min" }, { value: "5m", label: "5 min" }, { value: "15m", label: "15 min" }, { value: "30m", label: "30 min" }, ], icon: "π€", via: "settings" }, ], "Tempo": [ { key: "tap_tempo", label: "Tap Tempo", type: "bpm", def: 120, via: "settings", icon: "π" }, { key: "tempo_division", label: "Tempo Division", type: "select", def: "quarter", options: [ { value: "half", label: "Β½ Note" }, { value: "quarter", label: "ΒΌ Note" }, { value: "eighth", label: "β Note" }, { value: "triplet", label: "β Triplet" }, { value: "sixteenth", label: "ΒΉβββ Note" }, { value: "dotted_eighth", label: "Dotted β " }, ], icon: "πΆ", via: "settings" }, { key: "tap_tempo_mute", label: "Mute on Tap", type: "toggle", def: false, via: "settings", icon: "π" }, ], }; function buildDefaults(overrides = {}) { const init = {}; for (const group of Object.values(SETTINGS)) { for (const s of group) { init[s.key] = s.def; } } return { ...init, ...overrides }; } // ββ Widgets ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ function SettingsSlider({ label, value, min, max, unit, onChange }) { const trackRef = useRef(null); const dragRef = useRef(false); const pct = ((value - min) / (max - min)) * 100; const valFromEvent = useCallback((e) => { const t = trackRef.current; if (!t) return value; const r = t.getBoundingClientRect(); const x = (e.touches ? e.touches[0].clientX : e.clientX) - r.left; return Math.round(min + Math.max(0, Math.min(1, x / r.width)) * (max - min)); }, [min, max, value]); useEffect(() => { const move = (e) => { if (!dragRef.current) return; e.preventDefault(); onChange?.(valFromEvent(e)); }; const up = () => { dragRef.current = false; }; window.addEventListener("mousemove", move); window.addEventListener("mouseup", up); window.addEventListener("touchmove", move, { passive: false }); window.addEventListener("touchend", up); return () => { window.removeEventListener("mousemove", move); window.removeEventListener("mouseup", up); window.removeEventListener("touchmove", move); window.removeEventListener("touchend", up); }; }, [valFromEvent, onChange]); const handleStart = (e) => { e.preventDefault(); dragRef.current = true; onChange?.(valFromEvent(e)); }; const quick = (delta) => (e) => { e.preventDefault(); e.stopPropagation(); onChange?.(Math.max(min, Math.min(max, value + delta))); }; return (