Skip to content

Sound

This page shows how to play sounds on your clock: MP3 files, melodies, songs and tracks from a DFPlayer module. It also shows how loud each kind of sound plays, and what happens when two sounds meet.

A few words this page uses:

  • Alert: a sound you ask for from outside the clock. A notification's sound and a request to /api/v1/audio/play are alerts.
  • App sound: a sound a script plays.
  • Radio: an internet radio station. See Internet radio.
  • Master volume: the volume of the whole clock. Every other volume is a share of it.
  • RTTTL: a short text format for ringtones, from old mobile phones.

How it behaves

Every sound is described the same way, whether you play it with a request, over MQTT, with a notification or from a script. It plays at the master volume times the share of its group: alerts, app sounds or the radio. The clock plays one sound at a time, and the radio pauses while another sound plays (What plays over what). A new alert replaces the one that plays, and a script's sound never cuts an alert off. A sound plays once, unless you add "loop": true, and a station plays until you stop it.

What your clock can play

Which sounds your clock can play depends on its hardware. The web UI shows only what your clock can play. To see it yourself, look at audio in GET /api/v1/capabilities:

{"audio":{"mp3":true,"rtttl":true,"song":true,"speech":false,"track":false,
          "radio":true,"url":false,"effect":false,"clip":false}}
Flag Your clock can
mp3 play MP3 files you upload. This needs PSRAM and an I²S amplifier
rtttl play melodies on the buzzer
song play songs written as text with its synthesizer. Same hardware as mp3
track play numbered tracks from a DFPlayer module
radio play internet radio. Same hardware as mp3

Every flag is always there, true or false. The other flags are always false on this clock.

Play a sound

The quickest test plays three rising notes:

curl -X POST http://<awtrix-ip>/api/v1/audio/play \
  -H 'Content-Type: application/json' \
  -d '{"rtttl":"beep:d=4,o=5,b=120:c,e,g"}'

The answer is:

{"ok":true}

The body says what to play. It is called the sound, and a notification's sound takes the same value.

A stored sound is played by its name:

curl -X POST http://<awtrix-ip>/api/v1/audio/play \
  -H 'Content-Type: application/json' \
  -d '{"file":"ding"}'

A plain name in quotes is short for the same thing. "ding" and {"file":"ding"} play the same sound:

curl -X POST http://<awtrix-ip>/api/v1/audio/play \
  -H 'Content-Type: application/json' \
  -d '"ding"'

A sound has exactly one of these keys. The key says what plays:

Key Value Plays
file a stored name such as "ding", or a script's sound such as "Racer/boost" a stored MP3 or melody
rtttl RTTTL text, up to 512 characters the melody in the request
song song text a song on the synthesizer
track a whole number from 1 to 2999 a track from the DFPlayer
station a station name, a position in the list, or a stream address internet radio, see Internet radio

Next to the key, "loop": true repeats the sound until you stop it. See Repeat a sound.

Give the clock a choice

A sound can also be a list of 1 to 4 sounds. The clock plays the first one it can play. It skips an entry when it lacks the hardware for it, or when a file is not stored.

This notification plays track 3 on a clock with a DFPlayer, and the melody on every other clock:

curl -X POST http://<awtrix-ip>/api/v1/notifications \
  -H 'Content-Type: application/json' \
  -d '{"text":"Door","sound":[{"track":3},{"rtttl":"bell:d=4,o=5,b=100:e,c"}]}'

What the notification shows on the display

The display shows Door while the sound plays. A clock that can play none of the entries shows the notification without sound.

How a name is found

A plain name such as "ding" is looked up in this order:

  1. the MP3 /MP3/ding.mp3, on a clock that plays MP3s;
  2. the melody /MELODIES/ding.txt, on a clock that plays melodies.

A script asks its own folder first. See Sounds for your script.

A name with a slash, such as "Racer/boost", plays the sound boost of the script Racer. It is looked up in that script's folder only.

Names are 1 to 32 characters of A-Z, a-z, 0-9, _ and -.

MP3s

MP3s need a clock with mp3 in its capabilities.

Upload an MP3

  1. Open the web UI and go to the Audio tab.
  2. In the MP3s section, drag the file onto ⬆ Upload, or click it to choose the file.

