- C++ 85.3%
- HTML 11.7%
- CMake 3%
MidiInput now wires up all MIDI sources itself -- no `aconnect` needed. At startup it subscribes to every readable source port; while running it rescans once per second and grabs anything newly plugged in (snd_seq_connect_from is idempotent, so already-wired sources just return -EBUSY). Hotplug deliberately does NOT use System:Announce: under PipeWire that stream delivers no PORT_START events (verified with aseqdump), so an announce-based approach silently never fires. The timed rescan is cheap, runs on the existing poll loop's wakeups, and works everywhere. A manual `aconnect` still works but is no longer necessary. Docs updated (README, ARCHITECTURE.md §6c). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|---|---|---|
| cmake | ||
| doc | ||
| include/ui-art-rt | ||
| src | ||
| tests | ||
| .clang-format | ||
| .gitignore | ||
| AGENTS.md | ||
| CMakeLists.txt | ||
| LICENSE | ||
| README.md | ||
ui-art-rt
Eine Spielwiese, um eine Audio-Engine-Architektur auszuprobieren: den Schnitt in drei entkoppelte, über lock-freie Kanäle kommunizierende Schichten.
UI-Thread ──Control/Play (SpscQueue)──▶ ART-Thread ──RT::BlockParameters (PointerExchange)──▶ RT-Thread
(MainLoop) (~1ms Tick) (Audio-Callback)
- UI nimmt User-Input entgegen, editiert
UI::State(viaUI::Processor) und schickt Messages nach ART. - ART (Almost-Realtime) merged Messages + Play-Events, macht Voice-Allocation und
Macro-Modulation und legt pro Zeitscheibe einen kompletten
RT::BlockParametersfür RT ab. - RT (Realtime) läuft im ALSA-Playback-Thread, holt pro Block die neuesten
RT::BlockParameters, smoothed alle Parameter und rendert nahezu branchfrei alle Voices direkt in den ALSA-Puffer.
Der ART/RT-Split ist neu — genau das ist hier der Untersuchungsgegenstand. Die
tragende Idee: jede Voice hält einen eigenen SoundContext-Snapshot, wodurch
„alte Voices spielen alten Stand aus", „Drum-Modus", „Layer/Split" und Live-Preset-Edits
ohne Sonderfälle im Allocator funktionieren.
➡️ Design, Diagramme (UML) und offene Fragen: doc/ARCHITECTURE.md
Layout
include/ui-art-rt/ öffentliche Header, nach Schicht sortiert (lockfree/ model/ art/ rt/ ...)
src/ Implementierungen + main.cpp (verdrahtet die drei Threads)
tests/ Catch2-Unit-Tests (deterministisch, ohne Threads)
doc/ Architektur-Dokumentation mit Diagrammen
Code lesen — wo anfangen?
Der Code ist bewusst so geschrieben, dass man ihn von oben nach unten in dieser Reihenfolge lesen kann; jede Schicht baut auf der vorigen auf:
model/— die Daten:Parameters.h,MacroControls.h,SoundContext.h. Kleine, kommentierte Wert-Typen, kein Threading. Hier anfangen.messages/+Channels.h— was zwischen den Threads fließt und über welche Kanäle.ui/Processor.h— die einfachste der drei Schichten: editieren + Message schicken.art/—VoiceAllocator(welche Voice spielt was) undProcessor(Tick-Schleife).rt/— die anspruchsvollste Schicht.BlockParameters.h(das Datenlayout) zuerst, dannsrc/rt/Processor.cpp(oben steht ein „How to read"-Block zur SIMD-Notation).lockfree/—SpscQueue.hundPointerExchange.h: klein, aber subtil. Zuletzt.
Jede Klasse hat oben einen Kommentar, der ihre Aufgabe und ihren Thread erklärt.
Bauen
Voraussetzung: alsa-lib inkl. Devel (pkg-config alsa) und ein spielbares Audio-Device.
Keine weiteren Abhängigkeiten — die UI ist eine eingebettete Web-App (nur POSIX-Sockets).
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
cmake --build build
Testen
ctest --test-dir build --output-on-failure
Spielen
./build/ui-art-rt-app # startet Engine (live über ALSA) + Web-Server auf Port 8080
Dann im Browser http://localhost:8080 öffnen. Die Seite (eine einzige, selbst-enthaltene
HTML-Datei) bietet Preset-Buttons, Modus-/Unison-Wähler, Slider für Macro A/B und Volume, ein
Pitch-Wheel (federt zurück) und ein Oktav-Keyboard (Maus oder Computertastatur
a w s e d f t g y h u j k; Drücken → Note-On, Loslassen → Note-Off). Der Browser schickt
knappe Text-Kommandos über WebSocket; die App reicht sie an UI::Processor / den Play-Ring
weiter. UIARTRT_LOG=1 loggt die empfangenen Kommandos.
MIDI-Keyboard
Beim Start öffnet die App einen ALSA-Sequencer-Eingang ui-art-rt:input und hängt jede
MIDI-Quelle automatisch an — sowohl beim Start vorhandene als auch später eingesteckte (die App
scannt einmal pro Sekunde nach). Du musst also nichts verbinden: Keyboard einstecken und spielen.
(Ein manuelles aconnect 'Dein Keyboard' ui-art-rt funktioniert weiterhin, ist aber nicht nötig.)
Unterstützt werden Note-On/Off (mit Velocity), Aftertouch (Channel- und Poly-Key- Pressure → öffnet den Filter), Pitch-Bend (±2 Halbtöne) und das Sustain-Pedal (CC 64). MIDI ist optional — ohne Sequencer läuft die App normal mit nur der Web-UI weiter.
Für echte RT-Priorität ohne root: sudo setcap 'cap_sys_nice=eip' ./build/ui-art-rt-app.
Konventionen
Code-Style und Agent-Regeln folgen den NL/C15-Konventionen (.clang-format, AGENTS.md).
Ausnahme in diesem Projekt: ausführliche Kommentare sind ausdrücklich erwünscht, weil es
eine Erkundungs-Spielwiese ist.