Skip to content

Theme Format

Synssins edited this page Oct 12, 2026 · 2 revisions

Theme Format

This page describes the files that make up a Sonorium theme, so you can build one by hand, from an empty folder, and add it to Sonorium. It matches Sonorium 1.7.1.

The full technical specification, with the exact mixer maths, is docs/THEME_FORMAT.md in the repository.


What a theme is

A theme is a folder. The audio files in it are the sounds; two JSON files say how each sound plays. Think of it as a mixing desk packed in a box: the audio files are the instruments, metadata.json is the desk's settings, and presets.json holds saved settings you can switch between.

Thunderstorm/                  <- the theme folder
  metadata.json                <- theme info, track settings, group settings
  presets.json                 <- presets and sequences
  Rain.wav                     <- a track
  Gusts.wav                    <- a track
  Wind/                        <- a group
    Wind 1.wav                 <- a track in the group
    Wind 2.wav
  ATTRIBUTION.md               <- optional: credits, for people
  MANIFEST.json                <- optional: source and licence, for tools
File Required What it is
Audio files Yes, at least one The sounds. A folder with no audio file is not listed as a theme.
metadata.json No, but write it Name, description, icon and how every track and group plays. Without it Sonorium makes one with defaults.
presets.json No Presets and sequences.
MANIFEST.json No Source and licence details. Sonorium's mixer doesn't read it.
ATTRIBUTION.md No Credits for the sounds, in plain text. Sonorium's mixer doesn't read it.

All JSON files are UTF-8 text. Write non-English characters, emoji included, as \uXXXX escapes ("🔥" for 🔥): every install reads those correctly.

Where themes live

Every theme is one folder inside Sonorium's audio folder.

Install Audio folder
Home Assistant app /media/sonorium (the media share, folder sonorium)
Docker /media/sonorium inside the container: the host folder you mapped to it (./sonorium/media in the Getting Started compose file)
Windows app The themes folder next to Sonorium.exe

Audio files

Rule Detail
Formats .mp3, .wav, .flac, .ogg (upper or lower case)
Best format 44.1 kHz mono. Sonorium mixes in 44.1 kHz mono: other rates are resampled and stereo is mixed down to mono as the file is read.
Where At the top of the theme folder, or in a group folder one level down. Files deeper than that are not found.
Ignored Files and folders whose name starts with . or _ (useful for drafts: _drafts/).
Order Top-level files sorted by name, then each group (sorted by name) with its files sorted by name.

Track keys

Each track is known by its key: its path inside the theme without the extension, with / between group and file.

File Key
Rain.wav Rain
Wind/Wind 1.wav Wind/Wind 1

Keys are what metadata.json and presets.json use to name tracks. The web UI shows only the part after the /. Two files with the same name and different extensions in one folder (Rain.wav and Rain.mp3) get the same key: give each file a different name.

Folder names

  • Theme folder: any name not starting with .. It is the theme's name when metadata.json gives none.
  • Group folder: at most 60 characters; not / \ : * ? " < > |; not starting with . or _; not ending with . or a space. The folder name is the group's name.

metadata.json

{
  "spec_version": 2,
  "id": "c3a9e1f0-5d2b-4f6a-8e47-1b9d0c7a2e58",
  "name": "Thunderstorm",
  "description": "Rain and wind, with thunder rolling in.",
  "icon": "⛈️",
  "categories": ["Weather"],
  "ebb_duration": true,
  "intrusions_retired": true,
  "auto_retired": true,
  "tracks": { "Rain": { "playback_mode": "continuous", "volume": 0.7 } },
  "groups": {}
}

Theme fields