You play an MP3 by its file name without .mp3, so name the file the way you want to call it.

  • Use normal MP3 files, the kind any converter makes. A file that is not an MP3 is refused.
  • MP3s share the storage with icons, melodies and scripts, so keep them to a few seconds. The line above the list in the MP3s section shows how much space is left.
  • An MP3 and a melody never share a name. If a melody called ding is stored, an MP3 called ding.mp3 is refused, and the other way round. Rename one of them first.

Play an MP3

  1. Open the Audio tab.
  2. Press ▶ next to the MP3.

Or use the file name without .mp3:

curl -X POST http://<awtrix-ip>/api/v1/audio/play \
  -H 'Content-Type: application/json' \
  -d '{"file":"ding"}'

The same name works as "sound":"ding" in a notification, and in a script.

Rename an MP3

Click the pen next to it on the Audio tab, type the new name and press Enter, or send:

curl -X POST http://<awtrix-ip>/api/v1/audio/mp3/rename \
  -H 'Content-Type: application/json' \
  -d '{"from":"ding","to":"bell"}'

Alarms, notifications and scripts that play the old name stay silent until you change them. A script's own MP3s keep their names.

Delete an MP3

Click the bin next to it on the Audio tab, or send:

curl -X DELETE http://<awtrix-ip>/api/v1/audio/mp3/ding

MP3s that come with a script

A script can bring its own MP3s. They live in the script's folder. The Audio tab lists them below your own MP3s, in a group for each script. From outside the script, play one as "Racer/boost":

curl -X POST http://<awtrix-ip>/api/v1/audio/play \
  -H 'Content-Type: application/json' \
  -d '{"file":"Racer/boost"}'

A script's sounds may have the same name as a melody or as an MP3 in /MP3. See Sounds for your script.

Deleting a script with sounds asks what happens to them: Delete with sounds, or Keep sounds. Kept sounds stay on the Audio tab, in a group marked script removed. They come back into use when a script of the same name is installed again. Delete them there one by one when you do not need them any more.

Melodies

A melody is a short tune in RTTTL text. You can send it with each request, or store it on the clock and play it by name. Melodies need a clock with rtttl in its capabilities.

Writing RTTTL

An RTTTL melody has three parts, separated by colons. All three are required:

name:defaults:notes
beep:d=4,o=5,b=120:c,e,g
└─┬─┘ └──────┬─────┘ └─┬─┘
name    defaults     notes
  • name: 1 to 24 characters. It is not played, but it must not be empty.
  • defaults: d is the default note length, o the default octave, b the beats per minute. Each may appear once at most, in any order, and each may be left out.
  • notes: separated by commas. Each note is an optional length, a letter a to g (p is a pause), an optional #, an optional . for a dotted note, and an optional octave. 16c6 is a 16th note C in octave 6. A note without a length or octave uses the defaults.

Allowed values:

Element Allowed If left out
d and any note's length 1, 2, 4, 8, 16, 32 d, default 4
o and any note's octave 4, 5, 6, 7 o, default 6
b 10 to 300 default 63
note letter a to g, or p for a pause

Anything else is refused, including b#, e#, a pause with # and a length such as 3. The answer names the reason and the position in the text:

curl -X POST http://<awtrix-ip>/api/v1/audio/play \
  -H 'Content-Type: application/json' \
  -d '{"rtttl":"d=4,o=5,b=120:c,e,g"}'
{"error":{"code":"validationFailed",
          "message":"missing ':' (at offset 19)",
          "field":"rtttl"}}

The status is 422.

A melody is at most 512 characters, sent in the request or stored in a file. See Limits.

Some melodies to try:

# Two-tone doorbell
curl -X POST http://<awtrix-ip>/api/v1/audio/play -H 'Content-Type: application/json' \
  -d '{"rtttl":"bell:d=4,o=5,b=100:e,c"}'

# Falling "something went wrong"
curl -X POST http://<awtrix-ip>/api/v1/audio/play -H 'Content-Type: application/json' \
  -d '{"rtttl":"lose:d=8,o=5,b=120:16c,16b,16a,4g"}'

