NodeWorld

Des mondes qui réagissent à la musique avec Pulse

Depuis SDK 0.2.1

Pulse écoute la musique de ton monde et la transforme en valeurs que tes shaders lisent à chaque image : le niveau de quatre bandes (des basses aux aigus) et leurs 1,4 dernières secondes, le spectre, des niveaux lissés, un temps musical qui avance plus vite sur les temps forts, et quatre couleurs tirées des notes qui dominent. Le paquet a aussi une tablette que les joueurs prennent en main pour tout régler pendant la soirée.

C’est le paquet Unity NodeWorld Pulse (com.nodeworld.pulse), sous licence MIT. Il demande NodeWorld SDK Worlds, qu’il apporte.

Ajouter le paquet

  1. Ajoute le registre NodeWorld à ton projet, comme pour le SDK (installer le SDK).
  2. Ouvre Window, Package Manager, choisis My Registries, sélectionne NodeWorld Pulse, puis Install.
  3. Dans le NW World Config de ton monde, ajoute à Flux Sharp Sources les sept scripts de Packages/com.nodeworld.pulse/Runtime/Flux/ (dans la fenêtre Project, ils sont sous Packages, NodeWorld Pulse, Runtime, Flux) : PulseAudio, PulseTablet, PulseHandle, PulseSharedSlider, PulseSharedToggle, PulseThemeColors, PulseLabels.

Brancher la musique

  1. Glisse le prefab Pulse (Packages, NodeWorld Pulse, Runtime, Prefabs) dans ta scène. Il porte le moteur : un composant FL# Script de classe Pulse.PulseAudio.
  2. Dans son champ source, mets l’Audio Source qui joue ta musique : une enceinte de la scène, ou la sortie son d’un écran vidéo.

Pulse lit ce que joue la source, quel que soit son volume : un joueur qui baisse la musique voit toujours les lumières réagir. Quand la source se tait ou s’arrête, toutes les valeurs retombent à 0.

Un seul moteur par monde suffit : tous les shaders de la scène lisent les mêmes valeurs.

Poser la tablette dans le monde

  1. Glisse le prefab PulseTablet dans ta scène et place-le : son socle se pose sur une table, à environ 1 m du sol.
  2. Sur la racine du prefab, le FL# Script de classe Pulse.PulseTablet a un champ pulse : mets-y l’objet Pulse de ta scène.

La tablette reste sur son socle jusqu’à ce qu’on la prenne. Un joueur la prend par une des deux poignées du bas, ou par les deux, une dans chaque main ; lâchée, elle reste là où elle est. Sa place est la même pour tous les joueurs.

Ce que fait l’écran :

À l’écranCe que ça règle
Bandes : les quatre colonnes de couleurTire le bouton blanc en haut d’une colonne : le seuil de la bande. Une bande au-dessus de son seuil allume son bouton.
Bandes : le rail sous les colonnesTire un bouton : là où une bande s’arrête et où la suivante commence sur le spectre.
Signal : GainLe niveau auquel la musique est lue. Le petit repère au milieu est le niveau normal ; tout à droite, il est doublé.
Signal : FonduLe temps que met une bande à retomber après un coup.
Signal : CourbeLa forme de cette retombée.
Signal : Gain automatiqueSuit tout seul le volume de la musique.
Le bouton rond en haut à gaucheAllume ou éteint l’analyse : éteinte, tes shaders voient la musique arrêtée.
Le bouton rond en bas à gaucheRemet les réglages et les couleurs comme au chargement du monde (le bouton marche ne change pas).
Couleurs : les quatre pastilles rondesChoisis-en une, puis règle-la avec les curseurs de teinte, de saturation et de luminosité en dessous. Choisir ou régler une pastille coupe Auto.
Couleurs : AutoLes quatre couleurs suivent les notes de la musique au lieu des pastilles.

La carte du bas montre les 1,4 dernières secondes de chaque bande (quatre rangées de points, le présent à droite) et, en dessous, une onde qui grandit avec la musique.

Les textes de l’écran suivent la langue du jeu de chaque joueur (français ou anglais).

Qui règle quoi

Les réglages sont partagés : quand un joueur bouge un curseur, toute l’instance voit et entend la même chose. Le champ controllerSyncMode de Pulse.PulseTablet choisit ce qui est partagé :

controllerSyncModePartagé avec l’instance
0 (par défaut)tout
1tout sauf le bouton marche
2tout sauf le bouton marche et Gain
3rien : chaque joueur règle pour lui

Lire la musique dans un shader

Inclus Pulse.cginc du paquet, puis lis les valeurs. Un shader complet, à enregistrer dans un fichier .shader de ton projet : la première couleur de la musique brille avec les basses.