Field Type Required Default What it does
spec_version integer Yes: write 2 2 The file layout version. Missing or below 2 marks an older theme, which Sonorium converts when it loads it (see What Sonorium does when it loads a theme).
id string Recommended A new random UUID, saved on first load The theme's permanent ID. Channels, playlists and linked files find the theme by it, so renaming the folder keeps them working. Make one with any UUID tool (python -c "import uuid; print(uuid.uuid4())"); every theme needs its own. Import theme gives the imported theme a new one.
name string No The folder name The name shown in Sonorium.
description string No "" Shown under the name.
icon string No "" One emoji. Empty: Sonorium picks one from the theme's name.
is_favorite true/false No false Listed under Favorites.
categories list of strings No [] Category names. A category that doesn't exist yet is listed once a theme uses it.
short_file_threshold number, seconds No 15 (Settings › Advanced) Only used for tracks without a playback_mode (see auto below).
tracks object No {} Settings per track, by key. A track without an entry uses every default.
groups object No {} Settings per group, by group name.
links object No none Files used from other themes (see Linked files).
attribution object No none Source and licence (see attribution).
ebb_duration, intrusions_retired, auto_retired true/false Yes for a new theme: write true false Marks that the three one-time conversions for older themes are done. Without "ebb_duration": true, Sonorium reads your Ebb & Flow Duration values as the old Interval and turns them around (0.3 becomes 0.7) the first time it loads the theme.

Track settings

Each entry in tracks holds any of these fields. Leave a field out to use its default.

Field Type, range Default What it does
playback_mode "continuous", "sparse", "presence", "unassigned" "auto" How the track plays: see Playback modes. Always write it.
volume 0.0 to 1.0 1.0 The track's level (1.0 is the file as it is). For Ebb & Flow, the top of the Volume range.
presence 0.0 to 1.0 1.0 Interval for Intermittent, Duration for Ebb & Flow, the chance of being picked in a group (see the modes).
muted true/false false Leaves the track out of the mix.
seamless_loop true/false false Gapless: a Background track loops with a hard cut instead of a 1.5 s crossfade. Only for files cut to loop perfectly.
fade_in, fade_out 0 to 30 seconds 0 (off) Fade in / Fade out: the file fades in each time it starts and out each time it ends, loops included. For files that start or end abruptly.
volume_low 0.0 to 1.0 0.2 Ebb & Flow: the bottom of the Volume range. The level moves between volume_low and volume.
rise 0.0 to 1.0 0.0 Ebb & Flow Rise: how fast the level climbs, from 0 (Gradual) to 1 (Sudden).
pause_between true/false false Ebb & Flow Pause between plays: the file plays once from start to end, fades out, pauses, then comes back.
pause_min, pause_max seconds, 0 or more 30, 300 Ebb & Flow Pause: each pause is a random time in this range. It also staggers the first start.
exclusive true/false false One at a time (legacy), from themes made before groups. Use a group instead.

Playback modes

playback_mode In the web UI What you hear presence means
"continuous" Background Plays all the time, looping smoothly. Rain, wind, a fire. Not used.
"sparse" Intermittent Plays the whole file once, then stays quiet before playing again. Bird calls, a door. Interval: the wait between plays. 1.0 waits about 3 minutes, 0.0 about 30 minutes, each wait 30 % shorter or longer at random. These are the defaults of Wait between plays and Wait randomness on Settings › Advanced.
"presence" Ebb & Flow Always heard, the level drifting up and down between volume_low and volume. Surf, gusting wind. Duration: how long the level stays at each value; higher is longer.
"unassigned" Unassigned Nothing. The track waits to be placed. Not used.
"auto" (none) The default for a track without a mode, decided by the file's length when it starts: at presence 1.0 Background; below 1.0, files shorter than short_file_threshold play Intermittent, longer ones Ebb & Flow. Write a real mode instead. Depends on the mode it becomes.

A track inside a group plays the group's way, whatever its own playback_mode. Its volume and presence still count (see below).

Groups

A subfolder with audio in it is a group. Its entry in groups (keyed by the folder name) sets how its tracks play together. A group without an entry is an Intermittent group with the defaults.

mode In the web UI What you hear
"intermittent" (or missing) Intermittent group, in the Intermittent section One track at a time, never overlapping. A track plays its whole file once; then the group waits for the Gap and picks the next one. The same track never plays twice in a row, and a track that just played is less likely to be picked next.
"merry_go_round" Merry-go-round, in the Background section One continuous bed: one file plays, then crossfades into another picked at random. A group with one file crossfades into itself.
"ebb_flow" Ebb & Flow group, in the Ebb & Flow section Every file plays at once, each rising and falling between its own volume_low and volume.

"intrusion" is a retired mode: Sonorium converts such groups when it loads the theme.

