Feat: refactoring codebase
This commit is contained in:
82
docs/engine/audio_modulation.md
Normal file
82
docs/engine/audio_modulation.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# Audio-Rate Modulation
|
||||
|
||||
Any parameter can be modulated continuously using modulation words. Instead of a fixed value, these words produce a modulation string that the engine interprets as a moving signal.
|
||||
|
||||
All time values are in **steps**, just like `attack`, `decay`, and `release`. At 120 BPM with speed 1, one step is 0.125 seconds. Writing `4 lfo` means a 4-step period.
|
||||
|
||||
## LFOs
|
||||
|
||||
Oscillate a parameter between two values.
|
||||
|
||||
```forth
|
||||
saw s 200 4000 4 lfo lpf . ( sweep filter over 4 steps )
|
||||
saw s 0.3 0.7 2 tlfo pan . ( triangle pan over 2 steps )
|
||||
```
|
||||
|
||||
| Word | Shape | Output |
|
||||
|------|-------|--------|
|
||||
| `lfo` | Sine | `min~max:period` |
|
||||
| `tlfo` | Triangle | `min~max:periodt` |
|
||||
| `wlfo` | Sawtooth | `min~max:periodw` |
|
||||
| `qlfo` | Square | `min~max:periodq` |
|
||||
|
||||
Stack effect: `( min max period -- str )`
|
||||
|
||||
## Slides
|
||||
|
||||
Transition from one value to another over a duration.
|
||||
|
||||
```forth
|
||||
saw s 0 1 0.5 slide gain . ( fade in over half a step )
|
||||
saw s 200 4000 8 sslide lpf . ( smooth sweep over 8 steps )
|
||||
```
|
||||
|
||||
| Word | Curve | Output |
|
||||
|------|-------|--------|
|
||||
| `slide` | Linear | `start>end:dur` |
|
||||
| `expslide` | Exponential | `start>end:dure` |
|
||||
| `sslide` | Smooth (S-curve) | `start>end:durs` |
|
||||
|
||||
Stack effect: `( start end dur -- str )`
|
||||
|
||||
## Random
|
||||
|
||||
Randomize a parameter within a range, retriggering at a given period.
|
||||
|
||||
```forth
|
||||
saw s 200 4000 2 jit lpf . ( new random value every 2 steps )
|
||||
saw s 200 4000 2 sjit lpf . ( same but smoothly interpolated )
|
||||
saw s 200 4000 1 drunk lpf . ( random walk, each step )
|
||||
```
|
||||
|
||||
| Word | Behavior | Output |
|
||||
|------|----------|--------|
|
||||
| `jit` | Sample & hold | `min?max:period` |
|
||||
| `sjit` | Smooth interpolation | `min?max:periods` |
|
||||
| `drunk` | Random walk | `min?max:periodd` |
|
||||
|
||||
Stack effect: `( min max period -- str )`
|
||||
|
||||
## Envelopes
|
||||
|
||||
Define a multi-segment envelope for a parameter. Provide a start value, then pairs of target and duration.
|
||||
|
||||
```forth
|
||||
saw s 0 1 0.1 0.7 0.5 0 8 env gain .
|
||||
```
|
||||
|
||||
This creates: start at `0`, rise to `1` in `0.1` steps, drop to `0.7` in `0.5` steps, fall to `0` in `8` steps.
|
||||
|
||||
Stack effect: `( start target1 dur1 [target2 dur2 ...] -- str )`
|
||||
|
||||
## Combining
|
||||
|
||||
Modulation words return strings, so they compose naturally with the rest of the language. Use them anywhere a parameter value is expected.
|
||||
|
||||
```forth
|
||||
saw s
|
||||
200 4000 4 lfo lpf
|
||||
0.3 0.7 8 tlfo pan
|
||||
0 1 0.1 0.7 0.5 0 8 env gain
|
||||
.
|
||||
```
|
||||
65
docs/engine/distortion.md
Normal file
65
docs/engine/distortion.md
Normal file
@@ -0,0 +1,65 @@
|
||||
# Distortion
|
||||
|
||||
Distortion effects add harmonics by nonlinearly shaping the waveform.
|
||||
|
||||
## Saturation
|
||||
|
||||
Soft saturation using the transfer function `x / (1 + k|x|)`.
|
||||
|
||||
```forth
|
||||
saw 2 distort .
|
||||
saw 8 distort 0.5 distortvol . ( with volume compensation )
|
||||
```
|
||||
|
||||
| Parameter | Range | Description |
|
||||
|-----------|-------|-------------|
|
||||
| `distort` | 0+ | Saturation amount |
|
||||
| `distortvol` | 0-1 | Output volume |
|
||||
|
||||
## Wavefolding
|
||||
|
||||
Wavefolding reflects the signal when it exceeds ±1, using `sin(x × amount × π/2)`.
|
||||
|
||||
```forth
|
||||
sine 4 fold .
|
||||
```
|
||||
|
||||
| Parameter | Range | Description |
|
||||
|-----------|-------|-------------|
|
||||
| `fold` | 0+ | Fold amount |
|
||||
|
||||
## Wavewrapping
|
||||
|
||||
Wavewrapping applies modulo to wrap the signal into the -1 to 1 range.
|
||||
|
||||
```forth
|
||||
saw 3 wrap .
|
||||
```
|
||||
|
||||
| Parameter | Range | Description |
|
||||
|-----------|-------|-------------|
|
||||
| `wrap` | 0+ | Number of wraps |
|
||||
|
||||
## Bit Crushing
|
||||
|
||||
Bit crushing quantizes the signal to fewer amplitude levels.
|
||||
|
||||
```forth
|
||||
snare 6 crush . ( 6-bit = 32 levels )
|
||||
```
|
||||
|
||||
| Parameter | Range | Description |
|
||||
|-----------|-------|-------------|
|
||||
| `crush` | 1-16 | Bit depth |
|
||||
|
||||
## Sample Rate Reduction
|
||||
|
||||
Sample rate reduction holds each sample for multiple output samples.
|
||||
|
||||
```forth
|
||||
hat 4 coarse . ( 1/4 effective sample rate )
|
||||
```
|
||||
|
||||
| Parameter | Range | Description |
|
||||
|-----------|-------|-------------|
|
||||
| `coarse` | 1+ | Reduction factor (1 = bypass) |
|
||||
131
docs/engine/filters.md
Normal file
131
docs/engine/filters.md
Normal file
@@ -0,0 +1,131 @@
|
||||
# Filters
|
||||
|
||||
Filters attenuate frequencies above or below a cutoff point.
|
||||
|
||||
## Lowpass Filter
|
||||
|
||||
The lowpass filter (`lpf`) attenuates frequencies above the cutoff.
|
||||
|
||||
```forth
|
||||
saw 1000 lpf . ( cut above 1000 Hz )
|
||||
saw 500 lpf 0.8 lpq . ( with resonance )
|
||||
```
|
||||
|
||||
| Parameter | Range | Description |
|
||||
|-----------|-------|-------------|
|
||||
| `lpf` | Hz | Cutoff frequency |
|
||||
| `lpq` | 0-1 | Resonance (peak at cutoff) |
|
||||
|
||||
## Highpass Filter
|
||||
|
||||
The highpass filter (`hpf`) attenuates frequencies below the cutoff.
|
||||
|
||||
```forth
|
||||
kick 200 hpf . ( cut below 200 Hz )
|
||||
pad 400 hpf 0.3 hpq . ( with resonance )
|
||||
```
|
||||
|
||||
| Parameter | Range | Description |
|
||||
|-----------|-------|-------------|
|
||||
| `hpf` | Hz | Cutoff frequency |
|
||||
| `hpq` | 0-1 | Resonance |
|
||||
|
||||
## Bandpass Filter
|
||||
|
||||
The bandpass filter (`bpf`) attenuates frequencies outside a band around the center frequency.
|
||||
|
||||
```forth
|
||||
noise 1000 bpf 0.7 bpq . ( narrow band around 1000 Hz )
|
||||
```
|
||||
|
||||
| Parameter | Range | Description |
|
||||
|-----------|-------|-------------|
|
||||
| `bpf` | Hz | Center frequency |
|
||||
| `bpq` | 0-1 | Resonance (narrower band) |
|
||||
|
||||
## Filter Slope
|
||||
|
||||
The `ftype` parameter sets the filter slope (rolloff steepness).
|
||||
|
||||
| Value | Slope |
|
||||
|-------|-------|
|
||||
| `1` | 12 dB/octave |
|
||||
| `2` | 24 dB/octave (default) |
|
||||
| `3` | 48 dB/octave |
|
||||
|
||||
```forth
|
||||
saw 800 lpf 3 ftype . ( 48 dB/oct lowpass )
|
||||
```
|
||||
|
||||
## Filter Envelope
|
||||
|
||||
Filters can be modulated by an ADSR envelope. The envelope multiplies the base cutoff:
|
||||
|
||||
```
|
||||
final_cutoff = lpf + (lpe × envelope × lpf)
|
||||
```
|
||||
|
||||
When the envelope is at 1.0 and `lpe` is 1.0, the cutoff doubles. When the envelope is at 0, the cutoff equals `lpf`.
|
||||
|
||||
```forth
|
||||
saw 200 lpf 2 lpe 0.01 lpa 0.3 lpd . ( cutoff sweeps from 600 Hz down to 200 Hz )
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
|-----------|-------------|
|
||||
| `lpe` | Envelope depth (multiplier, 1.0 = double cutoff at peak) |
|
||||
| `lpa` | Attack time in seconds |
|
||||
| `lpd` | Decay time in seconds |
|
||||
| `lps` | Sustain level (0-1) |
|
||||
| `lpr` | Release time in seconds |
|
||||
|
||||
The same pattern works for highpass (`hpe`, `hpa`, etc.) and bandpass (`bpe`, `bpa`, etc.).
|
||||
|
||||
## Ladder Filters
|
||||
|
||||
Ladder filters use a different algorithm (Moog-style) with self-oscillation at high resonance.
|
||||
|
||||
```forth
|
||||
saw 800 llpf 0.7 llpq . ( ladder lowpass )
|
||||
saw 300 lhpf 0.5 lhpq . ( ladder highpass )
|
||||
saw 1000 lbpf 0.8 lbpq . ( ladder bandpass )
|
||||
```
|
||||
|
||||
| Parameter | Range | Description |
|
||||
|-----------|-------|-------------|
|
||||
| `llpf` | Hz | Ladder lowpass cutoff |
|
||||
| `llpq` | 0-1 | Ladder lowpass resonance |
|
||||
| `lhpf` | Hz | Ladder highpass cutoff |
|
||||
| `lhpq` | 0-1 | Ladder highpass resonance |
|
||||
| `lbpf` | Hz | Ladder bandpass cutoff |
|
||||
| `lbpq` | 0-1 | Ladder bandpass resonance |
|
||||
|
||||
Ladder filters share the lowpass envelope parameters (`lpe`, `lpa`, etc.).
|
||||
|
||||
## EQ
|
||||
|
||||
The 3-band EQ applies shelf and peak filters at fixed frequencies.
|
||||
|
||||
```forth
|
||||
kick 3 eqlo -2 eqhi . ( +3 dB at 200 Hz, -2 dB at 5000 Hz )
|
||||
snare 2 eqmid . ( +2 dB at 1000 Hz )
|
||||
```
|
||||
|
||||
| Parameter | Frequency | Type |
|
||||
|-----------|-----------|------|
|
||||
| `eqlo` | 200 Hz | Low shelf (dB) |
|
||||
| `eqmid` | 1000 Hz | Peak (dB) |
|
||||
| `eqhi` | 5000 Hz | High shelf (dB) |
|
||||
|
||||
## Tilt EQ
|
||||
|
||||
Tilt EQ applies a high shelf at 800 Hz with up to ±6 dB gain.
|
||||
|
||||
```forth
|
||||
pad -0.5 tilt . ( -3 dB above 800 Hz )
|
||||
hat 0.5 tilt . ( +3 dB above 800 Hz )
|
||||
```
|
||||
|
||||
| Parameter | Range | Description |
|
||||
|-----------|-------|-------------|
|
||||
| `tilt` | -1 to 1 | High shelf gain (-1 = -6 dB, 0 = flat, 1 = +6 dB) |
|
||||
55
docs/engine/intro.md
Normal file
55
docs/engine/intro.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Introduction
|
||||
|
||||
Cagire includes an audio engine called `Doux`. No external software is needed to make sound. `Doux` is an opinionated, semi-modular synthesizer. It was designed for live coding environments and works by receiving command strings that describe sounds. Despite its fixed architecture,`Doux` is extremely versatile and will likely cover most of the audio needs of a live coder.
|
||||
|
||||
## How It Works
|
||||
|
||||
When you write a Forth script and emit (`.`), the script produces a command string. This command travels to the audio engine, which interprets it and creates a voice. The voice plays until its envelope finishes or until it is killed by another voice. You can also spawn infinite voices, but you will need to manage their lifecycle manually, otherwise they will never stop.
|
||||
|
||||
```forth
|
||||
saw s c4 note 0.8 gain 0.3 verb .
|
||||
```
|
||||
|
||||
## Voices
|
||||
|
||||
Each `emit` (`.`) creates or manages a voice by sending parameters. Voices are independent sound generators with their own oscillator, envelope, and effects. The engine can run many voices at once (up to `128`, default `32`). When you exceed the voice limit, the oldest voice is stolen (a process called _round robin scheduling_). You can monitor voice usage on the Engine page:
|
||||
|
||||
- **Active voices**: how many are playing right now.
|
||||
- **Peak voices**: the maximum reached since last reset.
|
||||
|
||||
Press `r` on the Engine page to reset the peak counter.
|
||||
|
||||
## Parameters
|
||||
|
||||
After selecting a sound source, you add parameters. Each parameter word takes a value from the stack and stores it in the command register:
|
||||
|
||||
```forth
|
||||
saw s
|
||||
c4 note ;; pitch
|
||||
0.5 gain ;; volume
|
||||
0.1 attack ;; envelope attack time
|
||||
2000 lpf ;; lowpass filter at 2kHz
|
||||
0.3 verb ;; reverb mix
|
||||
.
|
||||
```
|
||||
|
||||
Parameters can appear in any order. They accumulate until you emit. You can clear the register using the `clear` word.
|
||||
|
||||
## Controlling Existing Voices
|
||||
|
||||
You can emit without a sound name. In this case, no new voice is created. Instead, the parameters are sent to control an existing voice. Use `voice` with an ID to target a specific voice:
|
||||
|
||||
```forth
|
||||
0 voice 500 freq . ;; change frequency on voice 0
|
||||
```
|
||||
|
||||
This is useful for modulating long-running or infinite voices. Set up a drone on one step with a known voice ID, then tweak its parameters from other steps.
|
||||
|
||||
## Hush and Panic
|
||||
|
||||
Two emergency controls exist on the Engine page:
|
||||
|
||||
- `h` - **Hush**: gracefully fade out all voices
|
||||
- `p` - **Panic**: immediately kill all voices
|
||||
|
||||
Use hush when things get too loud. Use panic when things go wrong.
|
||||
132
docs/engine/modulation.md
Normal file
132
docs/engine/modulation.md
Normal file
@@ -0,0 +1,132 @@
|
||||
# Modulation
|
||||
|
||||
Modulation effects vary parameters over time using LFOs or envelopes.
|
||||
|
||||
## Vibrato
|
||||
|
||||
Vibrato modulates pitch with an LFO.
|
||||
|
||||
```forth
|
||||
saw 5 vib 0.5 vibmod . ( 5 Hz, 0.5 semitone depth )
|
||||
```
|
||||
|
||||
| Parameter | Range | Description |
|
||||
|-----------|-------|-------------|
|
||||
| `vib` | Hz | LFO rate |
|
||||
| `vibmod` | semitones | Modulation depth |
|
||||
| `vibshape` | shape | LFO waveform (sine, tri, saw, square) |
|
||||
|
||||
## Pitch Envelope
|
||||
|
||||
The pitch envelope applies an ADSR to the oscillator frequency.
|
||||
|
||||
```forth
|
||||
sine 100 freq 24 penv 0.001 patt 0.1 pdec .
|
||||
```
|
||||
|
||||
| Parameter | Description |
|
||||
|-----------|-------------|
|
||||
| `penv` | Envelope depth in semitones |
|
||||
| `patt` | Attack time in seconds |
|
||||
| `pdec` | Decay time in seconds |
|
||||
| `psus` | Sustain level (0-1) |
|
||||
| `prel` | Release time in seconds |
|
||||
|
||||
## Glide
|
||||
|
||||
Glide interpolates between pitch changes over time.
|
||||
|
||||
```forth
|
||||
saw c4 0.1 glide . ( 100ms glide )
|
||||
```
|
||||
|
||||
| Parameter | Range | Description |
|
||||
|-----------|-------|-------------|
|
||||
| `glide` | seconds | Glide time |
|
||||
|
||||
## FM Synthesis
|
||||
|
||||
FM modulates the carrier frequency with a modulator oscillator.
|
||||
|
||||
```forth
|
||||
sine 440 freq 2 fm 2 fmh . ( modulator at 2× carrier frequency )
|
||||
```
|
||||
|
||||
| Parameter | Range | Description |
|
||||
|-----------|-------|-------------|
|
||||
| `fm` | 0+ | Modulation index |
|
||||
| `fmh` | ratio | Harmonic ratio (modulator / carrier) |
|
||||
| `fmshape` | shape | Modulator waveform |
|
||||
|
||||
FM has its own envelope (`fme`, `fma`, `fmd`, `fms`, `fmr`).
|
||||
|
||||
## Amplitude Modulation
|
||||
|
||||
AM multiplies the signal by an LFO.
|
||||
|
||||
```forth
|
||||
pad 4 am 0.5 amdepth . ( 4 Hz tremolo )
|
||||
```
|
||||
|
||||
| Parameter | Range | Description |
|
||||
|-----------|-------|-------------|
|
||||
| `am` | Hz | LFO rate |
|
||||
| `amdepth` | 0-1 | Modulation depth |
|
||||
| `amshape` | shape | LFO waveform |
|
||||
|
||||
## Ring Modulation
|
||||
|
||||
Ring modulation multiplies two signals, producing sum and difference frequencies.
|
||||
|
||||
```forth
|
||||
saw 150 rm 0.8 rmdepth . ( ring mod at 150 Hz )
|
||||
```
|
||||
|
||||
| Parameter | Range | Description |
|
||||
|-----------|-------|-------------|
|
||||
| `rm` | Hz | Modulator frequency |
|
||||
| `rmdepth` | 0-1 | Modulation depth |
|
||||
| `rmshape` | shape | Modulator waveform |
|
||||
|
||||
## Phaser
|
||||
|
||||
Phaser sweeps notches through the frequency spectrum using allpass filters.
|
||||
|
||||
```forth
|
||||
pad 0.5 phaser 0.6 phaserdepth .
|
||||
```
|
||||
|
||||
| Parameter | Range | Description |
|
||||
|-----------|-------|-------------|
|
||||
| `phaser` | Hz | Sweep rate |
|
||||
| `phaserdepth` | 0-1 | Sweep depth |
|
||||
| `phasersweep` | cents | Sweep range |
|
||||
| `phasercenter` | Hz | Center frequency |
|
||||
|
||||
## Flanger
|
||||
|
||||
Flanger mixes the signal with a short modulated delay (0.5-10ms).
|
||||
|
||||
```forth
|
||||
pad 0.3 flanger 0.7 flangerdepth 0.5 flangerfeedback .
|
||||
```
|
||||
|
||||
| Parameter | Range | Description |
|
||||
|-----------|-------|-------------|
|
||||
| `flanger` | Hz | Modulation rate |
|
||||
| `flangerdepth` | 0-1 | Modulation depth |
|
||||
| `flangerfeedback` | 0-0.95 | Feedback amount |
|
||||
|
||||
## Chorus
|
||||
|
||||
Chorus uses multiple modulated delay lines with 120° phase offset for stereo width.
|
||||
|
||||
```forth
|
||||
pad 1 chorus 0.4 chorusdepth 20 chorusdelay .
|
||||
```
|
||||
|
||||
| Parameter | Range | Description |
|
||||
|-----------|-------|-------------|
|
||||
| `chorus` | Hz | Modulation rate |
|
||||
| `chorusdepth` | 0-1 | Modulation depth |
|
||||
| `chorusdelay` | ms | Base delay time |
|
||||
126
docs/engine/samples.md
Normal file
126
docs/engine/samples.md
Normal file
@@ -0,0 +1,126 @@
|
||||
# Samples
|
||||
|
||||
The `sample` source plays audio files from disk with pitch tracking.
|
||||
|
||||
## Loading Samples
|
||||
|
||||
There are two ways to load samples:
|
||||
|
||||
* **From the app:** Navigate to the Engine view and find the Samples section. Press `A` to open a file browser, then select a folder containing your samples. Press `D` to remove the last added path.
|
||||
|
||||
* **From the command line:** Use the `-s` flag when launching Cagire:
|
||||
|
||||
```
|
||||
cagire -s ~/samples -s ~/more-samples
|
||||
```
|
||||
|
||||
The engine scans these directories and builds a registry of available samples. Samples load in the background without blocking audio. Supported file formats are `.wav`, `.mp3`, `.ogg`, `.flac` and `.aiff`.
|
||||
|
||||
## Folder Organization
|
||||
|
||||
```
|
||||
samples/
|
||||
├── kick.wav → "kick"
|
||||
├── snare.wav → "snare"
|
||||
└── hats/
|
||||
├── closed.wav → "hats" n 0
|
||||
├── open.wav → "hats" n 1
|
||||
└── pedal.wav → "hats" n 2
|
||||
```
|
||||
|
||||
Folders at the root of your directory are used as the name of a sample bank. Folders create sample banks where each file gets an index. Files are sorted alphabetically and assigned indices starting from `0`.
|
||||
|
||||
## Playing Samples
|
||||
|
||||
```forth
|
||||
kick sound . ( play kick sample )
|
||||
hats sound 2 n . ( play third hat sample )
|
||||
snare sound 0.5 speed . ( play snare at half speed )
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Range | Description |
|
||||
|-----------|-------|-------------|
|
||||
| `n` | 0+ | Sample index within a folder (wraps around) |
|
||||
| `begin` | 0-1 | Playback start position |
|
||||
| `end` | 0-1 | Playback end position |
|
||||
| `speed` | any | Playback speed multiplier |
|
||||
| `freq` | Hz | Base frequency for pitch tracking |
|
||||
| `fit` | seconds | Stretch/compress sample to fit duration |
|
||||
| `cut` | 0+ | Choke group |
|
||||
|
||||
## Slicing with Begin/End
|
||||
|
||||
The `begin` and `end` parameters define what portion of the sample plays. Values are normalized from 0 (start) to 1 (end).
|
||||
|
||||
```forth
|
||||
kick sound 0.25 begin 0.75 end . ( play middle half )
|
||||
kick sound 0.5 begin . ( play second half )
|
||||
kick sound 0.5 end . ( play first half )
|
||||
```
|
||||
|
||||
If begin is greater than end, they swap automatically.
|
||||
|
||||
## Speed and Pitch
|
||||
|
||||
The `speed` parameter affects both tempo and pitch. A speed of 2 plays twice as fast and an octave higher.
|
||||
|
||||
```forth
|
||||
snare sound 2 speed . ( double speed, octave up )
|
||||
snare sound 0.5 speed . ( half speed, octave down )
|
||||
snare sound -1 speed . ( play in reverse )
|
||||
```
|
||||
|
||||
For pitched playback, use `freq` or note names. The sample's base frequency defaults to middle C (261.626 Hz).
|
||||
|
||||
```forth
|
||||
kick sound 440 freq . ( play at A4 )
|
||||
kick sound c4 . ( play at C4 )
|
||||
```
|
||||
|
||||
Negative speed will reverse the sample and play it backwards.
|
||||
|
||||
```forth
|
||||
crow sound -1 speed . ( play backwards at nominal speed )
|
||||
crow sound -4 speed . ( play backwards, 4 times faster )
|
||||
```
|
||||
|
||||
## Fitting to Duration
|
||||
|
||||
The `fit` parameter stretches or compresses a sample to match a target duration in seconds. This adjusts speed automatically.
|
||||
|
||||
```forth
|
||||
kick sound 0.25 fit . ( fit kick into quarter second )
|
||||
snare sound beat fit . ( fit snare to one beat )
|
||||
```
|
||||
|
||||
## Choke Groups
|
||||
|
||||
The `cut` parameter assigns a sample to a choke group. When a new sample with the same cut value plays, it kills any currently playing samples in that group.
|
||||
|
||||
```forth
|
||||
hihat_closed sound 1 cut . ( choke group 1 )
|
||||
hihat_open sound 1 cut . ( kills closed hat, starts open )
|
||||
```
|
||||
|
||||
This is essential for realistic hi-hat behavior where open and closed hats shouldn't overlap.
|
||||
|
||||
## Bank Variations
|
||||
|
||||
Add `_suffix` to sample names to create variations that share the same base name.
|
||||
|
||||
```
|
||||
samples/
|
||||
├── kick.wav
|
||||
├── kick_hard.wav
|
||||
├── kick_soft.wav
|
||||
```
|
||||
|
||||
Select variations with the `bank` parameter:
|
||||
|
||||
```forth
|
||||
kick sound . ( plays kick.wav )
|
||||
kick sound hard bank . ( plays kick_hard.wav )
|
||||
kick sound soft bank . ( plays kick_soft.wav )
|
||||
```
|
||||
125
docs/engine/settings.md
Normal file
125
docs/engine/settings.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# Settings
|
||||
|
||||
The audio engine can be configured through the Engine page or via command-line arguments. Settings are saved and restored between sessions.
|
||||
|
||||
## Engine Page
|
||||
|
||||
Press `Ctrl+Right` until you reach the Engine page. Here you can see the engine status and adjust settings.
|
||||
|
||||
### Display
|
||||
|
||||
The right side of the page shows visualizations:
|
||||
|
||||
- **Scope**: oscilloscope showing the audio waveform
|
||||
- **Spectrum**: 32-band frequency analyzer
|
||||
|
||||
### Settings
|
||||
|
||||
Navigate with arrow keys, adjust values with left/right:
|
||||
|
||||
- **Output Device**: where sound goes (speakers, headphones, interface).
|
||||
- **Input Device**: what audio input source to use (microphone, line-in, etc.).
|
||||
- **Channels**: number of output channels (2 for stereo).
|
||||
- **Buffer Size**: audio buffer in samples (64-4096).
|
||||
- **Max Voices**: polyphony limit (1-128, default 32).
|
||||
|
||||
### Buffer Size
|
||||
|
||||
Smaller buffers mean lower latency but higher CPU load. Larger buffers are safer but feel sluggish.
|
||||
|
||||
| Buffer | Latency at 44.1kHz |
|
||||
|--------|-------------------|
|
||||
| 64 | ~1.5ms |
|
||||
| 128 | ~3ms |
|
||||
| 256 | ~6ms |
|
||||
| 512 | ~12ms |
|
||||
| 1024 | ~23ms |
|
||||
|
||||
Start with 512. Lower it if you need tighter timing. Raise it if you hear glitches.
|
||||
|
||||
## Samples
|
||||
|
||||
The engine indexes audio files from your sample directories. Add directories with `A`, remove with `D`. The sample count shows how many files are indexed.
|
||||
|
||||
### Supported Formats
|
||||
|
||||
- WAV (.wav)
|
||||
- MP3 (.mp3)
|
||||
- OGG Vorbis (.ogg)
|
||||
- FLAC (.flac)
|
||||
- AIFF (.aiff, .aif)
|
||||
- AAC (.aac)
|
||||
- M4A (.m4a)
|
||||
|
||||
### Lazy Loading
|
||||
|
||||
Samples are not loaded into memory at startup. They are decoded on demand when first played. This means you can have thousands of samples indexed without using much RAM until you actually use them.
|
||||
|
||||
### Folder Organization
|
||||
|
||||
The scanner looks at top-level files and one level of subdirectories:
|
||||
|
||||
```
|
||||
samples/
|
||||
├── kick.wav -> "kick"
|
||||
├── snare.wav -> "snare"
|
||||
├── hats/
|
||||
│ ├── closed.wav -> "hats" n 0
|
||||
│ ├── open.wav -> "hats" n 1
|
||||
│ └── pedal.wav -> "hats" n 2
|
||||
└── breaks/
|
||||
├── amen.wav -> "breaks" n 0
|
||||
└── think.wav -> "breaks" n 1
|
||||
```
|
||||
|
||||
Top-level files are named by their filename (without extension). Files inside folders are sorted alphabetically and numbered starting from 0.
|
||||
|
||||
### Playing Samples
|
||||
|
||||
Reference samples by name:
|
||||
|
||||
```forth
|
||||
kick s . ;; play kick.wav
|
||||
snare s 0.5 gain . ;; play snare at half volume
|
||||
```
|
||||
|
||||
For samples in folders, use `n` to select which one:
|
||||
|
||||
```forth
|
||||
hats s 0 n . ;; play hats/closed.wav (index 0)
|
||||
hats s 1 n . ;; play hats/open.wav (index 1)
|
||||
hats s 2 n . ;; play hats/pedal.wav (index 2)
|
||||
```
|
||||
|
||||
The index wraps around. If you have 3 samples and request `5 n`, you get index 2 (because 5 % 3 = 2).
|
||||
|
||||
### Sample Variations with Bank
|
||||
|
||||
The `bank` parameter lets you organize variations:
|
||||
|
||||
```
|
||||
samples/
|
||||
├── kick.wav -> default
|
||||
├── kick_a.wav -> bank "a"
|
||||
├── kick_b.wav -> bank "b"
|
||||
└── kick_hard.wav -> bank "hard"
|
||||
```
|
||||
|
||||
```forth
|
||||
kick s . ;; plays kick.wav
|
||||
kick s a bank . ;; plays kick_a.wav
|
||||
kick s hard bank . ;; plays kick_hard.wav
|
||||
```
|
||||
|
||||
If the banked version does not exist, it falls back to the default.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
* **No sound**: Check output device selection.
|
||||
* Try the test sound (`t`) on Engine page).
|
||||
|
||||
* **Glitches/crackling**: Increase buffer size, restart the Engine.
|
||||
|
||||
* **High CPU**: Reduce max voices. Disable scope/spectrum. Increase buffer size.
|
||||
|
||||
* **Samples not found**: Check sample directories on Engine page. Filenames are case-sensitive on some systems.
|
||||
92
docs/engine/sources.md
Normal file
92
docs/engine/sources.md
Normal file
@@ -0,0 +1,92 @@
|
||||
# Sources
|
||||
|
||||
The audio engine provides a variety of sound sources. Use the `sound` word (or `s` for short) to select one.
|
||||
|
||||
## Basic Oscillators
|
||||
|
||||
| Name | Description |
|
||||
|------|-------------|
|
||||
| `sine` | Pure sinusoid, smooth and mellow |
|
||||
| `tri` | Triangle wave, warmer than sine, naturally band-limited |
|
||||
| `saw` | Bright sawtooth with anti-aliasing, rich in harmonics |
|
||||
| `zaw` | Raw sawtooth without anti-aliasing, lo-fi character |
|
||||
| `pulse`, `square` | Variable-width pulse wave with anti-aliasing |
|
||||
| `pulze`, `zquare` | Raw pulse without anti-aliasing, 8-bit feel |
|
||||
|
||||
`pulse` and `pulze` respond to the `pw` parameter (0.0-1.0) for pulse width. At 0.5 you get a square wave.
|
||||
|
||||
### Phase Shaping
|
||||
|
||||
All oscillators support phase shaping for timbral variation:
|
||||
|
||||
| Parameter | Range | Effect |
|
||||
|-----------|-------|--------|
|
||||
| `size` | 0-256 | Phase quantization (lo-fi, chiptune). |
|
||||
| `mult` | 0.25-16 | Phase multiplier (harmonic overtones). |
|
||||
| `warp` | -1 to 1 | Power curve asymmetry. |
|
||||
| `mirror` | 0-1 | Phase reflection point. |
|
||||
|
||||
These are super useful to get the most out of your oscillators.
|
||||
|
||||
### Sub Oscillator
|
||||
|
||||
Add a sub oscillator layer to any basic oscillator:
|
||||
|
||||
| Parameter | Range | Effect |
|
||||
|-----------|-------|--------|
|
||||
| `sub` | 0-1 | Mix level |
|
||||
| `suboct` | 1-3 | Octaves below main. |
|
||||
| `subwave` | tri/sine/square | Sub waveform. |
|
||||
|
||||
## Noise
|
||||
|
||||
| Name | Description |
|
||||
|------|-------------|
|
||||
| `white` | Equal energy across all frequencies, bright and hissy. |
|
||||
| `pink` | -3dB/octave rolloff, equal energy per octave, natural. |
|
||||
| `brown` | -6dB/octave rolloff, deep rumbling, random walk. |
|
||||
|
||||
Noise sources ignore pitch. Use filters to shape the spectrum.
|
||||
|
||||
## Live Input
|
||||
|
||||
| Name | Description |
|
||||
|------|-------------|
|
||||
| `live`, `livein`, `mic` | Live audio input from microphone or line-in |
|
||||
|
||||
All filter and effect parameters apply to the input signal.
|
||||
|
||||
## Plaits Engines
|
||||
|
||||
The Plaits engines come from Mutable Instruments and provide a range of synthesis methods. Beware, these sources can be quite CPU hungry. All share three control parameters (`0.0`-`1.0`):
|
||||
|
||||
| Parameter | Controls |
|
||||
|-----------|----------|
|
||||
| `harmonics` | Harmonic content, structure, detuning. |
|
||||
| `timbre` | Brightness, tonal color. |
|
||||
| `morph` | Smooth transitions between variations. |
|
||||
|
||||
### Pitched
|
||||
|
||||
| Name | Description |
|
||||
|------|-------------|
|
||||
| `modal` | Struck/plucked resonant bodies (strings, plates, tubes). |
|
||||
| `va`, `analog` | Virtual analog with waveform sync and crossfading. |
|
||||
| `ws`, `waveshape` | Waveshaper and wavefolder. |
|
||||
| `fm2` | Two-operator FM synthesis with feedback. |
|
||||
| `grain` | Granular formant oscillator (vowel-like). |
|
||||
| `additive` | Harmonic additive synthesis. |
|
||||
| `wavetable` | Built-in Plaits wavetables (four 8x8 banks). |
|
||||
| `chord` | Four-note chord generator. |
|
||||
| `swarm` | Granular cloud of enveloped sawtooths. |
|
||||
| `pnoise` | Clocked noise through multimode filter. |
|
||||
|
||||
### Percussion
|
||||
|
||||
| Name | Description |
|
||||
|------|-------------|
|
||||
| `kick`, `bass` | 808-style bass drum. |
|
||||
| `snare` | Analog snare drum with tone/noise balance. |
|
||||
| `hihat`, `hat` | Metallic 808-style hi-hat. |
|
||||
|
||||
Percussions are super hard to use correctly, because you need to tweak their envelope correctly.
|
||||
118
docs/engine/space.md
Normal file
118
docs/engine/space.md
Normal file
@@ -0,0 +1,118 @@
|
||||
# Space & Time
|
||||
|
||||
Spatial effects position sounds in the stereo field and add depth through delays and reverbs.
|
||||
|
||||
## Pan
|
||||
|
||||
Pan positions a sound in the stereo field.
|
||||
|
||||
```forth
|
||||
hat -0.5 pan . ( slightly left )
|
||||
perc 1 pan . ( hard right )
|
||||
kick 0 pan . ( center )
|
||||
```
|
||||
|
||||
| Parameter | Range | Description |
|
||||
|-----------|-------|-------------|
|
||||
| `pan` | -1 to 1 | Stereo position (-1 = left, 0 = center, 1 = right) |
|
||||
|
||||
## Width
|
||||
|
||||
Width controls the stereo spread using mid-side processing.
|
||||
|
||||
```forth
|
||||
pad 1.5 width . ( wider stereo )
|
||||
pad 0 width . ( mono )
|
||||
```
|
||||
|
||||
| Parameter | Range | Description |
|
||||
|-----------|-------|-------------|
|
||||
| `width` | 0+ | Stereo width (0 = mono, 1 = unchanged, 2 = exaggerated) |
|
||||
|
||||
## Haas Effect
|
||||
|
||||
The Haas effect delays one channel slightly, creating a sense of stereo width and spatial placement.
|
||||
|
||||
```forth
|
||||
snare 15 haas . ( 15ms delay on right channel )
|
||||
```
|
||||
|
||||
| Parameter | Range | Description |
|
||||
|-----------|-------|-------------|
|
||||
| `haas` | ms | Delay time (1-10ms = subtle width, 10-35ms = distinct echo) |
|
||||
|
||||
## Delay
|
||||
|
||||
Delay is a send effect that creates echoes. The `delay` parameter sets how much signal is sent to the delay bus.
|
||||
|
||||
```forth
|
||||
snare 0.3 delay 0.25 delaytime 0.5 delayfeedback .
|
||||
```
|
||||
|
||||
| Parameter | Range | Description |
|
||||
|-----------|-------|-------------|
|
||||
| `delay` | 0-1 | Send level |
|
||||
| `delaytime` | seconds | Delay time |
|
||||
| `delayfeedback` | 0-0.95 | Feedback amount |
|
||||
| `delaytype` | type | Delay algorithm |
|
||||
|
||||
### Delay Types
|
||||
|
||||
| Type | Description |
|
||||
|------|-------------|
|
||||
| `standard` | Clean digital repeats |
|
||||
| `pingpong` | Bounces between left and right |
|
||||
| `tape` | Each repeat gets darker (analog warmth) |
|
||||
| `multitap` | 4 taps with swing control via feedback |
|
||||
|
||||
```forth
|
||||
snare 0.4 delay pingpong delaytype .
|
||||
pad 0.3 delay tape delaytype .
|
||||
```
|
||||
|
||||
## Reverb
|
||||
|
||||
Reverb is a send effect that simulates acoustic spaces. The `verb` parameter sets the send level.
|
||||
|
||||
```forth
|
||||
snare 0.2 verb 2 verbdecay .
|
||||
pad 0.4 verb 4 verbdecay 0.7 verbdamp .
|
||||
```
|
||||
|
||||
| Parameter | Range | Description |
|
||||
|-----------|-------|-------------|
|
||||
| `verb` | 0-1 | Send level |
|
||||
| `verbdecay` | seconds | Reverb tail length |
|
||||
| `verbdamp` | 0-1 | High frequency damping |
|
||||
| `verbpredelay` | ms | Initial delay before reverb |
|
||||
| `verbdiff` | 0-1 | Diffusion (smears transients) |
|
||||
| `verbtype` | type | Reverb algorithm |
|
||||
|
||||
### Reverb Types
|
||||
|
||||
| Type | Description |
|
||||
|------|-------------|
|
||||
| `dattorro` | Plate reverb, bright and metallic shimmer |
|
||||
| `fdn` | Hall reverb, dense and smooth |
|
||||
|
||||
```forth
|
||||
snare 0.3 verb dattorro verbtype . ( plate )
|
||||
pad 0.5 verb fdn verbtype . ( hall )
|
||||
```
|
||||
|
||||
## Comb Filter
|
||||
|
||||
The comb filter creates resonant pitched delays, useful for Karplus-Strong string synthesis and metallic tones.
|
||||
|
||||
```forth
|
||||
white 0.5 comb 220 combfreq 0.9 combfeedback . ( plucked string )
|
||||
```
|
||||
|
||||
| Parameter | Range | Description |
|
||||
|-----------|-------|-------------|
|
||||
| `comb` | 0-1 | Send level |
|
||||
| `combfreq` | Hz | Resonant frequency |
|
||||
| `combfeedback` | 0-0.99 | Feedback (higher = longer decay) |
|
||||
| `combdamp` | 0-1 | High frequency damping |
|
||||
|
||||
Higher feedback creates longer, ringing tones. Add damping for more natural string-like decay.
|
||||
87
docs/engine/wavetable.md
Normal file
87
docs/engine/wavetable.md
Normal file
@@ -0,0 +1,87 @@
|
||||
# Wavetables
|
||||
|
||||
Any sample can be played as a wavetable. When you use the `scan` parameter, the sample automatically becomes a pitched oscillator that can morph between cycles.
|
||||
|
||||
## What is a Wavetable?
|
||||
|
||||
A wavetable is a series of single-cycle waveforms stored end-to-end in an audio file. Each cycle is a complete waveform that starts and ends at zero crossing, allowing it to loop seamlessly at any pitch.
|
||||
|
||||
```
|
||||
Sample: [cycle 0][cycle 1][cycle 2][cycle 3]
|
||||
↑ ↑
|
||||
scan 0 scan 1
|
||||
```
|
||||
|
||||
The oscillator reads through one cycle at audio rate (determining pitch), while `scan` selects which cycle to play. Values between cycles crossfade smoothly, creating timbral morphing.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
Just add `scan` to any sample and it becomes a wavetable:
|
||||
|
||||
```forth
|
||||
pad 0 scan . ( play pad as wavetable, first cycle )
|
||||
pad 0.5 scan . ( blend to middle cycles )
|
||||
pad 440 freq 0 scan . ( play at A4 )
|
||||
```
|
||||
|
||||
Without `scan`, the sample plays normally. With `scan`, it becomes a looping wavetable oscillator.
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Range | Description |
|
||||
|-----------|-------|-------------|
|
||||
| `scan` | 0-1 | Position in wavetable (0 = first cycle, 1 = last) |
|
||||
| `wtlen` | samples | Cycle length in samples (0 = entire sample) |
|
||||
| `scanlfo` | Hz | LFO rate for scan modulation |
|
||||
| `scandepth` | 0-1 | LFO modulation depth |
|
||||
| `scanshape` | shape | LFO waveform |
|
||||
|
||||
## Cycle Length
|
||||
|
||||
The `wtlen` parameter tells the engine how many samples make up one cycle. This must match how the wavetable was created, otherwise you'll hear the wrong pitch or glitchy artifacts.
|
||||
|
||||
```forth
|
||||
pad 0 scan 2048 wtlen . ( Serum-style 2048-sample cycles )
|
||||
pad 0 scan 1024 wtlen . ( 1024-sample cycles )
|
||||
```
|
||||
|
||||
Common cycle lengths are powers of two: 256, 512, 1024, 2048. Serum uses 2048 samples per cycle. The number of cycles in a wavetable is the total sample length divided by `wtlen`. If `wtlen` is 0 (default), the entire sample is treated as one cycle. The sample still loops as a pitched oscillator, but `scan` has no morphing effect since there's only one cycle.
|
||||
|
||||
## Scanning
|
||||
|
||||
The `scan` parameter selects which cycle to play:
|
||||
|
||||
```forth
|
||||
pad 0 scan . ( first cycle only )
|
||||
pad 0.5 scan . ( blend between middle cycles )
|
||||
pad 1 scan . ( last cycle only )
|
||||
```
|
||||
|
||||
## LFO Modulation
|
||||
|
||||
Automate the scan position with a built-in LFO:
|
||||
|
||||
```forth
|
||||
pad 0 scan 2 scanlfo 0.3 scandepth . ( 2 Hz modulation, 30% depth )
|
||||
```
|
||||
|
||||
Available LFO shapes:
|
||||
|
||||
| Shape | Description |
|
||||
|-------|-------------|
|
||||
| `sine` | Smooth oscillation (default) |
|
||||
| `tri` | Triangle wave |
|
||||
| `saw` | Sawtooth, ramps up |
|
||||
| `square` | Alternates between extremes |
|
||||
| `sh` | Sample and hold, random steps |
|
||||
|
||||
## Creating Wavetables
|
||||
|
||||
A proper wavetable file:
|
||||
|
||||
- Contains multiple single-cycle waveforms of identical length
|
||||
- Each cycle starts and ends at zero crossing for seamless looping
|
||||
- Uses power-of-two cycle lengths (256, 512, 1024, 2048)
|
||||
- Has cycles that morph smoothly from one to the next
|
||||
|
||||
You can find wavetable packs online or create your own in tools like Serum, WaveEdit, or Audacity (using zero-crossing snap). Single-cycle waveforms also work. With `wtlen` set to 0, a single-cycle sample becomes a basic pitched oscillator.
|
||||
43
docs/engine/words.md
Normal file
43
docs/engine/words.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Words & Sounds
|
||||
|
||||
Word definitions let you abstract sound design into reusable units.
|
||||
|
||||
## Defining Sounds
|
||||
|
||||
```forth
|
||||
: lead "saw" s 0.3 gain 1200 lpf ;
|
||||
```
|
||||
|
||||
Use it with different notes:
|
||||
|
||||
```forth
|
||||
c4 note lead .
|
||||
e4 note lead .
|
||||
```
|
||||
|
||||
## Self-Contained Words
|
||||
|
||||
Include the emit to make the word play directly:
|
||||
|
||||
```forth
|
||||
: kk "kick" s 1 decay . ;
|
||||
: hh "hihat" s 0.5 gain 0.5 decay . ;
|
||||
```
|
||||
|
||||
Steps become simple:
|
||||
|
||||
```forth
|
||||
kk
|
||||
0.5 at hh
|
||||
```
|
||||
|
||||
## Effect Presets
|
||||
|
||||
```forth
|
||||
: dark 800 lpf 0.6 lpq ;
|
||||
: wet 0.7 verb 8 verbdiff ;
|
||||
```
|
||||
|
||||
```forth
|
||||
c4 note saw s dark wet .
|
||||
```
|
||||
Reference in New Issue
Block a user