hlsl
Shader "MyWorld/Pulse Glow"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Glow ("Glow", Range(0, 4)) = 1
    }
    SubShader
    {
        Tags { "RenderType" = "Opaque" }
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            #include "Packages/com.nodeworld.pulse/Runtime/Shaders/Pulse.cginc"

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _Glow;

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                UNITY_VERTEX_INPUT_INSTANCE_ID
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
                UNITY_VERTEX_OUTPUT_STEREO
            };

            v2f vert (appdata v)
            {
                v2f o;
                UNITY_SETUP_INSTANCE_ID(v);
                UNITY_INITIALIZE_OUTPUT(v2f, o);
                UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            float4 frag (v2f i) : SV_Target
            {
                float4 col = tex2D(_MainTex, i.uv);
                if (PulseIsOn())
                    col.rgb += PulseThemeColor(0) * PulseSmooth(0, 8) * _Glow;   // la première couleur de la musique, avec les basses lissées
                return col;
            }
            ENDCG
        }
    }
}
FonctionCe qu’elle rend
PulseIsAvailable()true dès que le moteur tourne dans le monde. Dans l’éditeur Unity hors Play mode, elle rend false et toutes les fonctions rendent 0.
PulseIsOn()true quand le moteur tourne et que l’analyse est allumée (bouton marche de la tablette).
PulseBand(band, delay)Le niveau d’une bande (0 basses, 1 bas médiums, 2 hauts médiums, 3 aigus), de 0 à 1, il y a delay pas de 1/90 s (0 maintenant, jusqu’à 127 : 1,41 s).
PulseSmooth(band, smoothing)Le niveau d’une bande, lissé : de 0 très lisse (il reste 0,55 d’un changement au bout d’une seconde) à 15 vif.
PulseChrono(mode, band, wrap)Un temps musical (mode de 0 à 7) qui avance plus vite quand la bande est forte. wrap vaut 14400000 ou 628319 : la valeur repart de 0 à ce nombre.
PulseThemeColor(i)La couleur i (0 à 3) : les notes qui dominent la musique, ou les pastilles de la tablette.
PulsePhase()Où en est l’horloge à 90 Hz de l’historique entre deux pas (0 à 1) : pour lire l’historique au même endroit d’une image à l’autre.
PulseData(xy)Le texel brut (x, y) de la texture de données (tableau ci-dessous).
PulseLerp(xy)Pareil, entre deux texels d’une ligne (x avec une partie décimale).

La texture de données

Le moteur calcule à chaque image la texture globale _PulseTex (128 × 32 flottants) sur la carte graphique, comme AudioLink : son script envoie seulement les échantillons de la musique et les réglages. Les bandes, les couleurs de thème et l’autocorrélation suivent les notes avec une image de retard. Ses places, en #define dans Pulse.cginc :

PlaceContenu
PULSE_POS_BANDS (lignes 0 à 3)La bande b sur la ligne b ; x = retard en pas de 1/90 s ; r = niveau.
PULSE_POS_SPECTRUM (lignes 4 et 5)La note n (0 à 239, 24 par octave depuis 13,75 Hz) en (n % 128, 4 + n / 128) ; r brut, g filtré et égalisé, b filtré.
PULSE_POS_THEME (ligne 23, x de 0 à 3)Les quatre couleurs de thème (rgb).
PULSE_POS_PHASE (23, x 4)r = phase de l’horloge de l’historique.
PULSE_POS_STATE (23, x 5)r = 1 analyse allumée, 0 éteinte.
PULSE_POS_AUTOCORR (ligne 27)Autocorrélation du spectre (r).
PULSE_POS_SMOOTH (lignes 28 à 31, x de 0 à 15)La bande b sur la ligne 28 + b ; x = lissage ; r = niveau.
PULSE_POS_CHRONO (lignes 28 à 31, x de 16 à 23)La bande b sur la ligne 28 + b ; x = 16 + mode ; r = temps modulo 14 400 000, g = modulo 628 319.
PULSE_POS_VU (28, x de 24 à 27)Niveau RMS, quatre vitesses (r).

Les champs du moteur

Le FL# Script du prefab Pulse (Pulse.PulseAudio) démarre avec ces valeurs ; la tablette les change pendant la partie.

ChampCe qu’il fait
sourceL’Audio Source de la musique.
engineLa custom render texture PulseEngine du paquet (Runtime/Textures), déjà mise dans le prefab : la carte graphique y calcule _PulseTex.
gainNiveau d’entrée (1 par défaut).
bass, treblePoids des notes graves et aiguës du spectre (1 par défaut).
x0 à x3Où chaque bande commence sur le spectre.
threshold0 à threshold3Seuil de chaque bande.
fadeLength, fadeExpFalloffCombien de temps et avec quelle courbe une bande retombe.
autogain, autogainDerateGain automatique, et combien il se retient.
actifAnalyse allumée (true) ou éteinte.
themeColorMode, customThemeColor0 à customThemeColor30 : couleurs des notes ; 1 : les quatre couleurs choisies.

Licence

Le paquet est sous licence MIT. Son LICENSE.md contient aussi les notices du code dont il dérive (MIT) et de sa police, Geist (SIL Open Font License).