# Jackpot fanfare
curl -X POST http://<awtrix-ip>/api/v1/audio/play -H 'Content-Type: application/json' \
  -d '{"rtttl":"jackpot:d=8,o=5,b=120:16c,16e,16g,c6,16p,16c6,16e6,4g6"}'

Store a melody

  1. Open the Audio tab and go to Melodies.
  2. Press + New melody.
  3. Enter a name and the notes, then save.

The editor checks the text while you type, plays it in your browser, and plays it on the clock when you want to hear it there. See Melodies.

Or save one with a request:

curl -X PUT http://<awtrix-ip>/api/v1/audio/melodies/doorbell \
  -H 'Content-Type: application/json' \
  -d '{"rtttl":"d=4,o=5,b=100:e,c"}'

The answer is 201 for a new melody and 200 when it replaced one. A text with a mistake answers 422.

  • The melody is stored as /MELODIES/doorbell.txt. Its name part is always the name you saved it under. Send d=4,o=5,b=100:e,c and the file holds doorbell:d=4,o=5,b=100:e,c.
  • Names are 1 to 24 characters of A-Z, a-z, 0-9, _ and -.
  • A melody never takes the name of a stored MP3. Saving doorbell while /MP3/doorbell.mp3 exists answers 409, name taken.

Play a stored melody

Use the name without .txt:

curl -X POST http://<awtrix-ip>/api/v1/audio/play \
  -H 'Content-Type: application/json' \
  -d '{"file":"doorbell"}'

If nothing is called doorbell, the answer is 404:

{"error":{"code":"notFound","message":"nothing called \"doorbell\""}}

List the stored melodies

curl http://<awtrix-ip>/api/v1/audio/melodies
{"melodies":[{"name":"doorbell","rtttl":"doorbell:d=4,o=5,b=100:e,c",
              "bytes":26,"notes":2,"durationMs":2400,"valid":true}],
 "usedBytes":41216,"totalBytes":1048576}
  • notes and durationMs tell you how long a melody is without playing it.
  • A melody with a mistake is still listed, with valid:false, error and index. So you can find and fix it in the editor.
  • usedBytes and totalBytes are for the whole storage. Melodies share it with icons, palettes and scripts.

Delete or rename a melody

curl -X DELETE http://<awtrix-ip>/api/v1/audio/melodies/doorbell

The answer is 404 notFound if there is no such melody. To rename a melody, save it under the new name and delete the old one.

Songs

The synthesizer plays music written as text: a few instruments and the notes they play. You send the text in the request. Nothing is uploaded or stored. How to write a song: Song text.

curl -X POST http://<awtrix-ip>/api/v1/audio/play \
  -H 'Content-Type: application/json' \
  -d '{"song":"bpm 120; inst lead wave=pulse volume=75; lead: c4 e g c5"}'
  • The song plays once. Add "loop": true to repeat it until you stop it.
  • Song text with a mistake is refused with 422 validationFailed, field song. The message names the line and column.
  • Scripts can play a song as music. See the scripting guide.

Repeat a sound

Add "loop": true to a sound to repeat it until you stop it:

curl -X POST http://<awtrix-ip>/api/v1/audio/play \
  -H 'Content-Type: application/json' \
  -d '{"rtttl":"siren:d=8,o=5,b=200:c,g,c,g","loop":true}'
  • It repeats until you stop it, or until a new alert takes its place.
  • The radio stays paused while it repeats and comes back once it has stopped.
  • In a notification it repeats while the notification is shown. See Notifications.
  • loop does not work with station. A station plays until you stop it anyway.

Volume

The clock has one master volume and three groups. Each group is a share of the master volume:

Setting Range Default Volume of
volume 0 to 100 60 the whole clock. Every group below is a share of it
radioVolume 0 to 100 80 internet radio
appVolume 0 to 100 100 everything a script plays
alertVolume 0 to 100 100 notification sounds and /api/v1/audio/play

What you hear is the master volume times the group's share. With volume at 50 and alertVolume at 60, an alert plays at 30.

In the web UI

  1. Open the Audio tab.
  2. Move the sliders in the Mixer section at the top: Master, Radio, Apps and Alerts. Radio shows only on a clock that plays radio.

A change applies at once, also to sounds that are playing.

