Sign inSign up

alh477/demod-vox

By alh477

Updated 7 months ago

Power Armor Voice FX — LV2 plugin (Faust) 48khz ~24ms

Image
Integration & delivery
Data science
Monitoring & observability
0

1.1K

alh477/demod-vox repository overview

DeMoD Vox

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!!!!

DeMoD-Vox

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.

video


⚠ Latency

Total round-trip latency (plugin processing + hardware buffer):

SourceFramesTime @ 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.


I/O Specification (Locked)

PropertyValue
Sample rate96 000 Hz — host must match
Input32-bit float (LV2 audio port)
Output depth16-bit default · 20-bit · 24-bit selectable
ChannelsMono in → Mono out

Signal Chain

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

Files

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

Quick Start — NixOS + Home Manager

1. Add the flake input

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 ];
          };
        }
      ];
    };
  };
}
2. Enable in 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;
};
3. Enable in your Home Manager config
# 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;
};
4. Rebuild
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.


What the Nix Module Does

NixOS module (programs.demod-vox.enable = true)
WhatHow
Installs LV2 pluginenvironment.systemPackages/run/current-system/sw/lib/lv2/
Sets LV2_PATHprofileRelativeSessionVariables → includes system + user profile lv2 dirs
PipeWire at 96 kHzservices.pipewire.extraConfig → clock rate, quantum, min/max quantum
JACK compatibilityservices.pipewire.jack.enable = true
RT prioritiessecurity.rtkit.enable + security.pam.loginLimits for @audio group
VM settingsvm.swappiness = 10, kernel.timer_migration = 0
Installs Carlaoptional — installCarla = true
Installs EasyEffectsoptional — preset in /etc/easyeffects/input/
Home Manager module (programs.demod-vox.enable = true)
WhatHow
LV2 to user profilehome.packages~/.nix-profile/lib/lv2/
LV2_PATH session varhome.sessionVariables — covers user + system profile paths
EasyEffects presetxdg.configFile."easyeffects/input/DeMoD_Vox.json"
Carla sessionxdg.configFile."rncbc.org/Carla/DeMoD_Vox.carxs"

Manual Build (without Nix)

Faust → LV2

-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'
Faust → LADSPA (fallback)
faust2ladspa -srate 96000 -vec -vs 32 DeMoD_Vox.dsp
cp DeMoD_Vox.so ~/.ladspa/
Faust → JACK standalone
faust2jack -srate 96000 -vec -vs 32 DeMoD_Vox.dsp && ./DeMoD_Vox
Csound → JACK (PipeWire compatible)
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 → ALSA
csound -+rtaudio=alsa -odac0 -iadc0 \
       -b512 -B2048 DeMoD_Vox.csd

Using with Carla

  1. Start Carla — it connects to PipeWire-JACK automatically.
  2. Add Plugin → scan LV2 → search DeMoD Vox. If it doesn't appear:
    echo $LV2_PATH          # check path is set
    ls $LV2_PATH            # check plugin bundle exists
    cat ~/.lv2/DeMoD_Vox.lv2/manifest.ttl   # check URI
    
  3. Connect your microphone input to the plugin input port in the Carla patchbay.
  4. Connect the plugin output to your monitor / recording output.
  5. Adjust parameters in the plugin GUI or via OSC automation.

Carla sample rate must be 96000. Set in Carla: Settings → Configure Carla → Engine → Sample Rate → 96000.


Using with EasyEffects

EasyEffects applies effects to the system microphone input (or output). DeMoD Vox works as a microphone (input device) effect.

  1. Open EasyEffects → Input tab.
  2. Click PresetsImport → select the installed DeMoD_Vox.json, or use the system/HM module which installs it automatically.
  3. Click Load to apply.
  4. The plugin appears in the effects chain. Enable it with the toggle.

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.


PipeWire / JACK Manual Configuration

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

Development Shell

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

Nix Module Options Reference

NixOS (programs.demod-vox)
OptionTypeDefaultDescription
enableboolfalseEnable the module
packagepackageflake defaultOverride the plugin package
sampleRateint96000PipeWire clock rate
quantumint256PipeWire/JACK buffer size (frames)
installCarlabooltrueInstall Carla
installEasyEffectsbooltrueInstall EasyEffects + system preset
installCsoundboolfalseInstall Csound + runner script
Home Manager (programs.demod-vox)
OptionTypeDefaultDescription
enableboolfalseEnable the module
packagepackageflake defaultOverride the plugin package
installEasyEffectsPresetbooltrueInstall preset to ~/.config/easyeffects/input/
installCarlaboolfalseInstall Carla to user profile
installEasyEffectsboolfalseInstall EasyEffects to user profile
installCsoundboolfalseInstall Csound + runner to user profile
installCarlaSessionboolfalseInstall Carla rack session with plugin pre-loaded

Parameter Reference

