snd: music and sound effects¶
Sound is a synth for music and short PCM samples for effects. Both are
authored entirely in the App: music is a text file you write in the editor,
effects are .wav files you drop in (the App converts them).
The one rule that shapes everything: sound is an effect of _update(), never
of _draw(). _draw() may be dropped under load without breaking replay, so
snd.* called from it is an error. Put your sound calls in _update().
The functions¶
snd.music(name [, loop]) / snd.music()¶
Plays the song name — the name of a .son file in the game, without the
extension (game.son → snd.music("game")). loop true repeats it. With no
argument, stops the music. An unknown name is an error listing the songs that
exist (like gfx.background).
snd.play(name [, vol])¶
Plays a sound effect once — the name of a .sfx file, without the extension.
vol is 0 to 15 (default full). Two effects play at a time; a third steals the
oldest voice. An unknown effect is silent, not an error (like a missing
sprite): a typo never crashes a game.
snd.stop()¶
Cuts everything, music and effects, at once.
snd.volume(music [, sfx])¶
Master volumes, 0 to 15. snd.volume(8) sets the music level; a second argument
sets the effects level.
function _update()
local p = pad.get()
if start and p & pad.START ~= 0 then snd.music("theme", true) end
if p & pad.A ~= 0 and not (prev & pad.A) then snd.play("shoot") end
prev = p
end
Music: the .son file¶
A song is a small text file in the tracker tradition — readable, diffable, written by hand in the editor. Create a music in the workshop (library, Sounds, +) and it opens with a skeleton that already plays.
; theme.son — the title music
tempo 8 ; frames per line (60/8 ≈ 7.5 lines a second)
inst lead onde=pulse25 env=1,3,10,6 ; A,D in frames; S level 0..15; R frames
inst bass onde=tri env=0,0,12,2
pattern intro
C-4 lead v12 | C-2 bass | --- | ---
E-4 | --- | --- | ---
G-4 . a047 | G-2 | --- | ---
--- | --- | --- | ---
fin
morceau
intro intro
boucle 0 ; loop back to entry 0 (omit for no loop)
fin
tempo N— frames per line. Lower is faster.inst name onde=… env=A,D,S,R— an instrument.ondeis one ofpulse12,pulse25,pulse50(square),tri,scie(sawtooth),bruit(noise). The envelope is counted in frames: attack, decay, sustain level (0–15), release.pattern name…fin— a block of lines. Each line is the 4 channels separated by|. In a cell: a note likeC-4(C-0toB-7),---for nothing,offfor note-off,.to keep the channel's current instrument. Optional per-cell:vNNvolume,aXYZarpeggio (root, +Y, +Z semitones). A pattern is as long as the lines you write — it loops there, not at 64.morceau…fin— the sequence of patterns to play, then optionallyboucle ito repeat from entryi.
Four synth channels play at once. A noise channel still needs a note (it sets
the LFSR rate). A game can hold several songs; snd.music("name") picks one.
Effects: .sfx from a .wav¶
Drop a .wav on the library's Sounds and the App converts it to a .sfx (8-bit mono
PCM at 24 kHz). PCM WAV, 8 or 16 bits, mono or stereo, any rate — it is
downmixed and resampled. A game holds up to 64 effects and about 80 seconds
of them in total (1,920 KiB at 24 kHz); the App refuses a bundle that goes
over, with the numbers. You can also drop a ready-made .sfx.
Sounds in the workshop¶
In the workshop's library, Sounds holds the raw sounds and Audio bundles
groups them. Drop a .wav (converted to an effect), a .sfx or a .son, or
create a music; double-click a sound to open it in a tab, where an effect shows
its waveform and a music is edited as text, and ▶ Listen plays it with the
console's synthesizer. Group sounds into an audio bundle, give each a flat
name, and attach the bundle to the project — its pieces land in the game as
<name>.sfx / <name>.son, exactly what snd.play("name") /
snd.music("name") read. Unlike a level there is nothing to compile: a sound
stands on its own. ▶ Play runs the game with its sound.
You can still upload a .son/.sfx/.wav straight into a project's files for
a one-off; the library is the reusable part on top. See
working in the App.
What the names don't say¶
- Timing is in frames, not seconds. A song's tempo, an envelope, all count logical frames — the same clock the game runs on, so replay is exact.
- No
math.sinin the sandbox. The synth uses frozen integer tables, likesys.sin; you never touch that, but it is why the sound is bit-identical on the simulator and the board. - On the board, effects live in flash and are read in place; music is tiny and lives in RAM. You don't manage any of that. The first time a game runs, its effects are written to the flash — a few seconds for a full reserve — and left alone until its sounds change; another game's effects take their place when that game runs.