Group field Type, range Default Applies to What it does
mode see above "intermittent" all How the group plays.
volume 0.0 to 1.0 1.0 all Group Volume: multiplies each track's own volume.
presence 0.0 to 1.0 1.0 all Group Interval or Duration: multiplies each track's own presence.
muted true/false false all Mutes every track in the group.
gap_min, gap_max seconds, 0 or more 120 each (Settings › Advanced) Intermittent Gap: after a track finishes, the group waits a random time in this range. The web UI shows it in minutes. With only one of the two set, it is used for both.
crossfade seconds, 1 to 60 10 Merry-go-round Crossfade: the overlap between one file and the next. A short file gets a shorter crossfade (at most half its length).
pause_between true/false false Ebb & Flow Pause between plays for the whole group: every file pauses between plays, at staggered times, so at least one is always playing.
rise 0.0 to 1.0 none Ebb & Flow Same Rise for every file: one Rise for the whole group instead of each file's own. Leave it out to use each file's own.

A group works like a submix fader on a mixing desk: its volume and presence scale its tracks' own values. A track at 0.5 in a group at 0.5 plays at 0.25.

In an Intermittent group or a Merry-go-round, each track's presence is its chance of being picked: with four tracks at 1.0, 1.0, 1.0 and 0.2, the 0.2 track plays about one turn in ten. In a Merry-go-round, a track at 0 (or muted) is never picked.

Linked files

A linked file is an audio file of another theme, used by this theme without a copy. It is listed in links and has its own entry in tracks like any other track:

"links": {
  "Crickets": { "theme": "0b6f2d4e-7a51-4c3e-9d27-5e8a1f3c9b62", "track": "Crickets" },
  "Night/Owl": { "theme": "0b6f2d4e-7a51-4c3e-9d27-5e8a1f3c9b62", "track": "Owl" }
},
"tracks": {
  "Crickets": { "playback_mode": "sparse", "muted": true }
}
Part Rule
Key "<name>" for an ungrouped link, "<group>/<name>" for one in a group. It must not be the key of a file of this theme.
theme The source theme's id (from its metadata.json).
track The source track's key. Only real files can be linked, not another theme's links.
Missing source The link is kept and shown as Missing; it doesn't play.
Export Export copies linked files into the zip as normal files, so an exported theme works without the theme it linked from.

Since a link points at a theme id, it only works on the install that has that theme. To share a theme with a linked file, export it from Sonorium, or copy the file in.

attribution

Optional. Shown to people who look at the theme's source. Any of:

Field Example
source "Recorded by the theme author"
source_url The page the sounds came from
license "CC BY 4.0"
license_url "https://creativecommons.org/licenses/by/4.0/"
imported_date ISO 8601 time, for a tool that made the theme
imported_by The tool that made the theme

Fields Sonorium keeps

The first time Sonorium saves the theme (any change in the editor, an import, a conversion), it rewrites metadata.json with every field listed above, defaults filled in. Any other field at the top level, or inside a track entry, is dropped. Unknown fields inside a group entry and inside presets.json are kept.


presets.json

{
  "presets": {
    "<preset id>": { "name": "...", "is_default": true, "tracks": {}, "groups": {} }
  },
  "sequence_defaults": { "hold_min": 300, "hold_max": 900, "ramp": 30 },
  "sequences": {}
}

Presets

A preset is a saved version of the theme's mix: the same storm with the thunder off, or with the rain louder. A channel playing a preset hears the theme's own settings with the preset's values on top. A field the preset leaves out follows the theme.

Field Type Required What it does
Preset ID (the key) string Yes Lower-case letters, digits and _. Sonorium makes IDs from the name the same way: "Full storm" becomes full_storm.
name string Yes Shown in preset lists.
is_default true/false No The default preset, marked ★: picked when a channel chooses the theme. Mark one preset; if several are marked, the first in the file wins.
tracks object No Per track key: any of volume, presence, muted, playback_mode, seamless_loop, exclusive, volume_low, pause_between, pause_min, pause_max, with the ranges in Track settings.
groups object No Per group name: any of volume, presence, muted, gap_min, gap_max, pause_between, rise. A group's mode and crossfade belong to the theme and can't be set by a preset.

When a channel switches preset, volumes and intervals glide to the new values over 3 seconds, and tracks the preset turns on or off fade in or out over 3 seconds. A new playback_mode or seamless_loop is heard the next time the theme starts.

A preset made in the web UI lists every track with every field, so it doesn't depend on the theme's settings. By hand, listing only what changes is enough; listing everything protects the preset from later changes to the theme.