Heavy
ParameterRangeDefaultNotes
Pitch Shift−12–0 st00 = no shift (21 ms latency still applies)
Bass Boost0–18 dB0 dB0 = flat passthrough
Bass Freq40–400 Hz120 HzShelf −3 dB point
EQ
ParameterRangeDefault
HPF Freq20–500 Hz100 Hz
LPF Freq1–12 kHz4.5 kHz
Mid Boost0–18 dB6 dB
Mid Freq500–5000 Hz2000 Hz
Mid BW100–4000 Hz800 Hz
Bitcrusher
ParameterRangeDefault
Bit Depth2–168
Downsample1–8×
Mix0–10.6
Ring Modulator
ParameterRangeDefault
Carrier Freq1–800 Hz60 Hz
Mix0–10.35
Helmet Echo
ParameterRangeDefault
Delay1–60 ms10 ms
Mix0–10.22
Feedback0–0.70.15
Compressor
ParameterRangeDefaultNotes
Threshold−40–0 dBFS−18 dB
Ratio1–20:18:1
Attack0.1–80 ms5 ms
Release10–500 ms60 ms
Output
ParameterRangeDefaultNotes
Gain−12–24 dB+6 dBCompressor makeup gain; signals above ±1.0 are hard-clipped
Bit Depth16 / 20 / 2416TPDF dither applied at all depths

Troubleshooting

Plugin not found by Carla / EasyEffects
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
PipeWire not at 96 kHz
pw-cli info 0 | grep rate
# Should show: clock.rate = 96000
# If not: systemctl --user restart wireplumber pipewire pipewire-pulse
Xruns / audio dropout

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)
EasyEffects preset URI mismatch
# 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
Csound JACK connection fails
pw-jack csound -+rtaudio=jack -odac -iadc -b256 -B512 DeMoD_Vox.csd
# pw-jack wraps Csound in the PipeWire JACK layer explicitly

Changelog

Current
  • Nix flake added: packages, nixosModules.default, homeManagerModules.default, devShells.default, checks
  • NixOS module: PipeWire 96 kHz, JACK compat, RTKit, PAM limits, EasyEffects system preset, Carla
  • Home Manager module: LV2_PATH, EasyEffects preset, Carla session file
  • EasyEffects preset JSON with three named sub-presets
  • Latency improved: Faust 85 ms → 21 ms (window 8192→2048); Csound 42 ms → 21 ms (fftsize 4096→2048)
  • Build flags: -vec -vs 32 -dfs added to faust2lv2 call for SIMD vectorisation
Previous
  • Hard clip before WLR; TPDF dither fixed (two independent LCGs); compressor ratio wired; bass shelf corrected
  • Pitch shift + bass boost added; latency documented
  • SR locked to 96 kHz; TPDF dither + word-length reduction output

License

MIT — see LICENSE.
Copyright (c) 2026 ALH477

DeMoD Vox - Docker Audio Pipeline

A Docker-based LV2 audio plugin pipeline with Carla GUI support, X11 for lightweight display, and multi-platform audio backend support.

Features

  • LV2 Plugin Host - Load and run LV2 audio plugins
  • Carla GUI - Full-featured audio plugin host with graphical interface
  • Xvfb Support - Headless X11 for server/CI environments
  • Multi-Platform - Linux (JACK), macOS (PulseAudio), Windows (WSLg)
  • FAUST Support - Compile .dsp source files to LV2 plugins
  • OSC Control - Full OSC parameter control via python-osc

Quick Start

Prerequisites
PlatformRequirements
LinuxDocker, JACK audio server, audio group membership
macOSDocker Desktop with audio enabled
WindowsWSL2 with WSLg
Build the Image
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

Platform-Specific Usage

Linux (JACK Audio)

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
macOS (PulseAudio)

Prerequisites:

  • Docker Desktop with audio enabled: Settings → Audio

Run DeMoD Vox:

docker compose -f docker-compose.macos.yml run --rm demod-macos --interactive
make run-macos
Windows (WSLg)
# PowerShell
.\launch.ps1

# Or docker compose
docker compose -f docker-compose.windows.yml run --rm lv2-pipeline --interactive
make run-windows

Carla GUI Mode

The image includes Carla - a fully-featured audio plugin host with GUI.

Interactive 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
Headless with Xvfb

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
Carla-Only Compose
# 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

Available Scripts

ScriptDescription
/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.shList available LV2 plugins

Environment Variables

VariableDefaultDescription
PLUGIN_URI-LV2 plugin URI to load
PLUGIN_PARAMS[]JSON array of parameters
PULSE_LATENCY_MSEC30Audio latency in milliseconds
PULSE_SAMPLE_RATE48000Audio sample rate
JALV_BLOCK_SIZE512Audio block size
LV2_PATH/usr/lib/lv2LV2 plugin directory
DISPLAY:0X11 display
CARLA_FULL_GUI0Set to 1 for full GUI mode

Headless/Automation 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

Using Makefile

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

Troubleshooting

Linux (JACK)
# 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
macOS
  • Enable Docker Desktop audio: Settings → Audio
  • Check CoreAudio: system_profiler SPAudioDataType
Windows
  • Verify WSLg: wsl --list --running
  • Check socket: wsl ls -la /mnt/wslg/
Carla GUI Issues
# 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

Audio Backend Configuration

# 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
PulseAudio (macOS/Windows)
# Container uses PulseAudio bridge
PULSE_SERVER="unix:/run/user/1000/pulse/native" docker compose up
ALSA Direct
# For testing without JACK
AUDIO_DRIVER=alsa docker compose up

Development

Compiling FAUST Plugins

Place .dsp files in the faust/ directory before building:

# The Dockerfile automatically compiles all .dsp files
docker build -t demod-vox:custom .
Adding Custom Plugins

Mount your plugin directory:

docker run -v /path/to/my/plugins:/usr/lib/lv2:ro demod-vox:latest \
    jalv.gtk "http://my.plugin.uri"

Tag summary

Content type

Image

Digest

sha256:0ac07c03d

Size

347.7 MB

Last updated

7 months ago

docker pull alh477/demod-vox