With the API

curl -X PATCH http://<awtrix-ip>/api/v1/settings \
  -H 'Content-Type: application/json' \
  -d '{"volume":50,"alertVolume":60}'
  • 0 is silence. "volume": 0 silences every sound, the radio included.
  • A value outside 0 to 100 is refused with 422.

All four settings: Sound settings.

What plays over what

When What happens
An alert starts The radio pauses and comes back afterwards. A script's sounds never cut an alert off
A new alert arrives while one plays The new alert replaces the playing one
A script plays a single sound while an alert plays The script's sound is not played
A script plays a sound The radio pauses and comes back when the script's sound has ended
A notification with loop leaves the display Its sound stops at once
A notification without loop leaves the display Its sound plays to its end

The clock plays one sound at a time.

Stop a sound

On the Audio tab, press ■ in the bar that shows what is playing. Or send:

curl -X POST http://<awtrix-ip>/api/v1/audio/stop

This stops everything, the radio too. Add group to stop less:

curl -X POST http://<awtrix-ip>/api/v1/audio/stop \
  -H 'Content-Type: application/json' \
  -d '{"group":"alert"}'
group Stops
alert the alert that is playing
app every sound a script plays
radio the radio

Any other value answers 422, must be alert, app or radio.

Over MQTT

The same sound goes to <prefix>/cmd/audio/play:

mosquitto_pub -h <broker> -t 'awtrixNG/cmd/audio/play' -m '{"file":"ding"}'
mosquitto_pub -h <broker> -t 'awtrixNG/cmd/audio/stop' -m '{"group":"alert"}'
  • An empty payload on cmd/audio/stop stops everything.
  • Errors come back on <prefix>/cmd/audio/play/result as {"ok":false,"error":{…}}.
  • <prefix>/state/audio shows what is playing. It is kept by the broker, and it is sent again on every change.
  • Storing and listing melodies works over HTTP only.

See Command topics.

DFPlayer tracks

A DIY board can drive a DFPlayer Mini MP3 module. AWTRIX uses it when the DFPlayer switch under System → Audio is on and both DFPlayer pins are set. The buzzer keeps working next to it. See Sound hardware and The pin map.

A DFPlayer plays numbered files from its own SD card:

curl -X POST http://<awtrix-ip>/api/v1/audio/play \
  -H 'Content-Type: application/json' \
  -d '{"track":3}'
  • A number outside 1 to 2999 answers 422 validationFailed.
  • A track plays at the volume of its group, like every other sound.

The buzzer

The buzzer plays melodies only. To silence it for good, set pinBuzzer to -1 in the pin map.

When it goes wrong

What you see Why
422 validationFailed the sound has a mistake, for example two keys, a name with .mp3 or .txt, or a melody that cannot be read, or a track out of range. field names the key
404 notFound, nothing called "x" no MP3 or melody has that name. Check the spelling
404 notFound, no file "Racer/x" the script Racer has no sound called x
503 unavailable your clock cannot play this kind of sound, for example an MP3 without an I²S amplifier. For a list, the clock can play none of its entries
409 nameTaken, name taken an MP3 and a melody would share a name
200, but no sound the master volume or the group's volume is 0, a script's sound met a playing alert, or the DFPlayer track is not on the card
MP3 upload refused the file name has characters other than A-Z a-z 0-9 _ -, or the file is not an MP3

Every status code and message: Audio playback errors.

Good to know

  • An rtttl without a name in front is refused with 422. Write any name and a colon before the defaults: beep:d=4,o=5,b=120:c,e,g. Only a stored melody may leave the name out.
  • A stored sound is played by its name alone. {"file":"ding.mp3"} is refused with 422, invalid name. Send {"file":"ding"}.
  • An MP3 whose file name has spaces or other signs is refused. Names may only use A-Z, a-z, 0-9, _ and -, up to 32 characters. Rename My Song (2024).mp3 to my-song-2024.mp3 first.
  • station works only on its own. In a list or in a notification's sound it is refused with 422, not here. Start the radio with a request of its own.
  • AWTRIX cannot see what is on the DFPlayer's card. A track that is not there answers 200 and plays nothing. Check the numbers of the files on the card.

Details