Sequences

A sequence plays some of the theme's presets in order on a channel, gliding from one to the next: drizzle, then rain, then a downpour. It is listed with the presets, marked with the sequence icon.

Field Type, range Default What it does
sequence_defaults.hold_min, .hold_max seconds, 0 to 604800 300, 900 The theme's Time on each preset: each preset plays for a random time in this range.
sequence_defaults.ramp seconds, 0 to 604800 30 The theme's Ramp: how long the glide to the next preset lasts.
Sequence ID (the key) string Made like a preset ID.
name string, 1 to 100 characters required Shown with the presets. Unique in the theme.
presets list of preset IDs required The presets, in play order. Presets not listed are never reached.
at_end "reverse", "restart", "stop" "reverse" At the end: Reverse plays the list backwards (1 2 3 2 1 2 …), Start again goes back to the first preset, Stop stays on the last one.
hold_min, hold_max, ramp seconds, or null null The sequence's own timing. null uses sequence_defaults. hold_min must not be above hold_max.
owner null null Write null.
while object none While playing changes per step (below).
transitions object none Coming in / Leaving styles per step (below).

While playing

Changes how tracks play while one step plays, for this sequence only, on top of that step's preset. Keyed by preset ID:

"while": {
  "full_storm": {
    "tracks": { "Rain": { "volume": 0.9 } },
    "groups": { "Thunder": { "gap_min": 30, "gap_max": 90 } }
  }
}
Part Fields
tracks Per track key: any of volume, volume_low, presence, muted, pause_between, pause_min, pause_max.
groups Per group name: any of volume, presence, muted, gap_min, gap_max, pause_between, rise.

A field left out (or null) keeps the preset's value.

Coming in and Leaving

How tracks change at a step, keyed by preset ID. in holds the tracks this step turns on or makes louder (Coming in); out the tracks the next step turns off or makes quieter (Leaving).

"transitions": {
  "full_storm": {
    "in":  { "Thunder/Thunder 1": { "styles": ["dist"], "values": { "dist": 70 }, "pre_fade": 20 } },
    "out": { "Gusts": { "styles": ["swell"], "values": { "swell": 20 }, "pre_fade": 0 } }
  }
}
Style Coming in Leaving values entry
gusts Gusts Gusts dying down Intensity, 0 to 100 (default 50)
swell Swell Smooth fade Speed: seconds of the fade time it uses (default 20)
build Build Thin out Amount, 0 to 100 (default 60). For Intermittent tracks.
dist Distance Recede How far, 0 to 100 (default 50)
fresh Start fresh Finish then stop none
Field Type, range What it does
styles list of the style keys Any combination. An empty list with pre_fade 0 is Smooth: the track follows the ramp.
values object The setting of each style that has one.
max_volume 0.0 to 1.0, optional Gusts: the peaks never go above this.
pre_fade 0 to 90 seconds Pre-fade: the change starts this long before the step. The fade time is pre-fade plus ramp.

The web UI and the API refuse values outside these ranges. Sonorium doesn't check a hand-written presets.json the same way, so keep every value inside its range.


MANIFEST.json and ATTRIBUTION.md

Both are optional and travel with the theme in exports. Sonorium's mixer reads neither.

ATTRIBUTION.md is for people: where the sounds come from, the licence and what it allows, and credits per file.

MANIFEST.json is for tools. The bundled themes use this shape:

{
  "source":  { "site": "", "url": "", "creator": "The theme author" },
  "license": { "name": "CC BY 4.0", "url": "https://creativecommons.org/licenses/by/4.0/", "requires_attribution": true }
}
Field What it is
source.site, source.url, source.creator Where the sounds come from and who made them
license.name, license.url The licence
license.requires_attribution true when anyone sharing the sounds must credit the source

What Sonorium does when it loads a theme

Sonorium loads every theme when it starts, after Refresh on the Themes page, and after an import.

Older layouts are converted

Each conversion runs once per theme and first copies metadata.json and presets.json to backup files next to them:

Found What Sonorium does Backup
spec_version missing or below 2, or presets inside metadata.json Moves the presets to presets.json and writes "spec_version": 2 metadata.json.pre-presets.bak
No "ebb_duration": true Turns every Ebb & Flow presence around (0.3 becomes 0.7), in the theme and its presets *.pre-duration.bak
A group with "mode": "intrusion" Ungroups its linked files and removes the group; its own files move to the theme folder *.pre-links.bak
A track with "playback_mode": "auto" (and no "auto_retired": true) Gives it the mode it plays as *.pre-auto.bak

