Power Armor Voice FX — LV2 plugin (Faust) 48khz ~24ms
1.1K
Power armor voice FX — LV2 (Faust) + Csound instrument for Linux.
Inspired by this song. https://www.youtube.com/watch?v=-S8Kr4NvYJY&list=RDMM&start_radio=1&rv=O_xgVCWPzSM
Released as an open source MIT project since I am still learning. Also want you bastards to make shit like this!!!!
Transforms a microphone input into a sealed-helmet, vox-unit voice. Granular pitch shifting, bass shelf boost, bitcrusher, ring modulator, helmet echo, compressor, and TPDF-dithered output to 16/20/24-bit at a locked 96 kHz sample rate.
Packaged as a Nix flake with NixOS and Home Manager modules for one-command setup with Carla and EasyEffects over PipeWire/JACK.
Total round-trip latency (plugin processing + hardware buffer):
| Source | Frames | Time @ 96 kHz |
|---|---|---|
Pitch shifter (Faust ef.transpose, window=2048) | 2048 | ~21 ms |
| Pitch shifter (Csound PVS, ifftsize=2048) | 2048 | ~21 ms |
| PipeWire hardware buffer (default quantum=256) | 256 | ~2.7 ms |
| Total (typical) | ~24 ms |
Latency is constant at all semitone values, including 0 — the pitch engine always runs. In a DAW, compensate by advancing the recorded output forward by ~21 ms, or use manual plugin delay compensation.
| Property | Value |
|---|---|
| Sample rate | 96 000 Hz — host must match |
| Input | 32-bit float (LV2 audio port) |
| Output depth | 16-bit default · 20-bit · 24-bit selectable |
| Channels | Mono in → Mono out |
IN (32f, 96 kHz)
→ [Pitch Shift] 0 to −12 semitones (21 ms latency)
→ [HPF] → [LPF] → [Mid Peak EQ]
→ [Bitcrusher / Downsample]
→ [Ring Modulator]
→ [Helmet Echo]
→ [Bass Boost] 1st-order low shelf
→ [Compressor]
→ [Output Gain]
→ [Hard Clip ±1.0]
→ [TPDF Dither + Word-Length Reduction (16/20/24-bit)]
→ [SR Guard × 1.0 or × 0.0]
→ OUT
DeMoD-Vox/
├── flake.nix Nix flake — packages, modules, devShell
├── modules/
│ ├── nixos.nix NixOS module (system-wide)
│ └── home-manager.nix Home Manager module (per-user)
├── easyeffects/
│ └── DeMoD_Vox_input.json EasyEffects input preset
├── DeMoD_Vox.dsp Faust source → LV2 / LADSPA
├── DeMoD_Vox.csd Csound source → standalone / csound-lv2
├── LICENSE MIT
└── README.md
In your system flake.nix:
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
home-manager.url = "github:nix-community/home-manager";
demod-vox.url = "github:ALH477/DeMoD-Vox";
};
outputs = { self, nixpkgs, home-manager, demod-vox, ... }: {
nixosConfigurations.mymachine = nixpkgs.lib.nixosSystem {
modules = [
./configuration.nix
demod-vox.nixosModules.default
home-manager.nixosModules.home-manager
{
home-manager.users.youruser = {
imports = [ demod-vox.homeManagerModules.default ];
};
}
];
};
};
}
configuration.nix# System-wide: PipeWire at 96 kHz + JACK + RT priorities + Carla
programs.demod-vox = {
enable = true;
quantum = 256; # 2.67 ms @ 96 kHz
installCarla = true;
installEasyEffects = true;
};
# Per-user: LV2_PATH, EasyEffects preset, optional Carla session
programs.demod-vox = {
enable = true;
installEasyEffectsPreset = true;
installCarlaSession = true; # pre-loads plugin in Carla
installCarla = true;
};
sudo nixos-rebuild switch --flake .#mymachine
The plugin is now discoverable by Carla and EasyEffects. PipeWire is running at 96 kHz with JACK compatibility and RT priorities.
programs.demod-vox.enable = true)| What | How |
|---|---|
| Installs LV2 plugin | environment.systemPackages → /run/current-system/sw/lib/lv2/ |
Sets LV2_PATH | profileRelativeSessionVariables → includes system + user profile lv2 dirs |
| PipeWire at 96 kHz | services.pipewire.extraConfig → clock rate, quantum, min/max quantum |
| JACK compatibility | services.pipewire.jack.enable = true |
| RT priorities | security.rtkit.enable + security.pam.loginLimits for @audio group |
| VM settings | vm.swappiness = 10, kernel.timer_migration = 0 |
| Installs Carla | optional — installCarla = true |
| Installs EasyEffects | optional — preset in /etc/easyeffects/input/ |
programs.demod-vox.enable = true)| What | How |
|---|---|
| LV2 to user profile | home.packages → ~/.nix-profile/lib/lv2/ |
LV2_PATH session var | home.sessionVariables — covers user + system profile paths |
| EasyEffects preset | xdg.configFile."easyeffects/input/DeMoD_Vox.json" |
| Carla session | xdg.configFile."rncbc.org/Carla/DeMoD_Vox.carxs" |
-vec -vs 32 -dfs enables SIMD vectorisation and loop scheduling for lower CPU overhead:
faust2lv2 -srate 96000 -vec -vs 32 -dfs DeMoD_Vox.dsp
cp -r DeMoD_Vox.lv2 ~/.lv2/
# Verify URI (needed for EasyEffects preset):
cat DeMoD_Vox.lv2/manifest.ttl | grep 'lv2:Plugin'
faust2ladspa -srate 96000 -vec -vs 32 DeMoD_Vox.dsp
cp DeMoD_Vox.so ~/.ladspa/
faust2jack -srate 96000 -vec -vs 32 DeMoD_Vox.dsp && ./DeMoD_Vox
csound -+rtaudio=jack -+rtmidi=null \
-odac -iadc -b256 -B512 \
DeMoD_Vox.csd
At 96 kHz, -b256 = 2.67 ms per period. PipeWire-JACK handles the connection — no separate jackd needed.
csound -+rtaudio=alsa -odac0 -iadc0 \
-b512 -B2048 DeMoD_Vox.csd
echo $LV2_PATH # check path is set
ls $LV2_PATH # check plugin bundle exists
cat ~/.lv2/DeMoD_Vox.lv2/manifest.ttl # check URI
Carla sample rate must be 96000. Set in Carla: Settings → Configure Carla → Engine → Sample Rate → 96000.
EasyEffects applies effects to the system microphone input (or output). DeMoD Vox works as a microphone (input device) effect.
DeMoD_Vox.json, or use the system/HM module which installs it automatically.If the plugin doesn't appear in the effects list:
# Check LV2_PATH is set
echo $LV2_PATH
# Check EasyEffects can see the plugin
easyeffects --lv2-dump 2>&1 | grep -i demod
# Verify the URI in the preset matches the built plugin
cat ~/.config/easyeffects/input/DeMoD_Vox.json | grep '"lv2#'
cat ~/.lv2/DeMoD_Vox.lv2/manifest.ttl | grep 'a lv2:Plugin'
# Update the URI in DeMoD_Vox.json if they differ.
EasyEffects needs PipeWire. It does not work with standalone JACK. The NixOS module configures this correctly.
If not using the NixOS module, configure PipeWire manually:
# /etc/pipewire/pipewire.conf.d/92-demod-vox.conf
context.properties = {
default.clock.rate = 96000
default.clock.quantum = 256
default.clock.min-quantum = 256
default.clock.max-quantum = 1024
default.clock.allowed-rates = [ 96000 ]
}
systemctl --user restart pipewire pipewire-pulse wireplumber
# Verify:
pw-cli info 0 | grep -E 'rate|quantum'
For real-time priorities without the NixOS module:
# /etc/security/limits.d/99-audio.conf
@audio - rtprio 99
@audio - memlock unlimited
@audio - nice -20
# Add yourself to the audio group:
sudo usermod -aG audio $USER
nix develop github:ALH477/DeMoD-Vox
# Or from a local clone:
git clone https://github.com/ALH477/DeMoD-Vox
cd DeMoD-Vox
nix develop
The dev shell includes: faust, csound, carla, easyeffects, jalv, lv2lint, pkg-config.
# Quick test with jalv (minimal LV2 host):
faust2lv2 -srate 96000 -vec -vs 32 -dfs DeMoD_Vox.dsp
jalv.gtk https://faustlv2.grame.fr/DeMoD_Vox
# Lint the LV2 bundle:
lv2lint -s lv2 https://faustlv2.grame.fr/DeMoD_Vox
# Run Nix build checks:
nix flake check
programs.demod-vox)| Option | Type | Default | Description |
|---|---|---|---|
enable | bool | false | Enable the module |
package | package | flake default | Override the plugin package |
sampleRate | int | 96000 | PipeWire clock rate |
quantum | int | 256 | PipeWire/JACK buffer size (frames) |
installCarla | bool | true | Install Carla |
installEasyEffects | bool | true | Install EasyEffects + system preset |
installCsound | bool | false | Install Csound + runner script |
programs.demod-vox)| Option | Type | Default | Description |
|---|---|---|---|
enable | bool | false | Enable the module |
package | package | flake default | Override the plugin package |
installEasyEffectsPreset | bool | true | Install preset to ~/.config/easyeffects/input/ |
installCarla | bool | false | Install Carla to user profile |
installEasyEffects | bool | false | Install EasyEffects to user profile |
installCsound | bool | false | Install Csound + runner to user profile |
installCarlaSession | bool | false | Install Carla rack session with plugin pre-loaded |
| Parameter | Range | Default | Notes |
|---|---|---|---|
| Pitch Shift | −12–0 st | 0 | 0 = no shift (21 ms latency still applies) |
| Bass Boost | 0–18 dB | 0 dB | 0 = flat passthrough |
| Bass Freq | 40–400 Hz | 120 Hz | Shelf −3 dB point |
| Parameter | Range | Default |
|---|---|---|
| HPF Freq | 20–500 Hz | 100 Hz |
| LPF Freq | 1–12 kHz | 4.5 kHz |
| Mid Boost | 0–18 dB | 6 dB |
| Mid Freq | 500–5000 Hz | 2000 Hz |
| Mid BW | 100–4000 Hz | 800 Hz |
| Parameter | Range | Default |
|---|---|---|
| Bit Depth | 2–16 | 8 |
| Downsample | 1–8× | 2× |
| Mix | 0–1 | 0.6 |
| Parameter | Range | Default |
|---|---|---|
| Carrier Freq | 1–800 Hz | 60 Hz |
| Mix | 0–1 | 0.35 |
| Parameter | Range | Default |
|---|---|---|
| Delay | 1–60 ms | 10 ms |
| Mix | 0–1 | 0.22 |
| Feedback | 0–0.7 | 0.15 |
| Parameter | Range | Default | Notes |
|---|---|---|---|
| Threshold | −40–0 dBFS | −18 dB | |
| Ratio | 1–20:1 | 8:1 | |
| Attack | 0.1–80 ms | 5 ms | |
| Release | 10–500 ms | 60 ms |
| Parameter | Range | Default | Notes |
|---|---|---|---|
| Gain | −12–24 dB | +6 dB | Compressor makeup gain; signals above ±1.0 are hard-clipped |
| Bit Depth | 16 / 20 / 24 | 16 | TPDF dither applied at all depths |
echo $LV2_PATH
ls $(echo $LV2_PATH | tr ':' '\n' | head -1)
# If empty, re-login or: source ~/.nix-profile/etc/profile.d/hm-session-vars.sh
pw-cli info 0 | grep rate
# Should show: clock.rate = 96000
# If not: systemctl --user restart wireplumber pipewire pipewire-pulse
Increase quantum: programs.demod-vox.quantum = 512 (5.3 ms). Check RT priorities:
chrt -p $(pgrep pipewire) # should show SCHED_FIFO or SCHED_RR
ulimit -r # should be > 0 (rtprio limit)
# Get the actual URI from the built plugin:
cat ~/.lv2/DeMoD_Vox.lv2/manifest.ttl | grep 'a lv2:Plugin' -A2
# Update DeMoD_Vox_input.json: replace the URI in "plugins_order" and the key name
pw-jack csound -+rtaudio=jack -odac -iadc -b256 -B512 DeMoD_Vox.csd
# pw-jack wraps Csound in the PipeWire JACK layer explicitly
packages, nixosModules.default, homeManagerModules.default, devShells.default, checks-vec -vs 32 -dfs added to faust2lv2 call for SIMD vectorisationMIT — see LICENSE.
Copyright (c) 2026 ALH477
A Docker-based LV2 audio plugin pipeline with Carla GUI support, X11 for lightweight display, and multi-platform audio backend support.
| Platform | Requirements |
|---|---|
| Linux | Docker, JACK audio server, audio group membership |
| macOS | Docker Desktop with audio enabled |
| Windows | WSL2 with WSLg |
cd docker-vox
docker build -t demod-vox:latest .
Or load a pre-built distribution:
zstd -d < dist/demod-vox-latest.tar.zst | docker load
Prerequisites:
sudo apt install jackd2 qjackctl
sudo usermod -aG audio $USER
# Log out and back in for group membership
Start JACK on host:
# Using QJackCtl GUI or:
jackd -d alsa -r 48000 -p 512 &
Run DeMoD Vox:
# Interactive CLI
docker compose -f docker-compose.linux.yml run --rm demod-linux --interactive
# Or use Makefile
make run-linux
Prerequisites:
Run DeMoD Vox:
docker compose -f docker-compose.macos.yml run --rm demod-macos --interactive
make run-macos
# PowerShell
.\launch.ps1
# Or docker compose
docker compose -f docker-compose.windows.yml run --rm lv2-pipeline --interactive
make run-windows
The image includes Carla - a fully-featured audio plugin host with GUI.
# Start Carla with X11 forwarding
docker run -it --rm \
-e DISPLAY=$DISPLAY \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-v $(pwd)/lv2_plugins:/usr/lib/lv2:ro \
--device /dev/snd \
demod-vox:latest \
carla
For server environments without a display:
# Using the built-in Xvfb support
docker run -it --rm \
-e CARLA_FULL_GUI=0 \
demod-vox:latest \
/opt/audio/scripts/run_carla.sh http://my.plugin.uri
# docker-compose.carla.yml
services:
carla-gui:
image: demod-vox:latest
volumes:
- ./lv2_plugins:/usr/lib/lv2:ro
- ./config:/opt/audio/config:ro
- /tmp/.X11-unix:/tmp/.X11-unix:rw
- ${XAUTHORITY:-$HOME/.Xauthority}:/root/.Xauthority:ro
environment:
- DISPLAY=${DISPLAY}
- PULSE_SERVER=unix:/run/user/1000/pulse/native
- LV2_PATH=/usr/lib/lv2
devices:
- /dev/snd:/dev/snd
group_add:
- audio
ipc: host
stdin_open: true
tty: true
| Script | Description |
|---|---|
/opt/audio/scripts/run_jalv.sh <uri> | Run plugin with Jalv (CLI) |
/opt/audio/scripts/run_carla.sh <uri> | Run Carla GUI with plugin |
/opt/audio/scripts/carla-headless.sh <uri> | Carla in headless mode |
/opt/audio/scripts/list_plugins.sh | List available LV2 plugins |
| Variable | Default | Description |
|---|---|---|
PLUGIN_URI | - | LV2 plugin URI to load |
PLUGIN_PARAMS | [] | JSON array of parameters |
PULSE_LATENCY_MSEC | 30 | Audio latency in milliseconds |
PULSE_SAMPLE_RATE | 48000 | Audio sample rate |
JALV_BLOCK_SIZE | 512 | Audio block size |
LV2_PATH | /usr/lib/lv2 | LV2 plugin directory |
DISPLAY | :0 | X11 display |
CARLA_FULL_GUI | 0 | Set to 1 for full GUI mode |
Run a specific plugin without interactive mode:
# Linux
PLUGIN_URI="http://example.com/my-plugin" \
docker compose -f docker-compose.linux.yml up
# With parameters
PLUGIN_URI="http://example.com/my-plugin" \
PLUGIN_PARAMS='[{"param": "gain", "value": 0.8}]' \
docker compose -f docker-compose.linux.yml up
make build # Build Docker image
make build-dist # Build and compress for distribution
make run-linux # Interactive on Linux
make run-linux-plugin PLUGIN_URI=<uri> # Headless on Linux
make run-macos # Interactive on macOS
make run-windows # Interactive on Windows/WSLg
make list-plugins # List available LV2 plugins
make shell # Interactive bash shell
make clean # Remove containers and image
# Check JACK status
jack_lsp
jack_lsof
# Verify audio group
groups $USER
# List audio devices
cat /proc/asound/cards
# Check permissions
ls -la /dev/snd
system_profiler SPAudioDataTypewsl --list --runningwsl ls -la /mnt/wslg/# If X11 forwarding fails
xhost +local:docker
# Or run with Xvfb (headless)
docker run -it --rm \
-e DISPLAY=:99 \
demod-vox:latest \
xvfb-run -a carla
# Host side: start JACK
jackd -d alsa -r 48000 -p 512 &
# Container: connect to JACK
AUDIO_DRIVER=jack JACKD_PARAMS="-d alsa" docker compose up
# Container uses PulseAudio bridge
PULSE_SERVER="unix:/run/user/1000/pulse/native" docker compose up
# For testing without JACK
AUDIO_DRIVER=alsa docker compose up
Place .dsp files in the faust/ directory before building:
# The Dockerfile automatically compiles all .dsp files
docker build -t demod-vox:custom .
Mount your plugin directory:
docker run -v /path/to/my/plugins:/usr/lib/lv2:ro demod-vox:latest \
jalv.gtk "http://my.plugin.uri"
Content type
Image
Digest
sha256:0ac07c03d…
Size
347.7 MB
Last updated
7 months ago
docker pull alh477/demod-vox