https://github.com/seajaysec/war-bells
Granular · glitch · delay · looper multi-effect module for the Ableton Move (Schwung framework)
https://github.com/seajaysec/war-bells
ableton-move audio-effect dsp granular looper schwung
Last synced: 29 days ago
JSON representation
Granular · glitch · delay · looper multi-effect module for the Ableton Move (Schwung framework)
- Host: GitHub
- URL: https://github.com/seajaysec/war-bells
- Owner: seajaysec
- License: agpl-3.0
- Created: 2026-06-18T07:50:53.000Z (about 1 month ago)
- Default Branch: main
- Last Pushed: 2026-06-18T16:26:53.000Z (about 1 month ago)
- Last Synced: 2026-06-18T16:29:53.954Z (about 1 month ago)
- Topics: ableton-move, audio-effect, dsp, granular, looper, schwung
- Language: C
- Homepage: https://seajaysec.github.io/war-bells/
- Size: 76.2 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# War Bells
**War Bells** is a granular-sampling / delay / looping multi-effect **module for the
Ableton Move**, built on the open-source [Schwung](https://github.com/charlesvestal/schwung)
framework. It is a hand-written C `audio_fx` plugin: eleven effects across four families,
forty-four variations, four grain envelopes, a Hold sampler, a four-mode stereo reverb with
**shimmer**, a resonant low-pass filter, pitch modulation, **scale-locked pitch**, a tempo-synced
**Motion** mod-LFO, a generative **Evolve/Dice** engine, input-ducking, a 60-second phrase looper,
eight character presets, and a 16-slot user-preset bank that saves your sounds *and* their loops.
🎛️ **[Interactive manual & live demo →](https://seajaysec.github.io/war-bells/)** ·
💬 **[Discuss on the Schwung Discord →](https://discord.com/channels/1480993331243778193/1517609182445178983)**
## The effects
Eleven effects in four families, each with four named variations:
| Family | Effects | Character |
|--------|---------|-----------|
| **Loops** | Glide · Seq · Stack | layered short loops at different speeds — rhythms & octaves |
| **Grains** | Cloud · Drone · Chain | clouds of tiny fragments — washes, drones, textures |
| **Glitch** | Arp · Cutup · Chop | real-time rearrangement — stutters & bursts |
| **Delays** | Taps · Warp | a **stereo** multi-tap delay line — rhythmic, filtered, pitched, ping-pong echoes |
Each effect's four variations have their own short labels (e.g. Stack → `oct+ / oct- / x2 /
range`, Taps → `line / swng / trip / wide`).
## Controls
War Bells is a standard Schwung `audio_fx` module. The host renders menu **pages** and maps
the **8 knobs** per page; metadata is served from the plugin (`chain_params` + `ui_hierarchy`)
so every parameter is editable on the device.
- **Root** — Preset · Effect · Variation · Activity · Repeats · **Rv Tone** · Mix · Space · Filter
- **Tone** — **Shape** · Resonance · FX Vol · **Grain Env** (Soft / Pluck / Swell / Gate) · **Scale** (Off / Maj / Min / Pent / Oct / 5th)
- **Time** — Clock (Free / Sync / Manual) · Subdivision · Tempo
- **Space FX** — Reverb (Room / Dark / Hall / Vast) · **Shimmer** (Oct± / 5th) · **Width** · Mod Depth · Mod Rate
- **Motion** — Mod Dest (Act / Filt / Space / Mix / Mod) · Rate (8 bar…1/8) · Depth · Wave
- **Generate** — **Evolve** · Range (Soft / Mid / Wild) · **Dice**
- **Perform** — Reverse · Hold · Hold Mode (Latch / Gate) · **Duck**
- **Looper** — on/off · Transport · Reverse · Level · Fade · Speed · Route · Quantize
- **Looper 2** — Fade shape · Record order · Looper-Only · Burst
- **User Slots** — User Slot (1–16) · User Op (Save / Load / Del)
- **Config** — Input (Stereo / Mono) · Input Gain · Bypass · Bypass Mode (Buf / Trail / True)
The macro knobs **Activity, Repeats, Mix, Space, Filter** (and **Shape**, on the Tone page)
re-interpret per effect. **Activity** = more/less of the effect's thing; **Repeats** = how
long it rings on. **Rv Tone** is a bipolar reverb shaper on its own root knob: centre = flat,
turn down to high-pass the tail (thins the lows / tames ambient low-end build-up), turn up to
low-pass it (darker, warmer). It filters the reverb *send*, so it stops mud at the source.
### Timing
Timing **defaults to Free** — a free-running internal tempo that drifts gently, so the
rhythmic engines breathe rather than lock metronomically (a free-running, never-quite-locked
feel). **Sync** locks hard to the Move's host clock; **Manual** holds a fixed
BPM. Onset-driven effects (Arp, Chain) also trigger from audio transients and MIDI note-ons.
### Saving your sounds
- **Character presets** — the `Preset` row sets the effect + all macros to one of eight
curated starting points (Init, Erase, Edit, Chor, Shimr, Birds, Glass, Pad).
- **User-preset bank** — on the *User Slots* page, pick a slot (1–16) and **Save**; it writes
every parameter *and* the recorded loop to disk under the module folder. **Load** restores
both; **Del** clears the slot.
- **Whole-chain patches** — War Bells serializes its full state, so a Signal-Chain patch saved
via the Schwung Manager captures it too (parameters only — not the loop audio).
### MIDI
Channel-wide CCs map the main controls (6 Activity · 7 Shape · 8 Filter · 9 Mix · 11 Repeats ·
12 Space · 20 Reverb · 33 Rv Tone · 22 Looper · 28–35 transport · 47 Reverse · 48 Hold · 102
Bypass, plus more). **Program Change** selects effect + variation directly (effect = PC ÷ 4,
variation = PC mod 4).
### Web control
War Bells ships a custom **web UI** (`web_ui.html`) — believed to be the first Schwung module to
do so. It's dual-purpose:
- **[Interactive demo + manual](https://seajaysec.github.io/war-bells/)** on GitHub Pages — the
synth panel runs as a simulation alongside the docs (live device control is disabled there
because a browser can't open an insecure socket from an https page).
- **Live controller** when opened *from the Move* (an http origin), with War Bells in a chain
slot: `http://move.local:7700/api/remote-ui/module-assets/war_bells/web_ui.html`. It connects
to the Schwung Manager WebSocket, finds War Bells in your slots, drives the DSP, and reflects
hardware-knob moves back into the page.
## How it works
```
in -> input gain/mono -> capture ring (frozen by Hold)
-> 6 granular voices + multitap delay -> wet
MIX(dry,wet) -> chorus(pitch-mod) -> SPACE(delay + reverb) -> resonant LP filter
-> looper (thru + base/overdub) -> bypass crossfade -> out
```
All DSP is hand-written, realtime-safe C (header-only primitives in `src/dsp/core/`):
windowed granular voices over a rolling live-input buffer (`grain.h`, four envelope shapes),
a 4-tap delay with a pitch shifter (`multitap.h`, `pitchshift.h`), a chorus (`chorus.h`), a
Schroeder–Moorer reverb with four mode presets (`reverb.h`), a TPT state-variable resonant
filter (`svf.h`), a two-buffer 60-second looper (`looper.h`, WAV save/load), and an onset
detector (`transient.h`). The per-variation "brain" lives in `effects.c`.
## Install (no build required)
You do **not** need to compile War Bells — install it through the **Schwung Manager**
(`http://move.local:7700` → **Modules**):
- **From the catalog** *(once listed — see below)* — find **War Bells** under audio FX and tap
**Install**. One tap; auto-updates when a new release ships.
- **Custom → from GitHub URL** — paste **`seajaysec/war-bells`**. The Manager reads
[`release.json`](release.json) and pulls the correct tarball from the latest GitHub Release.
- **Custom → from file** — download the **`war_bells-module.tar.gz`** asset from the
[latest Release](https://github.com/seajaysec/war-bells/releases/latest) and upload it.
> ⚠️ Use the **`war_bells-module.tar.gz`** asset, **not** GitHub's auto-generated
> "Source code (tar.gz)". The source archive keeps `module.json` under `src/`, so the Manager
> reports **"No module.json found in tarball."** The packaged asset has the right layout
> (`war_bells/module.json`).
Building from source is only for development:
```sh
bash scripts/run_tests.sh # host-side C tests (native cc)
bash scripts/build.sh # cross-compile war_bells.so (aarch64) + tarball
MOVE_HOST=ableton@move.local bash scripts/deploy-dev.sh # sideload to a Move
```
See [`INSTALL.md`](INSTALL.md). The shared object is `war_bells.so` and exports
`move_audio_fx_init_v2` (audio_fx ABI v2). `requires_continuous_processing` keeps the
granular / looper / delay state alive through silence.
## Status
DSP is verified by `tests/test_smoke.c`: dry passthrough is unity, all 44 variations render,
the looper records / plays / overdubs / undoes / erases / saves / loads, character presets and
the user-slot bank round-trip (params **and** loop audio), Hold↔Looper exclusivity holds, and
`state` / `chain_params` / `ui_hierarchy` serialize cleanly. The aarch64 `.so` cross-compiles
clean and exports the entry symbol. Final analog *voicing* is tuned on-device.
## License & credits
War Bells is released under the [GNU Affero General Public License v3.0](LICENSE) © Chris Farrell.
Because it's served over a network (the web UI), AGPL §13 applies — the in-app footer links back
to this source.
It links the Schwung host ABI: `src/host/audio_fx_api_v2.h` and `src/host/plugin_api_v1.h` are
redistributed unmodified from [Schwung](https://github.com/charlesvestal/schwung) (MIT ©
Charles Vestal) — see [`THIRD_PARTY.md`](THIRD_PARTY.md). The reverb is adapted from the
public-domain Freeverb (Jezar at Dreampoint). Documentation is illustrative.