A theme written as described on this page (spec_version 2, the three markers true, a mode on every track) needs none of these, and no backup files appear.

Broken files are set aside

A metadata.json or presets.json that isn't valid JSON is renamed to <name>.broken-<date>-<time> and replaced:

  • metadata.json is rebuilt with default settings for every track, keeping the id if it can still be read.
  • presets.json is refilled from metadata.json.pre-presets.bak if that holds presets, otherwise left empty.

The theme still loads and plays. Fix the .broken file and copy it back over the new one.

Where to see problems

Sonorium writes what it did to its log. To read it:

  1. Click Settings in the menu.
  2. Click Logs.

Lines to look for:

Theme 'Broken': can't read metadata.json (line 1): Illegal trailing comma before end of object, kept as metadata.json.broken-20261012-112248. Using defaults
Theme 'Old' converted to the 2.0 format
Theme 'Old': Ebb & Flow Interval values converted to Duration (originals kept as *.pre-duration.bak)
Theme 'Old': Auto playback modes replaced by the mode each track plays as (originals kept as *.pre-auto.bak)
Imported theme 'Thunderstorm' with 12 files

The API lists the same problems per theme: GET /api/themes gives each theme a "problems" list, empty when it loaded cleanly.

Ignored

  • Files and folders starting with . or _, and folders more than one level deep.
  • Entries in tracks whose key matches no file or link (kept in the file, not used).
  • Sequence steps that name a preset that doesn't exist.

Example 1: a minimal theme

Two tracks and one preset: a fire that plays all the time and crickets now and then.

Campfire/
  metadata.json
  presets.json
  Fire.wav
  Crickets.wav

metadata.json:

{
  "spec_version": 2,
  "id": "0b6f2d4e-7a51-4c3e-9d27-5e8a1f3c9b62",
  "name": "Campfire",
  "description": "A fire crackling, crickets now and then.",
  "icon": "🔥",
  "categories": ["Nature"],
  "ebb_duration": true,
  "intrusions_retired": true,
  "auto_retired": true,
  "tracks": {
    "Fire":     { "playback_mode": "continuous", "volume": 0.8 },
    "Crickets": { "playback_mode": "sparse", "volume": 0.5, "presence": 0.6 }
  }
}

presets.json:

{
  "presets": {
    "late_night": {
      "name": "Late night",
      "is_default": true,
      "tracks": {
        "Fire":     { "volume": 0.5 },
        "Crickets": { "volume": 0.7, "presence": 0.9 }
      }
    }
  }
}

Without a preset, the fire plays at 80 % and the crickets about every 10 to 18 minutes. Late night (the default) turns the fire down and brings the crickets back about every 4 to 7 minutes. Replace the id with a new UUID of your own.


Example 2: a fuller theme

Rain all the time, a Merry-go-round of wind, thunder in an Intermittent group, drips now and then, and gusts that rise and fall. Two presets and a sequence that moves between them.

Thunderstorm/
  metadata.json
  presets.json
  ATTRIBUTION.md
  MANIFEST.json
  Rain.wav                 Background
  Drips.wav                Intermittent
  Gusts.wav                Ebb & Flow, with Pause between plays
  Wind/                    Merry-go-round group
    Wind 1.wav
    Wind 2.wav
    Wind 3.wav
  Thunder/                 Intermittent group
    Thunder 1.wav
    Thunder 2.wav

metadata.json:

