Ein Tap mit mutedWhenTapped schaltet die ursprüngliche Ausgabe eines Programms stumm und liefert das Signal stattdessen bei Onyx ab; ein privates Aggregate-Device aus Tap und echtem Ausgabegerät gibt es nach der Verstärkung wieder aus. Das ist der einzige Weg, den macOS ohne eigenen Treiber anbietet. Die Kennlinie ist hergeleitet, nicht geraten: halbe empfundene Lautstärke sind rund −10 dB, also Faktor 0,316. Aus 0,5^k = 0,316 folgt k ≈ 1,66. Die Skala ist damit symmetrisch — 50 % sind −10 dB, 200 % sind +10 dB. Mein erster Ansatz mit der vierten Potenz ergab bei halbem Regler 6 % statt 32 %; der Test hat das gefangen, bevor es an einen Lautsprecher kam. Über 100 % greift ein weicher Begrenzer. Ohne ihn schneidet die Hardware die Werte hart ab, und das knackt hörbar. Er arbeitet erst ab 0,7, weil eine Begrenzung, die schon bei Zimmerlautstärke einsetzt, matt klingt. Der Mixer ist standardmäßig aus, und auch eingeschaltet greift er nur bei ausdrücklich gewählten Programmen ein. Alles andere läuft unverändert vorbei. Der Notausschalter steht sichtbar in der Ansicht, nicht in einem Menü: wenn der Ton weg ist, ist das der Knopf, den man sucht. Drei Fehlerfälle sind eingeplant, weil jeder von ihnen ein stummes Programm bedeutet. Der Wachhund baut Taps neu auf, die nur noch Stille liefern — der bekannte Fall aus Spike C. Ein Wechsel des Ausgabegeräts baut alle Taps neu auf, weil sie am alten Gerät hängen. Und ein fehlgeschlagener Aufbau räumt sich selbst weg, statt in einem halben Zustand zu verharren. Beim Beenden von Onyx wird der Mixer abgebaut: sonst bleiben die abgegriffenen Programme stumm zurück. 178 Tests grün, App-Signatur gültig.
Onyx
Notch-Erweiterung für macOS. Beim Überfahren der Notch fährt ein Panel mit eigenen Widgets aus — Kalender, Wetter, Medien, Hardware, Netzwerk, Audio-Mixer, Ablage und AirDrop.
Zielgerät: MacBook Pro mit Apple Silicon, macOS 26+.
Bauen
xcodegen generate # erzeugt Onyx.xcodeproj aus project.yml
open Onyx.xcodeproj # dann ⌘R
Voraussetzungen: Xcode 26, XcodeGen,
Signierung mit Team PP34X97WS3.
Tests laufen ohne Xcode:
cd Packages/OnyxKit && swift test
Aufbau
Die Projektdefinition liegt als project.yml vor, nicht als handgepflegte
.xcodeproj — so ist im Diff lesbar, was sich an den Build-Einstellungen ändert.
Onyx/ App-Target (nicht sandboxed, Hardened Runtime)
Packages/OnyxKit/ Alle Module als lokales Swift-Package
OnyxCore Einzelinstanz-Sicherung
OnyxDesign Farben, Maße, Bewegung — einzige Quelle
OnyxNotch Panel-Fenster, Geometrie, Zustandsmaschine
OnyxWidgetKit Widget-Protokoll, Layout-Engine, Persistenz
OnyxMenuBar Modul-Protokoll für Menüleisten-Elemente
CalendarProvider EventKit (und später Calendarr)
WeatherProvider WeatherKit + CoreLocation
MediaProvider MediaRemote-Adapter, AppleScript, Medientasten
Vendor/ Fremdcode im Quellzustand (siehe unten)
Spikes/ Wegwerf-Werkzeuge zur API-Verifikation
docs/spikes/ Was dabei herauskam — auch die Sackgassen
Entscheidungen, die man sonst für Fehler hält
Keine App-Sandbox. Sie ist mit dem privilegierten Helper, mit IOKit und mit dem MediaRemote-Adapter unvereinbar. Der App-Group-Container für Calendarr bleibt trotzdem erreichbar — auf macOS ist er von der Sandbox unabhängig. Nachgemessen in docs/spikes/D-appgroup.md.
TCC-Entitlements trotz fehlender Sandbox. Bei aktivierter Hardened Runtime
verlangt macOS com.apple.security.personal-information.* auch ohne Sandbox.
Fehlt eine davon, erscheint der Berechtigungsdialog gar nicht erst — ohne
Fehlermeldung. Das hat einen halben Abend gekostet:
docs/spikes/E-tcc-hardened-runtime.md.
ENABLE_DEBUG_DYLIB = NO. Xcode lagert im Debug-Build den Programmcode in
eine eigene dylib aus. TCC ordnet Berechtigungsanfragen dann dem verbleibenden
Rumpf zu, der weder Info.plist noch Entitlements trägt.
Eigenes Einstellungsfenster. SwiftUIs Settings-Szene öffnet über einen
privaten Selektor, der bei Apps ohne Menüleiste unzuverlässig ankommt.
Der MediaRemote-Adapter wird nicht gelinkt. Er wird von /usr/bin/perl
geladen, einem berechtigten Systemprogramm — im eigenen Prozess greift Apples
Entitlement-Prüfung und es käme nichts an.
Fremdcode
Vendor/mediaremote-adapter — ungive/mediaremote-adapter,
BSD-3-Clause. Als Quellcode eingebettet und beim Bauen kompiliert, nicht als
fertige Binary: so ist nachvollziehbar, was läuft. Stand siehe
ONYX-VERSION.txt.
© 2026 Scarriffleservices