Skip to content

Create Audio API

Taiizor edited this page Jun 19, 2026 · 3 revisions

The Audio API — SucroseAudioData(obj)

Audience: wallpaper creators. This page documents the audio‑reactive JavaScript feed: how to subscribe to it, the FFT spectrum array used for visualizers, and the now‑playing media‑session metadata that accompanies it. The audio feed is delivered only to Web wallpapers running on the WebView or CefSharp engines. To enable it you declare the SystemAudio hook in SucroseCompatible.json — see Create JS Bridge.

Contents

Enabling the audio feed

Add the SystemAudio hook to your wallpaper's SucroseCompatible.json:

{ "SystemAudio": "SucroseAudioData({0});" }

When this hook is non‑empty, the engine enables the Backgroundog audio channel for this wallpaper (AudioRequired = true), starts the live‑data transport, and calls your SucroseAudioData function each time new audio data arrives. The data is captured by the Backgroundog service via WASAPI loopback (the same audio your speakers are playing) and an FFT, then delivered to the engine and pushed into your page with ExecuteScriptAsync. See Backgroundog Service and Create Web Architecture for the full pipeline.

Subscribing in JavaScript

Define a global function whose name matches the template you put in SucroseCompatible.json (the convention is SucroseAudioData):

if (navigator.userAgent.startsWith("Sucrose")) {
  window.SucroseAudioData = function (obj) {
    // obj.Data is the FFT magnitude spectrum
    // obj also carries now-playing metadata (Title, Artist, ...)
    visualize(obj.Data);
  };
}

For a Lively / Wallpaper Engine fallback, feature‑detect window.wallpaperRegisterAudioListener first — see Create Compatibility.

The FFT spectrum (obj.Data)

The most important field is obj.Data:

  • It is a number array — the FFT magnitude spectrum — and it is the field used for visualization.
  • Its length is governed by MaxSample = 128, so expect 128 samples.
  • obj.Data[0] is the lowest band / bass; higher indices are higher frequencies.
  • Silence produces all‑zero (or near‑zero) values. Showcase wallpapers commonly treat obj.Data[0] === 0 as silence and skip animation.

A simple bass reading sums the low bins:

function bassLevel(data) {
  let sum = 0;
  for (let i = 0; i < 8; i++) sum += data[i];
  return sum;
}

Now‑playing metadata fields

Alongside the spectrum, the audio object carries media‑session ("now playing") metadata sourced from the OS:

Field Meaning
State Validity flag for the audio object (boolean).
Title Track title.
Artist Artist.
Subtitle Subtitle.
AlbumTitle Album title.
AlbumArtist Album artist.
AlbumTrackCount Number of tracks on the album.
TrackNumber Current track number.
SourceAppId The app providing the media session.
ThumbnailString Album/track thumbnail (string form).
MediaType Media type.
PlaybackRate Current playback rate.
PlaybackState Playback state.
PlaybackMode Playback mode.
RepeatMode Repeat mode.
ShuffleEnabled Whether shuffle is on.
PropsValid Whether the media‑session properties are valid.

Timing fields

Most timing values are numbers in millisecondsPosition, StartTime, EndTime, MinSeekTime, and MaxSeekTime. The two file-time fields, LastPlayingFileTime and PositionSetFileTime, are instead emitted as ISO 8601 date/time strings, not millisecond numbers.

Field Meaning
Position Current playback position.
StartTime Start time.
EndTime End time (track length).
MinSeekTime Minimum seek time.
MaxSeekTime Maximum seek time.
LastPlayingFileTime Last‑playing file time.
PositionSetFileTime Position‑set file time.

You can build a progress bar from Position and EndTime, and show track info from Title / Artist / AlbumTitle.

Visualizer example

A minimal frequency‑bar visualizer:

let frequencyArray = new Array(128).fill(0);

if (navigator.userAgent.startsWith("Sucrose")) {
  window.SucroseAudioData = function (obj) {
    frequencyArray = obj.Data || frequencyArray;

    // now-playing display
    if (obj.State) {
      document.getElementById("title").textContent  = obj.Title  || "";
      document.getElementById("artist").textContent = obj.Artist || "";
    }
  };
}

function render() {
  const silent = frequencyArray[0] === 0;
  if (!silent) {
    for (let i = 0; i < frequencyArray.length; i++) {
      drawBar(i, frequencyArray[i]);   // frequencyArray[0] ~ bass
    }
  }
  requestAnimationFrame(render);
}
render();

Notes and gotchas

  • The audio feed only reaches Web wallpapers on WebView/CefSharp — no audio data for MpvPlayer/VlcPlayer/Nebula/Vexana/Xavier/Aurora.
  • obj.Data length is 128; obj.Data[0] ≈ bass; all‑zero means silence.
  • Audio is captured from WASAPI loopback — it reflects what is actually playing on the system's default output, not microphone input.
  • Read obj.State to confirm the now‑playing metadata is valid before displaying it.
  • The data arrives on a timer from the Backgroundog service; treat each call as a fresh snapshot and avoid heavy synchronous work inside SucroseAudioData (drive your animation from requestAnimationFrame, as above).

See also

Home

Getting Started

Wallpaper Types

Using Sucrose

Settings Reference

Creating Wallpapers

Engine Reference

Automation & Command Line

Architecture & Internals

Data, Files & Diagnostics

Building & Contributing

Help & Support

Clone this wiki locally