rox

Eine Visualisierung, die im Player wohnt

Die meisten Player geben dir einen Spektrumanalysator und hören da auf. rox hat diese Panels, eine Milkdrop-Engine für zwanzig Jahre Presets, und darunter eine Modulationsschicht: benannte Signale aus dem Audiomaterial, geleitet in Shader-Eingänge, die du selbst schreibst, gespeichert in derselben Datei, in der auch der Rest deines Themes lebt.

Zuerst die gewöhnlichen Panels

Ein Spektrum-Panel mit Balken- oder Blockstilen, Verläufen, Spitzenkappen mit eigener Schwerkraft, Frequenzbeschriftungen und geteilter Zonierung, die ober- und unterhalb einer gewählten Frequenz mit unterschiedlichen Fenstergrößen analysiert, damit jedes Ende des Bereichs Reaktionsfreude gegen Auflösung zu eigenen Bedingungen tauscht. Ein Wellenformstreifen, der den ganzen Titel zeichnet, pro Kanal, und dorthin springt, wo du klickst. Ein VU-Meter. Ein Cover-Regal, das Cover in echtem 3D dreht. Nichts davon braucht eine Zeile Code, und es ist das, was die meisten Leute benutzen werden.

Pausieren friert die Balken dort ein, wo sie waren, statt sie auf den Boden fallen zu lassen. Das klingt nach Kleinigkeit, bis du dir genau den Moment ansehen willst, in dem du pausiert hast.

Milkdrop, in einem Panel und hinter allem

Ein Milkdrop-Panel rendert Presets über libprojectM in einem eigenen Thread und zeichnet das Ergebnis durch dieselbe Shader-Kette wie alles andere. Es dockt, tabt und löst sich also wie jedes andere Panel, und ein Flächen-Shader legt sich genauso darüber. Leg ein Preset-Paket in den Ordner, der auf der Presets-Seite steht, Cream of the Crop oder das originale MilkDrop-Set, und drück auf Neu einlesen. Texturen, die im Paket mitkommen, werden von allein gefunden.

Preset wählen öffnet einen Browser in einem eigenen Fenster: ein Ordnerbaum oder ein Raster aus Vorschaubildern, ein Filter, ein Favoriten-Schalter und Tastaturnavigation. Ein Klick auf ein Preset lädt es sofort hinter dem Fenster, du siehst also das echte Rendering und keine Vorschau. Rotation legt fest, was Weiter, Zurück und der Zeitwechsel durchlaufen, und Sperren hält ein Preset über Titelwechsel hinweg fest.

Dieselbe Engine läuft als Hintergrund hinter jedem Fenster, über das unscharfe Cover gelegt, in einer Stärke, die du wählst. Ein Preset kann seine eigenen Farben behalten, sich für das helle Theme umkehren, in der Palette malen oder die Farbe des laufenden Covers annehmen und dabei seine Details behalten, und eine Album-Tönung schiebt die Farbtöne Richtung Cover. Eine gestoppte Warteschlange blendet es aus, und der Render-Thread hält an, ein untätiges Visual kostet also nichts.

Shader, auf vier Flächen

Ein rox-Shader ist eine WGSL-Fragmentstufe. Er kann über der Fläche eines einzelnen Panels laufen, als eigenes Shader-Panel, als Overlay über dem ganzen Fenster, oder als Hintergrund, der unter allen Panels malt, hinter dem Cover. Overlay und Hintergrund haben je einen Schalter, der sie auf jedes offene rox-Fenster ausdehnt. Dieselbe Sprache, derselbe Uniform-Block, dieselbe Signalführung überall.

Jeder Shader bekommt die Uhr, die Auflösung, den Zeiger und acht Meta-Fließkommawerte, die den Moment beschreiben: Lautstärke, wo der Abspielkopf im Titel steht, ob überhaupt Audio läuft, die Länge des Titels, und wie dunkel die aktuelle Palette rendert, damit ein Shader sich für hell und dunkel passend anziehen kann, statt nur auf dem Theme zu funktionieren, für das er geschrieben wurde.

Ein Panel-Shader kann außerdem lesen, was das Panel tatsächlich gezeichnet hat. Eine Maskenbindung reicht ihm die eigene Zeichnung des Panels, auf Transparenz abgespielt, und Panels veröffentlichen die Form ihres Inhalts, ein Schatten oder ein Leuchten folgt also einem Cover im Letterbox-Format statt den leeren Balken links und rechts davon.

Über eine Stufe hinaus teilt ein // @pass-Kommentar den Text in eine Kette von bis zu acht, von denen jede die vorherigen Durchläufe namentlich lesen kann. Genau das braucht eine Blur-Pyramide oder ein zweistufiges Bloom. Eine // @asset-Zeile benennt ein Bild zum Abtasten, und // @asset art: @cover bindet das Cover des laufenden Titels und bindet neu, wenn der Titel wechselt. Neun Beispiele liegen der App bei, jedes davon führt einen anderen Teil dieses Vertrags vor statt neun Varianten eines Plasmas.

Zeig das Panel auf eine Datei auf der Platte, und rox beobachtet sie. Speichere in deinem Editor, und das Fenster hat es. Ein Speichern, das nicht übersetzt, lässt die letzte funktionierende Fassung auf dem Bildschirm und schreibt den Fehler ins Panel, denn das Bild zu verlieren ist eine schlechte Art herauszufinden, dass du ein Semikolon vertippt hast.

Signale sind der Teil, der anders ist

