Repository navigation
Beeps And Songs
Your Ender-3 V3 KE has a small buzzer on the board. Stock firmware only ever used it for one fixed, loud beep. NebulaOS drives it with hardware PWM instead, so it can play any pitch, any length, and full melodies — and it does so with zero CPU load, which means it's safe even in the middle of a print.
There are three things this gives you:
- A soft touch click when you tap the screen (optional).
-
M300beeps with real pitch and duration (the standard slicer "beep" command). -
PLAY_TUNEsongs — built-in tunes, plus your own, kept in an editable file.
The M300, BEEP and PLAY_TUNE macros are part of the NebulaOS Klipper config
(/etc/nebulaos/klipper/beeper.cfg). Klipper itself owns the buzzer: the nebulaos_beeper extra drives
the kernel's PWM channel for it (/sys/class/pwm/pwmchip0/pwm3) and plays every sound in the
background, so a beep or a song never pauses the print. The screen's touch click goes through the
same owner. /opt/nebulascreen/nebulabeep still exists for old scripts, but it only forwards to
Klipper now; the old RUN_SHELL_COMMAND CMD=guppybeep / CMD=nebulabeep names are gone - call
M300, PLAY_TUNE or NEBULAOS_BEEP FREQ=<Hz> DURATION=<ms> instead. NEBULAOS_BEEPER_STOP silences
the buzzer.
A quiet, low "tick" on every button tap — like a phone's touchscreen feedback.
- Turn it on/off: Settings → Display → Touch beep. (Default is off.)
- It only clicks on real taps, not when you scroll or drag.
- It's deliberately soft and low — not the old loud beep. Nothing to configure; flip it on and it just works.
The standard slicer/G-code beep command, now with real pitch:
M300 S<frequency Hz> P<duration ms>
| Example | What you hear |
|---|---|
M300 S1000 P200 |
1 kHz tone for 200 ms |
M300 S440 P500 |
low A note, half a second |
M300 S2000 P80 |
short high blip |
BEEP |
quick confirmation chirp (shortcut for M300 S2000 P120) |
Many slicers can emit M300 on events (e.g. "beep when the print finishes") — now it plays the pitch
and length you actually ask for.
PLAY_TUNE SONG=mario
PLAY_TUNE SONG=zelda
PLAY_TUNE SONG=starwars
PLAY_TUNE SONG=success # short happy jingle
PLAY_TUNE SONG=error # short low alert
These names come from a plain text file you can edit (see below). Great for a "print complete" or "print failed" jingle.
Songs live in:
/opt/printer_data/config/songs.conf
That's in the same config folder you already see in Mainsail/Fluidd's file manager, so you can edit
it right in your browser (or over SSH). The format is one song per line, name = RTTTL:
# Lines starting with # or ; are comments.
mario = mario:d=4,o=5,b=100:16e6,16e6,32p,16e6,...
success = success:d=4,o=6,b=140:8c,8e,8g,c
tetris = tetris:d=4,o=5,b=160:e6,8b,8c6,8d6,16e6,16d6,8c6,8b,a,8a,8c6,e6,8d6,8c6,bTo add a tune: grab an RTTTL string (the old Nokia ringtone format — thousands are online), paste it
in, give it a name, save, then run FIRMWARE_RESTART. Now PLAY_TUNE SONG=yourname plays it. No
recompiling, no reflashing.
Two things worth knowing:
-
Your songs survive updates. NebulaOS only creates
songs.confif it's missing — a NebulaOS update never overwrites the one you've edited. -
Use normal
#sharps here. Insongs.confyou can paste RTTTL exactly as found online (a#,f#, …). The buzzer player reads this file directly, so the sharps come through fine.
PLAY_TUNE RTTTL=mytune:d=4,o=5,b=120:c,e,g,8c6
For this inline form only, there are two rules (because the command passes through Klipper's G-code parser first):
- No spaces in the string.
- Write sharps as
s(e.g.as,cs,fs) — not#, which G-code treats as a comment.
For anything you'll reuse, just put it in songs.conf and use SONG= — no rules to remember.
Drop a command in your slicer's End G-code, on its own line:
PLAY_TUNE SONG=mario
It's a normal Klipper command, so the slicer passes it straight through. A few tips:
- Put it at the very end of your end-gcode. The song starts when the moves before it have finished and plays in the background - the printer does not wait for it.
- For a quick "done" chirp instead of a whole song, use
M300 S1500 P300orBEEP. - The slicer's end-gcode only runs on a successful finish. To get a sound on failure, trigger
PLAY_TUNE SONG=errorfrom a cancel/error macro instead.
Songs mid-print are cut short. Nothing waits for a song, but while a print runs a tune is cut to 20 seconds so a long song can't buzz through half the job. Save long songs for idle moments — print done, error, startup.
- Some notes are louder than others. The buzzer is a tiny piezo with a natural resonance around 2.3 kHz, so volume varies a bit from note to note. The pitch is always accurate — only loudness changes. That's the physical hardware, not a bug.
- It's a 1-bit beeper — think classic 8-bit chiptune, not hi-fi. There's no speaker or audio chip on the KE.
- Safe during prints. The tone itself is hardware PWM (no CPU); Klipper only switches notes, and it never holds the G-code queue to do so.
Start here
Install it
Set it up
Use the screen
Get good prints
- Calibration guide
- Calibration walkthrough
- Bed tramming
- Load cell calibration
- Axis twist
- Square parts (skew)
Everyday printing
Advanced
- Adaptive meshing and purge
- Quieter motors (TMC Autotune)
- Camera
- Timelapse
- Beeps and songs
- Power-loss recovery
Keep it running
When something is wrong
Developer documentation lives in each component repository. Start from the project README.