{
  "spec_version": 2,
  "id": "c3a9e1f0-5d2b-4f6a-8e47-1b9d0c7a2e58",
  "name": "Thunderstorm",
  "description": "Rain and wind, with thunder rolling in.",
  "icon": "⛈️",
  "categories": ["Weather"],
  "short_file_threshold": 15.0,
  "ebb_duration": true,
  "intrusions_retired": true,
  "auto_retired": true,
  "tracks": {
    "Rain":  { "playback_mode": "continuous", "volume": 0.7 },
    "Drips": { "playback_mode": "sparse", "volume": 0.4, "presence": 0.8, "fade_in": 0.5, "fade_out": 0.5 },
    "Gusts": { "playback_mode": "presence", "volume": 0.9, "volume_low": 0.2, "presence": 0.4, "rise": 0.7,
               "pause_between": true, "pause_min": 20, "pause_max": 90 },
    "Wind/Wind 1": { "playback_mode": "continuous", "volume": 1.0, "presence": 1.0 },
    "Wind/Wind 2": { "playback_mode": "continuous", "volume": 0.9, "presence": 1.0 },
    "Wind/Wind 3": { "playback_mode": "continuous", "volume": 1.0, "presence": 0.5 },
    "Thunder/Thunder 1": { "playback_mode": "sparse", "volume": 1.0, "presence": 1.0 },
    "Thunder/Thunder 2": { "playback_mode": "sparse", "volume": 0.8, "presence": 0.6 }
  },
  "groups": {
    "Wind":    { "mode": "merry_go_round", "crossfade": 8, "volume": 0.6 },
    "Thunder": { "mode": "intermittent", "gap_min": 60, "gap_max": 240, "volume": 0.9, "presence": 1.0 }
  },
  "attribution": {
    "source": "Recorded by the theme author",
    "license": "CC BY 4.0",
    "license_url": "https://creativecommons.org/licenses/by/4.0/"
  }
}

presets.json:

{
  "presets": {
    "light_rain": {
      "name": "Light rain",
      "is_default": true,
      "tracks": {
        "Rain":  { "volume": 0.5, "muted": false },
        "Drips": { "muted": false },
        "Gusts": { "muted": true },
        "Thunder/Thunder 1": { "muted": true },
        "Thunder/Thunder 2": { "muted": true }
      },
      "groups": {
        "Wind":    { "volume": 0.3, "muted": false },
        "Thunder": { "muted": true }
      }
    },
    "full_storm": {
      "name": "Full storm",
      "is_default": false,
      "tracks": {
        "Rain":  { "volume": 1.0, "muted": false },
        "Drips": { "muted": true },
        "Gusts": { "muted": false, "volume": 1.0, "volume_low": 0.4 },
        "Thunder/Thunder 1": { "muted": false },
        "Thunder/Thunder 2": { "muted": false }
      },
      "groups": {
        "Wind":    { "volume": 0.8, "muted": false },
        "Thunder": { "muted": false, "gap_min": 30, "gap_max": 120 }
      }
    }
  },
  "sequence_defaults": { "hold_min": 300, "hold_max": 900, "ramp": 30 },
  "sequences": {
    "storm_builds": {
      "name": "Storm builds",
      "presets": ["light_rain", "full_storm"],
      "at_end": "reverse",
      "hold_min": 600,
      "hold_max": 1200,
      "ramp": 60,
      "owner": null,
      "transitions": {
        "full_storm": {
          "in":  { "Thunder/Thunder 1": { "styles": ["dist"], "values": { "dist": 70 }, "pre_fade": 20 } },
          "out": { "Gusts": { "styles": ["swell"], "values": { "swell": 20 }, "pre_fade": 0 } }
        }
      },
      "while": {
        "full_storm": {
          "tracks": { "Rain": { "volume": 0.9 } },
          "groups": {}
        }
      }
    }
  }
}

ATTRIBUTION.md:

# Thunderstorm

All sounds recorded by the theme author.
Licence: CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/). Credit the author when you share it.

MANIFEST.json:

{
  "source": { "site": "", "url": "", "creator": "The theme author" },
  "license": { "name": "CC BY 4.0", "url": "https://creativecommons.org/licenses/by/4.0/", "requires_attribution": true }
}

What you hear:

  • Light rain (the default, ★): soft rain, a quiet wind bed, drips now and then. Gusts and thunder are off.
  • Full storm: loud rain, the wind bed louder, gusts rising and falling between 40 % and 100 % with pauses of 20 to 90 seconds, thunder every 30 seconds to 2 minutes after the last crack, one crack at a time. Drips are off.
  • Storm builds: 10 to 20 minutes on each preset with a one-minute glide between them, back and forth. Coming into Full storm, the first thunder starts far off and muffled (Distance), 20 seconds before the step; leaving it, the gusts fade out on a curve (Smooth fade). While Full storm plays in this sequence, the rain is at 90 % instead of 100 %.

