Skip to content

RoomEQ CLI

The roomeq binary takes a JSON configuration file describing your speaker measurements and room setup, runs the optimizer, and writes a DSP chain JSON that can be loaded directly into SotF’s audio engine or exported to third-party tools.

Terminal window
roomeq --config stereo.json --output stereo-dsp.json

stereo.json:

{
"speakers": {
"left": "measurements/left.csv",
"right": "measurements/right.csv"
},
"optimizer": {
"num_filters": 7,
"algorithm": "autoeq:de",
"min_freq": 20.0,
"max_freq": 1600.0
}
}
Terminal window
roomeq --config 2.1.json --output 2.1-dsp.json

2.1.json:

{
"system": {
"model": "stereo",
"speakers": { "L": "left", "R": "right", "LFE": "sub" },
"subwoofers": {
"config": "single",
"crossover": "bass_xo",
"sub": "L"
}
},
"speakers": {
"left": "measurements/left.csv",
"right": "measurements/right.csv",
"sub": "measurements/sub.csv"
},
"crossovers": {
"bass_xo": { "type": "LR24", "frequency": 80.0 }
},
"optimizer": {
"num_filters": 7,
"algorithm": "autoeq:de",
"target_response": { "shape": "harman" },
"phase_alignment": { "enabled": true }
}
}
FlagRequiredDefaultDescription
-c / --configYes*-Input room configuration JSON
-o / --outputYes*-Output DSP chain JSON
--sample-rateNo48000Filter design sample rate (Hz)
--export-formatNo-Also export to an external format (see below)
--export-pathNoautoExport output path (auto-derived from format)
--override-configNo-JSON file that overrides any section of the config
--dry-runNo-Validate config and check files without optimizing
--schema input|outputNo-Print JSON schema and exit
--convertNo-Convert existing DSP chain JSON to an export format (no optimization)

*Not required when using --schema or --convert.

Use --export-format to produce output for external applications alongside the SotF JSON:

ValueOutputUse with
camilladspYAML configCamillaDSP
apo.txtEqualizerAPO, Peace GUI, PipeWire parametric-EQ module
easyeffectsJSON presetEasyEffects
wavelet.txtWavelet (Android GraphicEQ)
pipewire.confPipeWire filter-chain
roonJSONRoon DSP Engine
Terminal window
roomeq --config room.json --output room-dsp.json --export-format apo --export-path room-eq.txt

Convert an existing output without re-optimizing:

Terminal window
roomeq --convert room-dsp.json --export-format camilladsp --export-path room.yaml
freq,spl,phase
20,75.0,45.2
50,78.0,30.1
100,80.0,15.5
20000,60.0,-90.3

Phase data is optional but required for accurate phase alignment and multi-driver crossover optimization.

TypeConfig keyUse case
Single speakerpath string or { "path": "..." }Standard speaker per channel
Group (multi-driver){ "measurements": [...], "crossover": "..." }Active 2-way/3-way speaker
MultiSub{ "subwoofers": [...] }Multiple subwoofers with gain/delay optimization
DBA{ "front": [...], "rear": [...] }Double Bass Array
Cardioid{ "front": "...", "rear": "...", "separation_meters": 0.5 }Gradient cardioid sub pair

The optimizer block in the config drives the optimization. Key fields:

FieldDefaultDescription
num_filters7PEQ filters per channel
algorithm"autoeq:de"Optimization algorithm (autoeq:de, cobyla, nlopt:isres, …)
loss_type"flat""flat", "score", or "epa"
min_q / max_q0.5 / 6.0Q factor range
min_db / max_db-12 / 4Gain range (dB)
min_freq / max_freq20 / 1600Frequency range (Hz)
max_iter50000Maximum optimizer iterations
refinetrueTwo-stage optimization (DE global + COBYLA local)
psychoacoustictrueERB-weighted loss for perceptual relevance
asymmetric_losstruePenalize peaks 2× more than dips

Control the in-room tonal target under optimizer.target_response:

ShapeDescription
"flat"0 dB flat target
"harman"Harman -0.8 dB/octave tilt (psychoacoustically preferred for in-room)
"custom"User-defined slope in slope_db_per_octave
"file"Load target from CSV (curve_path)
"from_measurement"Auto-derive slope from input measurement

Add bass/treble preference shelves:

{
"target_response": {
"shape": "harman",
"preference": {
"bass_shelf_db": 3.0,
"bass_shelf_freq": 200
}
}
}

Automatically detects F3 rolloff and generates a highpass filter to prevent driver damage:

{
"optimizer": {
"excursion_protection": {
"enabled": true,
"auto_detect_f3": true,
"filter_order": 4
}
}
}

Applies high-Q narrow filters below Schroeder (room modes) and low-Q broad filters above:

{
"optimizer": {
"schroeder_split": {
"enabled": true,
"room_dimensions": { "length": 5.0, "width": 4.0, "height": 2.5 }
}
}
}

Optimizes subwoofer delay and polarity for maximum energy sum at crossover:

{
"optimizer": {
"phase_alignment": { "enabled": true, "min_freq": 60, "max_freq": 100 }
}
}

Minimizes variance across multiple listening positions:

{
"optimizer": {
"multi_seat": { "enabled": true, "strategy": "minimize_variance" }
}
}

Generate linear-phase or mixed IIR+FIR correction filters:

{
"optimizer": {
"mode": "mixed",
"fir": { "taps": 4096, "phase": "kirkeby" },
"mixed_config": { "crossover_freq": 300, "fir_band": "low" }
}
}

The output JSON contains per-channel DSP chains compatible with SotF’s audio engine:

{
"channels": {
"left": {
"plugins": [
{ "plugin_type": "gain", "parameters": { "gain_db": -2.5 } },
{ "plugin_type": "eq", "parameters": { "filters": [...] } }
]
}
},
"metadata": {
"pre_score": 0.42,
"post_score": 0.91,
"algorithm": "autoeq:de"
}
}

Validate a config without running optimization:

Terminal window
roomeq --config room.json --output /dev/null --dry-run

Inspect the full input schema:

Terminal window
roomeq --schema input

roomeq uses the standard RUST_LOG environment variable:

Terminal window
RUST_LOG=debug roomeq --config room.json --output out.json
RUST_LOG=warn roomeq --config room.json --output out.json # quiet

Apply optimizer setting overrides without editing the main config (useful for scripting):

Terminal window
cat > quick.json <<'EOF'
{ "optimizer": { "num_filters": 5, "max_iter": 5000 } }
EOF
roomeq --config room.json --output room-quick.json --override-config quick.json