-
-
Notifications
You must be signed in to change notification settings - Fork 0
Sound Themes
SynapseOS boots silent. Every event sound is off, and
~/.config/synui/sounds.state does not exist until you turn one on. That is
deliberate: a system that starts making noises after an upgrade is a system that
gets its speakers muted, and then the notification you actually wanted is gone
too.
Turning them on is Super+S (the panel) or synui-sound (the command line).
Both write the same file, and the file is the only state there is.
sudo pacman -S sound-theme-freedesktop libcanberra # samples + the player
synui-sound # what is on right now
synui-sound all on # every event
synui-sound login on # or just one
synui-sound test login # hear it, regardless of switchessynui-sound with no arguments prints the whole state — master switch, theme,
volume, and one row per event showing the sample it would actually play:
master on
theme freedesktop
volume 70
login on service-login (Login)
device_added off device-added (Device plugged in)
lock on bell (Screen locked)
screenshot on (not in freedesktop) (Screenshot)
That third column is the point of the tool. Read on for why.
Ten of them, hooked into the compositor at the point the thing actually happens:
| Event | Fires when | Hook |
|---|---|---|
login |
the session starts | synui_main |
logout |
the session ends |
synui_destroy — so SIGTERM and ^C get it too, not just the quit action |
device_added / device_removed
|
USB or block device plugged / unplugged | the libudev monitor |
lock / unlock
|
screen locked / unlocked | lock.c |
notify |
a notification arrives |
notif.c, only when !replaces
|
screenshot |
a screenshot is taken | input.c |
volume_change |
the volume OSD moves |
input.c — not on mute |
error |
an alert | wherever one is raised |
notifyfires only on a genuinely new notification. A client updating an existing one (replaces_idset) is a progress bar, and playing a chime per update turns a file copy into a machine gun.
synui-sound show the current state
synui-sound <event> [on|off|toggle] one event
synui-sound all [on|off|toggle] every event at once
synui-sound master [on|off|toggle] the master switch alone
synui-sound test <event> play it once, ignoring every switch
synui-sound volume [0-100] master level
synui-sound theme [<name>] show or set the sound theme
synui-sound themes list installed themes
synui-sound samples [<theme>] list the sample ids a theme ships
synui-sound sound <event> [<id>|default] pick the sample for one event
synui-sound install <archive|dir> install a theme
synui-sound remove <name> remove one you installed
Two behaviours worth knowing:
-
all toggleturns everything OFF if anything is on. "Make it stop" is always one predictable command, never a coin flip. -
Turning any event on turns the master switch on. Otherwise
all onis ten switches flipped and still silence.
Each of these adds one theme to the picker:
sudo pacman -S sound-theme-freedesktop ocean-sound-theme \
sound-theme-elementary pop-sound-theme \
deepin-sound-theme cosmic-sound-themeThen synui-sound theme ocean, or the Sound theme row of the Super+S
panel.
synui-sound install ~/Downloads/some-sound-theme.tar.gz
synui-sound install ~/my-sounds # a plain folder works tooAccepted: .zip, .tar.gz, .tar.xz, .tar.bz2, .tar.zst, or a directory.
It lands in ~/.local/share/sounds/<name>/ and appears in the theme row
immediately. The installer prints the sample count, and warns if it is zero —
a theme that ships no samples installs fine and is silent, which is otherwise
indistinguishable from a broken switch.
A pack that ships a light and a dark variant side by side installs both.
The most likely thing you have is a folder of .oga/.ogg/.wav files with no
theme structure at all. Rather than refusing it over a missing index.theme, the
installer stages a real theme around it: samples into stereo/, a generated
index.theme naming it, and from there it is an ordinary install.
A theme is a directory:
~/.local/share/sounds/mine/stereo/desktop-login.oga
~/.local/share/sounds/mine/index.theme # [Sound Theme] / Directories=stereo
The file names are XDG sound ids (freedesktop.org sound-naming spec), so a
theme you make here works in GNOME and KDE unchanged. A theme need not be
complete — pick any sample it does have for any event with
synui-sound sound <event> <id>.
synui-sound remove mineOnly ever from ~/.local/share/sounds. A theme under /usr/share/sounds came
from a package and belongs to pacman — removing it here would leave the package
database claiming files that are gone. If the theme you remove was the selected
one, the selection moves to another installed theme, because a desktop that has
silently gone quiet is worse than one that sounds different.
By default each event resolves through an automatic chain: the name the sound-naming spec gives the event first, then a fallback the freedesktop theme actually ships.
synui-sound sound login bell # play "bell" for login instead
synui-sound sound login default # back to the automatic chain
synui-sound samples # what the current theme has to offerIn the Super+S panel, [ and ] cycle the selected event's sample.
(Brackets rather than Shift+arrows because the panel's key handler returns 0
for any modifier — Shift+Left never arrives at all.)
A deliberate pick is never silently replaced by a fallback. Once you name an id, only that id is tried. The fallback chain exists to make the defaults audible, not to second-guess you.
synui-sound sound validates the id against the theme on disk and refuses a
typo. That is the only place it can be caught: libcanberra answering "no such
sample" is indistinguishable from a broken toggle everywhere downstream.
The sound-naming spec defines desktop-login, desktop-screen-lock and others
that no theme on disk actually ships. Defaulting to them would mean every
event named a file nobody hears. So each event has a chain — spec name first, so
a theme that does ship the proper name wins, then one the freedesktop theme
really has:
| Event | Chain |
|---|---|
login |
desktop-login → service-login
|
lock |
desktop-screen-lock → bell
|
unlock |
desktop-unlock → complete
|
notify |
message-new-instant → message
|
screenshot |
screen-capture → camera-shutter
|
The state report and the panel both show the resolved id, checked against the
theme on disk — not the chain's first entry. Three states, three colours in the
panel: picked (bright), automatic (dim), and not in this theme (warning).
That last one is the whole reason the column exists.
/usr/share/sounds/alsa is nine channel-test .wav files (Front_Left.wav, …)
dropped there by alsa-utils. No index.theme, no stereo/, not one XDG
sample id. Select it and every event is silent — every switch says on, and
every lookup misses.
An earlier picker offered it, because it listed any directory under
share/sounds.
A theme is now index.theme or stereo/ or mono/, enforced in both
the shell (is_theme) and the panel (sound_dir_is_theme). Filtering alone
would leave anyone already on such a directory silent and none the wiser, so both
also name it:
theme alsa <-- NOT a sound theme, nothing will play
pick one of: freedesktop ocean
Lesson: when you tighten a validity check, handle the people already sitting on the invalid value. A filter fixes new choices and abandons existing ones.
The master level and the volume-OSD event were both called volume in one flat
state file. get volume read the event's line (off) into the level, and
every sound went silent. The event is now volume_change.
The same shape of bug is why the per-event sample override is keyed
<event>_sound and matched by building the exact key, not by prefix — an
event added later whose name extends another's would otherwise steal its line.
Lesson: one flat namespace means every name in it must be distinct from every other, including names of a different kind.
synui-sound is the single writer of sounds.state. The Super+S panel, the
Super+S keybind and the command line all run the same script, so "is this
event enabled?" has exactly one answer and one format.
The compositor caches the file to skip a fork() when everything is off — but it
is a cache, and the script re-checks on every invocation. A sound is never
played because the compositor's copy was stale.
Writes are temp-file + rename(), so the panel (which re-reads after every
change) can never see a half-written file.
Both the sound and widget panels keep an optimistic copy of the state, because spawning the helper is asynchronous and re-reading immediately after draws the previous value under the cursor.
But the volume row adjusts relatively. A copy left stale by a
synui-sound volume typed in a terminal gets written back over the new value.
The fix is an mtime-keyed refresh at the top of the key handler — and
deliberately not zeroing the mtime after your own write: an unchanged mtime
means the child has not landed yet, and the optimistic value is the better
answer.
The panel does not re-read while open. Changing
sounds.stateunder an open panel shows nothing — close and reopen it.
Device events come from a libudev monitor filtered to usb/usb_device and
block/disk. Unfiltered, plugging in one USB stick fires once per USB
interface and once per partition — four chimes for one stick.
canberra-gtk-play when it is present, with
--property=canberra.xdg-theme.name=<theme> so the setting applies to this one
sample without touching your global GTK sound-theme-name. Without libcanberra it
falls back to resolving the file itself and handing it to pw-play or paplay.
Volume is 0–100 as a percentage of full scale, converted to the dB libcanberra
wants (100 = 0 dB, the sample as recorded). 0 is treated as mute and never
reaches the player.
A theme with no such sample is silence, not an error — play always exits 0.
This is why the report has to do the checking.
synui-sound with no arguments resolves every event against the theme on disk,
so it answers "what would play?" without playing anything. synui-sound test <event> is the other half: it ignores every switch, so it separates "the sound
is off" from "the audio stack is broken".
See also: Cursor Themes, The Desktop, synui, Keybindings, Commands.
Using it
- Installation
- Updating
- Software
- Files
- Keybindings
- Commands
- Nix
- Gaming
- DaVinci Resolve
- Secure Boot
- Troubleshooting
Customising it
Components
Apps
Hacking on it