In the Wind group, Wind 3 (presence 0.5) comes up less often than the other two. Every wind file is 20 seconds or longer, at least twice the 8-second crossfade.

Both examples were checked on Sonorium 1.7.1: imported as zip files, they load without problems, their presets apply, and the sequence runs and steps.


Adding the theme to Sonorium

As a zip file

The zip holds one folder, the theme folder, with everything inside it:

Thunderstorm.zip
  Thunderstorm/
    metadata.json
    presets.json
    Rain.wav
    ...
    Wind/Wind 1.wav
    ...
  • Zip the folder, not its contents. In a zip without the top folder, files in group folders land at the top of the theme and the groups are lost.
  • The top folder's name becomes the theme folder's name. If a folder with that name already exists, the new one gets _1 (Thunderstorm_1), _2, and so on.
  • The imported theme gets a new id.

To make the zip:

  • Windows: right-click the theme folder, then click Compress to ZIP file (Windows 11) or Send to › Compressed (zipped) folder.
  • macOS: right-click (or Control-click) the theme folder, then click Compress.
  • Linux: zip -r Thunderstorm.zip Thunderstorm

Import through the web UI

  1. Click Themes in the menu.
  2. Click ⋯ at the top right of the Themes page (or press Tab until it is highlighted, then Enter).
  3. Click Import theme….
  4. Pick the zip file and click Open (or type its name and press Enter).

A message shows Imported "Thunderstorm" (12 files), and the theme appears in the list.

In 1.7.1, Import theme works on the Home Assistant app and Docker. On the Windows app, copy the folder in instead (see Copy the folder in).

Import through the API

curl -F "file=@Thunderstorm.zip" http://<sonorium-address>:8008/api/themes/import
curl -X POST http://<sonorium-address>:8008/api/themes/refresh

The first call answers:

{"status": "ok", "theme_folder": "Thunderstorm", "files_extracted": 12, "path": "/media/sonorium/Thunderstorm", "problems": []}

The second rescans the audio folder, as the web UI does after an import. With Require login on, add a key with Themes and presets › Upload and delete checked: -H "Authorization: Bearer <key>". Keys are made on Settings › Keys (see Sign-in and Users).

To add one audio file to an existing theme, into a group (the group folder is created if needed):

curl -F "file=@Drip 2.wav" -F "group=Thunder" http://<sonorium-address>:8008/api/themes/<theme id>/upload

A new file starts Unassigned: it doesn't play until you give it a mode in the Theme Editor. A file in a group plays the group's way.

Copy the folder in

  1. Copy the theme folder into the audio folder (see Where themes live).
  2. In Sonorium, click Themes in the menu.
  3. Click ⋯ at the top right of the Themes page.
  4. Click Refresh.

A copied theme keeps its id. Don't copy the same theme in twice with the same id: give the copy a new one.


Tips

  • Names: name files for what they are (Rain on roof.wav, Thunder 2.wav). The file name, without its extension, is the track's name in Sonorium and its key in the JSON files. Renaming a file later means changing its key everywhere it appears.
  • Levels: Sonorium raises the whole mix (Settings › Audio Settings › Master output gain, 60 % by default) and softens peaks that go too high. With the default gain, a single track's peaks above about -18 dBFS reach that limiter. Keep files modest and balance them with volume instead of making each file loud.
  • Loop seams (Background): a Background track crossfades its end into its start over 1.5 seconds, which hides a slightly rough loop point. Turn on seamless_loop (Gapless) only for a file cut to loop perfectly. Beds of 2 to 5 minutes repeat less noticeably than short ones.
  • Variety: for a bed that never repeats the same way, use 3 or more files of the same scene in a Merry-go-round group, each at least twice the crossfade long. For events (thunder, a door, a lute song), put several versions in an Intermittent group: they play one at a time, never the same one twice in a row.
  • Abrupt files: give a file that starts or ends with a click a short fade_in / fade_out (0.2 to 1 second).
  • File sizes: 44.1 kHz mono WAV is about 5 MB a minute; mono MP3 at 128 kbit/s about 1 MB a minute. Sonorium's own stream is 128 kbit/s mono MP3, so higher quality isn't heard. Use MP3 or OGG for long beds.
  • Test as you go: after a change by hand, use Refresh, open the theme with Edit, and listen with Preview mix. Check Settings › Logs if the theme looks different from what you wrote.

Clone this wiki locally