Ein Shader mit einer Uhr darin ist ein Bildschirmschoner. Zur Visualisierung wird er durch das, womit du ihn fütterst, und in rox ist das ein Pool benannter Signale, den sich die ganze App teilt. Du baust sie in einem eigenen Fenster unter Anwendung, neben dem Equalizer, und es bringt ein Spektrum und einen Transport mit, aus demselben Grund wie der Equalizer: du wählst ein Band mit Auge und Ohr an dem aus, was du tatsächlich abspielst.

Fünf Arten von Quelle. Ein Band ist die Energie zwischen zwei Frequenzen, das Signal, auf dem eine Welle reitet. Pegel ist die ganze Mischung. Ein Onset pulst, wenn ein Band über seinen eigenen jüngsten Durchschnitt springt, das Signal, auf dem ein Schlag reitet. Ein Auslöser pulst, wenn ein Band eine Linie überschreitet, die du gezogen hast, für Material, bei dem der gleitende Durchschnitt nie zum Abfallen kommt und ein Onset nach dem ersten Takt verstummt. Eine Summe zählt ein anderes Signal über die Zeit auf und läuft bei eins über, ein Shader kann sie also als Phase lesen, die vorrückt, solange die Musik laut ist, und stehenbleibt, wenn sie es nicht ist.

Jedes trägt eine Ansprechglättung und ein Gate. Das Gate ist die Einstellung, die sich ihren Platz verdient: ein Band, das auf Raumgeräusch mitreitet, hält jeden daran hängenden Regler für immer ein wenig aus der Ruhelage, und eine Schwelle mit einer Kurve darüber liefert stattdessen zwischen den Schlägen Stille. Das Messwerk zeichnet den ungegateten Wert mit der Schwelle quer darüber, denn ein Balken, der unter seinem eigenen Gate verschwunden ist, wäre beim Setzen des Gates überhaupt keine Hilfe.

Eine Route hängt ein Signal an einen Parameter, mit einem Ausgangsbereich: dieses Signal, dieses Ziel, von hier bis dort. Sechzehn Plätze erreichen jeden Shader, und die Plätze, auf die nichts geleitet ist, bekommen einen einfachen Regler auf der Einstellungsseite, ein Look kann also zur Hälfte von der Musik gespielt und zur Hälfte von Hand gesetzt sein.

Critters, als Argument

Eine der mitgelieferten Arbeitsflächen ist der ganze Player als 1-Bit-Druck: ein geordneter Dither über jeder Fläche, Tonwerte, die mit dem Subbass zusammenbrechen, und eine Rauschwand hinter den Panels, die sich mit dem Song bewegt. Es sind fünf Signale und vier Shader in einer einzigen Datei, und nichts davon ist ein Sonderfall in der App.

Die Critters-Arbeitsfläche von rox: das gesamte Fenster in schwarz-weißem geordnetem Dither, mit einem gebogenen Regal aus Albumcovern über Fortschrittsleiste, Transportzeile, Wellenformstreifen und Titeltabelle, alles auf einem wandernden Rauschfeld.

Lade ihn aus dem Willkommensfenster, öffne dann die Einstellungen und nimm ihn auseinander. Der Rest davon.

Den Shader eines Fremden ausführen

Shader reisen in den Dateien der Arbeitsflächen mit, ein importierter Look kommt also mit dem Code von jemand anderem an.

Nichts läuft, bevor du es sagst. Der Quellcode jedes Shaders bekommt einen Fingerabdruck, und die Freigabeliste ist maschinenlokal und wird nur durch eine direkte Handlung geschrieben: du hast die Datei ausgewählt, du hast neu geladen, du hast eine Vorlage gewählt, du hast Freigeben gedrückt. Ein Look, der in einem Bündel ankam, sitzt bis dahin untätig da, mit einem Knopf darunter. Die Beispiele, die rox mitbringt, sind konstruktionsbedingt vertrauenswürdig, weil sie in die Binärdatei einkompiliert sind.

Eines anzuschalten öffnet ein Bestätigungsfenster, das auf eine Antwort wartet, statt herunterzuzählen, und dieses Fenster wird selbst nie geshadert. Was der Shader auch mit dem Rest des Bildschirms anstellt, der Weg hinaus bleibt lesbar.

Was nicht abgedeckt ist

  • Routen erreichen Shader-Plätze und die Regler des Partikel-Panels. Die Einstellungen jedes anderen Panels sind weiterhin Regler, die du von Hand setzt.
  • Milkdrop-Presets, nicht AVS. Für Winamps AVS gibt es keinen Importer. Und ein Preset ist eine Datei auf deiner Platte, welches geladen ist, bleibt also pro Rechner, statt in einer Arbeitsfläche mitzureisen.
  • Keine MIDI- oder OSC-Steueroberfläche. Der Overlay-Durchlauf und die Panel-Durchläufe sind, was es gibt, angetrieben vom Audiomaterial und vom Zeiger.
  • Ein Durchlauf über das ganze Fenster ist ein echter GPU-Durchlauf pro Bild. Auf einem Laptop im Akkubetrieb ist das eine Entscheidung, die du triffst.

Der Weg von „ich will, dass der ganze Player auf den Kick blitzt“ bis dahin, dass er es tut, sind ein Band, ein Gate und eine Route, und keines der drei braucht einen neuen Build.

Probier es an deiner eigenen Sammlung

Nichts hier telefoniert nach Hause: die Analyse ist das Audiomaterial, das ohnehin durch den Player läuft. Mehr dazu, was eine Arbeitsfläche mit sich trägt.