# 🤚 ✋ + `skode` + `skred` = 💙 🔈
## What is this?
`skred` is an open-source, MIT-licensed sound engine that works on Linux, macOS,
MSWindows, and WASM. I'm in the middle of a refactor so it's living in-between
two different repos at the moment. You've landed on the latest repo.
`skode` is the short-hand notation that tells `skred` how to make sounds
and how to change a sound's character over time.
I showed off a little bit of this tooling in a lighting talk at the
[skode talk](https://youtu.be/SnJ0osgiqWM?si=O9Uv9lHX0F8fOeFm)
[2026 ElixirConf EU](https://www.elixirconf.eu/)
in Malaga Spain... watch for Elixir and Nerves and AtomVM stuff related to this in
the future.
I'll be talking about both these pieces and a bit more at the
[2026 ADC conference](https://audio.dev/adc-japan-26/)
in Tokyo. I hope I don't embarrass myself.
## Why am I doing it this way?
For years, I've wanted a simple way to play with sounds, both musical, and experimental.
I'm highly influenced by the PC sound hardware and analog/digital synthesizers I played
with during 80's and that will show up throughout this document. After you play with
this learning thing for a while, check out the silly Atari 800 / C64 theme inspired
REPL for `skred` [here](https://octetta.github.io/pulp/doc).
Anyway, to achieve this, I wanted a notation that is low-ceremony, meaning it's simple
to type and doesn't require much thinking once you remember a few symbols that do what
you want.
Rationalizing my position, how do you think about these notations from different
domains?
- Music notation like ♩, ♪, and 𝄞
- Math symbols, like √, ∑, and ∫
- Chemical element symbols like, Hg, H2O, and, Pb
- Abbreviations like `ls` or `cat` or `grep` used at a command prompt
- LOL and WTF...
These things look weird until they don't, and in my opinion their tersness
frees up mental space so you think more about what you want to do rather
than how to spell something or the finger gymnastics to enter it.
From proclivity and laziness, I limit `skode` to ASCII and have simple rules
to about how characters are used to easily classify things in my parsing code.
Something we'll visit later is how to concisely to send `skode` from a variety of tools
and languages, but it's worth mentioning that this HTML page uses the exact same notation
internally.
*A quick acknowledgement : `skode` and `skred` are HIGHLY influenced by the
[AMY](https://github.com/shorepine/amy)
project, but implemented independently over the past few years, reflecting my own
(questionable!?) goals... thanks to Brian and dAN for the inpiration and openess and
kindness. I also might not have done any of this without the
[miniaudio](https://miniaud.io)
project being available. Thanks mackron*
I'll talk about the `skred` sound engine in some detail later in this document, but let's
get you thinking about sound differently by trying a few simple things with `skode`.
## Let's make a sound!
Enough excuses, you've made it this far.. let's have fun.
First off, press the START button on the top of the page to get `skred` running.
This may ask your permission to record audio, which allows `skred` to record
audio (under your control) for use in sound samples. If you stick around long enough,
we'll learn about that later.
*If at any point the sound is unpleasant or unwanted, you can stop it with the
STOP button, which totally stops `skred` running, or by QUIET, which sends
a `skode` command to return `skred` to its initial quiet state, essentially
zero-ing out anything that was setup in making sound(s).*
Assuming you see a green square next to the START button, click the play button next to
the `skode` block below:
v0 w0 a0 f440 t 0 1 0 0 l1
Throughout this page, you can edit the `skode` text within a block, then press the
play button to hear the change.
Try these changes...
- Change `f440` to `f880`... you'll hear the same kind of tone but one octave higher.
- Try other numbers with `f`... my ears don't easily hear things below `f220` without amplification, but your ears may be better!
- Try changing the number to the right of the `t` from `0` to `.1` ... I promise I'll explain what this is later...
- Now let's use the `f220` and fix it so even I can hear it by changing the `a0` to `a20`...
- Finally, change two things, `w0` to `w1` and `a20` to `a0`...
How was that?
- Does any of this make sense?
- Was it easy?
- Want to learn more?
#### *Teaser*
*Don't be overwhelmed by this... I'll eventually explain it all!*
v0 a0 n69 t.01 .3 0 0 g.1 N0,0 >1 p-.25 w11 G1 H1 v1 w14 p.25
v2 m1 a0 f10 l1 v0 A2,.25,1
{v0 ~0 n69l1 ~.25 n65l2 ~.5 l2 ~.25 l3 ~.25 n60l2 ~.25 n61l2} e>0
~0 {v0 N-24,0 v1 N-7,5 e!0} R2 2
~4 {v0 N-7,0 v1 N-16,25 e!0} R2 2
~8 S100
## Explaining what we entered...
I'll break down the original `skode` block **`v0 w0 a0 f440 l1`**
### v means *voice*
Think of this like a single voice among a chorus of people.
`skred` can have many voices depending on how it's setup, but in this learning tool,
it has a chorus of 16 voices, each awaiting your instructions.
**`v0`** says make *voice 0* the one we are changing some characteristic of.
### w means *waveform*
Waveforms define the character of a voice depending on the sequence of numbers
being played.
**`w0`** says whatever voice we're pointed at, let it use waveform "0"
What is waveform "0" you ask?
**`w0`** is a sine wave. Is looks the letter S lying down on it's side.
You heard it by playing with it above, and some describe a human whistling as
a source of sine waves. `skred` uses the `sin()` function, instead of a person.
Sine waves are considered to be a pure fundamental sound, "with no flavor", which sounds
rude, so I say it's beautiful and peaceful.
You may want to use it for the sustaining portion of bells, or organs, if that's your
goal.
You also heard **`w1`** which is a square wave.
A square wave looks "binary", either all positive or all negative.
Square waves are harsher in character than sine waves, perhaps sounding like a clarinet,
or other reed-type instruments, no offence to reed instrument players, unless you like
being harsh.
Smart math people say if you add up all the odd frequency sine waves and adjust the
intensities in a particular way, you wind up with a square wave. I trust them.
I'll talk the other built-in waveforms later, but for now know that there
are 26 available when you start `skred`.
### a means *amplitude*
Perhaps intuitively, amplitude is how loud a voice is. Maybe less intuitive is that
in `skode` at least, the number used is expressed as decibels, or dB.
Without explaining things I really only partly understand, 0dB as we used above via **`a0`**,
means "normal" loudness, such that when there are more than one voice playing, we don't
over-drive the speaker (it's still possible to over-drive the speaker though, which is
dangerous and fun and edge-ey and artistic, right?).
In `skode` 10dB via **`a10`** is twice as loud as **`a0`**, and **`a-10`** is half as loud as **`a0`**.
### f means *frequency*
Frequency is how we specify the pitch of a sound.
Low numbers are like rumbles, and high numbers are like whistles.
`skode` uses units of Hertz (Hz), which my old math books intuitively called
"cycles-per-second", no disrespect to Mr. Hertz.
So, **`f440`** means 440 cycles-per-second, which smart music people call "concert A".
On an 88-key piano, 440 sits somewhere right of the middle of the keyboard (on the
right of of middle-C, if you took piano lessons).
While I still think of middle-C a lot due to those old piano lessons, its frequency
is 261.626 Hz, which is a lot harder to type than 440.
There's another way `skode` uses to specify frequency, but you'll have to wait for
that in a later section (hint: MIDI).
### t means *time based amplitude envelope*
*WARNING, I'm rambling on here and need to come up with a more articulate way
of describing this... suggestions are appreciated.*
The things we've shown before are important and interesting of course, but sound
and music instruments are even more interesting when they change over time.
The word "envelope" is used, perhaps because it's something that wraps around a
sound to change it. The kind of envelope used in `skred` is called an ADSR
envelope, corresponding to the 4 numbers following the **`t`**...
Those pieces are:
- *ATTACK* - time in seconds when the envelope is started going from quiet to the amplitude specified in the voice
- *DECAY* - time in seconds from the voice's amplitude (**`a`**) value to the SUSTAIN value
- *SUSTAIN* - adjustment of the amplitude between DECAY and RELEASE... specified as a 1 or a fraction of voice's amplitude
- *RELEASE* - time in seconds between when the envelope is told to stop going from SUSTAIN to quiet
### l (lower-case 'ell') means *start* or *stop* the amplitude envelope
Non-intuitively, the *ell* means *veLocity*, so with that cleared up (another thing copied from AMY)...
In `skode` if the value following the `l` is greater than 0, it starts the
ampltude envelope, multiplying the number following it by the voice's amplitude to allow
emphasis or de-emphasis. This is useful when we connect `skode` up to a MIDI keyboard,
which is a later topic.
If the envelope has a SUSTAIN value, the voice will continue playing until `l0` is
sent, which causes the envelope to use the RELEASE time.
It's easier to play with this to learn it than it is to talk about, so go back to that earlier block
and mess with it. I'll be here when you get back.
## More about waveforms
As promised, here's more about the rest of the built in waveforms.
`skred` has 26 built in (not totally the truth, but I'll explain that later),
and new waveforms can be added during runtime.
Here are some more to try out...
**`w1`** is a square wave
v0 w1 a0 f440 t0 2 0 0 l1
**`w2`** is a sawtooth wave from low to high. It looks like a shark fin going to the left.
v0 w2 a0 f440 t0 2 0 0 l1
**`w3`** is a sawtooth wave from high to low. Using the shark fin imagery, it's going the other direction.
v0 w3 a0 f440 t0 2 0 0 l1
**`w4`** is a triangle wave
v0 w4 a0 f440 t0 2 0 0 l1
**`w5`** is a short noise wave
v0 w5 a0 f440 t0 2 0 0 l1
**`w6`** is a long noise wave
v0 w6 a0 f440 t0 2 0 0 l1
**`w7`** and **`w8`** are the left and right audio input channels, used
for sample capture, and quasi-live effects
v14 m1 a20 w7 l1 ^r1 ~1.25 /r999
~1.5 v14 f440 m0 w999 a20 B1
~2 v14 f440 l1
~4.5 v14l0
~5 v14 f220 l1
~6.5 v14l0
**`w9`** is for future use, but will probably be left and right summed
**`w10`** to **`w25`** are recreations of my favorite 80's synth wave
tables created using my
[k-synth](https://octetta.github.io/k-synth)
tool (look at the patches under dw8000).
Eventually `k-synth` notation will be introduced into `skred` so you can
make your own periodic waveforms and even entire samples.
v0 w10 a0 f440 t0 2 0 0 l1
v0 w11 a0 f440 t0 2 0 0 l1
v0 w12 a0 f440 t0 2 0 0 l1
v0 w13 a0 f440 t0 2 0 0 l1
v0 w14 a0 f440 t0 2 0 0 l1
v0 w15 a0 f440 t0 2 0 0 l1
v0 w16 a0 f440 t0 2 0 0 l1
v0 w17 a0 f440 t0 2 0 0 l1
v0 w18 a0 f440 t0 2 0 0 l1
v0 w19 a0 f440 t0 2 0 0 l1
v0 w20 a0 f440 t0 2 0 0 l1
v0 w21 a0 f440 t0 2 0 0 l1
v0 w22 a0 f440 t0 2 0 0 l1
v0 w23 a0 f440 t0 2 0 0 l1
v0 w24 a0 f440 t0 2 0 0 l1
v0 w25 a0 f440 t0 2 0 0 l1
*Note: this learning page is a single HTML file... you can see how the WASM part
works if you're curious and don't mind looking at HTML that a C-programmer created.*
## Modulators
Just like envelopes change things over time to make things more interesting,
modulators can do that too, but using waveforms as the force behind that.
Things that can be modulated in `skred` are ampltude, frequency, panning,
and phase.
Since voices are waveforms, `skred` uses its own voices as modulators.
Examples to contemplate... start each then drag the slider...
### Amplitude Modulation
Uses `v1` to modulate `v0` amplitude, the slider changes `v1`'s frequency.
v1 frequency
v0 w0 a0 f440 t0 0 1 0 l1 A1 2 0 F-
v1 w0 a0 f1 m1 l1
### Frequency Modulation
Uses `v3` to modulate `v1` frequency, the slider changes `v3`'s frequency.
v3 frequency
v2 w0 a0 f440 t0 0 1 0 l1 F3 20 0 A-
v3 w0 a0 f1 m1 l1
## `skred` voice structure
This deserves more conversation... overview of a `skred` voice
graph TB
voiceam("voicex") -.-> am
am(AM) --> amp
wave(wave
table) --> voice
voicefm("voicey") -.-> fm
fm(FM) --> freq(frequency)
glide --> freq
freq --> wave
voicepdm("voicez") -.-> pdm
pdm(phase
modulation) --> pd
pd(phase
distortion) --> wave
crush(bit
crush) --> wave
sah(sample
and hold) --> wave
amp -.-> xout("voicemod")
smoother --> amp
voice(processed
sample) --> filter --> envelope --> amp(amplitude) --> panner(pan)
fadsr(adsr) --> filter
ffm(filter
modulation) --> filter
voicepanmod("voicew") -.-> panmod
panmod(pan
modulation) --> panner
panner --> left
panner --> right
## Half-baked pattern example
I'm getting tired, so while I rest up, here's a lightly annotated example of
chained voices, filtering, variables, and patterns to contemplate.
### Clear voices, set tempo, set variables
S100
Y0
Y1
M120
=0 32
=1 30
### Setup voices
v0 w11 a0 G1 H1 t 0 .5 0 0 p-1 g.2
v1 w10 a0 N0 25 t .1 .4 0 0 p1
v2 w6 a0 t 0 1 0 0
v3 w5 a10 t 0 .5 0 0 q2 f440 J1 K500 Q10 P4 1
v4 m1 a0 w0 f5 l1
### Setup patterns
y0
{v0 n35 l1}x0
{v0 n$0 l1}x1
{v0 n40 l1}x2
{v0 n$1 l1}x3
y1
{v2 l1}x0
{#}x1
{v3 l1}x2
{#}x3
### START the patterns
Z1
### Change $0 - note of second step
=0,41
### Change $1 - note of fourth step
=1,38
### Change the tempo
M160
### STOP the patterns and voices
Z0
## Inspecting things
See `skred` state and such
e?
=
??
Z
/s2
/s5
W
# 🖖
More to come later...
*...I support the principle of maximum astonishment...*
```
REM POKEY
POKE 53768,80:POKE 53760,156:POKE 53762,7:POKE 53761,168:POKE 53763,0
REM SID
V=54272:POKE V+24,15:POKE V+5,8:POKE V+6,0:POKE V,214:POKE V+1,28:POKE V+4,17
```