[group('download')]
download-speakers:
cargo run --bin autoeq-download-speakers --release
[group('build')]
prod-autoeq:
cargo build --release --bin autoeq
cargo build --release --bin benchmark-autoeq-speaker
[group('bench')]
bench-autoeq: bench-convergence bench-autoeq-speaker
[group('bench')]
bench-convergence:
cargo run --release --bin benchmark-convergence
[group('bench')]
bench-autoeq-speaker:
# either jobs=1 or --no-parallel ; or a mix if you have a lot of
# CPU cores
cargo run --release --bin benchmark-autoeq-speaker -- --qa --jobs 1
[group('examples')]
examples-autoeq:
cargo run --release --example headphone_loss_validation
[group('publish')]
publish-autoeq:
cd crates/autoeq && cargo publish
[group('demo')]
demo-headphone-loss:
cargo run --release --example headphone_loss_demo -- \
--spl "./data_tests/headphones/asr/bowerwilkins_p7/Bowers & Wilkins P7.csv" \
--target "./data_tests/targets/harman-over-ear-2018.csv"
# ----------------------------------------------------------------------
# QA AUTOEQ
# ----------------------------------------------------------------------
[group('qa-autoeq')]
qa-autoeq: prod-autoeq \
qa-ascilab-6b \
qa-jbl-m2-flat qa-jbl-m2-score \
qa-beyerdynamic-dt1990pro \
qa-edifierw830nb
[group('qa-autoeq')]
qa-ascilab-6b:
./target/release/autoeq --speaker="AsciLab F6B" --version asr --measurement CEA2034 \
--algo autoeq:de --loss speaker-score -n 7 --min-freq=30 --max-q=6 \
--qa 0.5
[group('qa-autoeq')]
qa-jbl-m2-flat:
./target/release/autoeq --speaker="JBL M2" --version eac --measurement CEA2034 \
--algo autoeq:de --loss speaker-flat -n 7 --min-freq=20 --max-q=6 --peq-model hp-pk \
--qa 0.5
[group('qa-autoeq')]
qa-jbl-m2-score:
./target/release/autoeq --speaker="JBL M2" --version eac --measurement CEA2034 \
--algo autoeq:de --loss speaker-score -n 7 --min-freq=20 --max-q=6 --peq-model hp-pk \
--qa 0.5
[group('qa-autoeq')]
qa-beyerdynamic-dt1990pro: qa-beyerdynamic-dt1990pro-flat qa-beyerdynamic-dt1990pro-score qa-beyerdynamic-dt1990pro-score2
[group('qa-autoeq')]
qa-beyerdynamic-dt1990pro-score:
./target/release/autoeq -n 5 \
--curve ./data_tests/headphones/asr/beyerdynamic_dt1990pro/Beyerdynamic\ DT1990\ Pro\ Headphone\ Frequency\ Response\ Measurement.csv \
--target ./data_tests/targets/harman-over-ear-2018.csv --loss headphone-score \
--qa 3.0
[group('qa-autoeq')]
qa-beyerdynamic-dt1990pro-score2:
./target/release/autoeq -n 7 \
--curve ./data_tests/headphones/asr/beyerdynamic_dt1990pro/Beyerdynamic\ DT1990\ Pro\ Headphone\ Frequency\ Response\ Measurement.csv \
--target ./data_tests/targets/harman-over-ear-2018.csv \
--loss headphone-score --max-db 6 --max-q 6 --algo mh:rga --maxeval 20000 --min-freq=20 --max-freq 10000 --peq-model hp-pk-lp --min-q 0.6 --min-db 0.25 \
--qa 1.5
[group('qa-autoeq')]
qa-beyerdynamic-dt1990pro-flat:
./target/release/autoeq -n 5 \
--curve ./data_tests/headphones/asr/beyerdynamic_dt1990pro/Beyerdynamic\ DT1990\ Pro\ Headphone\ Frequency\ Response\ Measurement.csv \
--target ./data_tests/targets/harman-over-ear-2018.csv \
--loss headphone-flat --max-db 6 --max-q 6 --maxeval 20000 --algo mh:pso --min-freq=20 --max-freq 10000 --peq-model pk \
--qa 0.5
[group('qa-autoeq')]
qa-edifierw830nb: qa-edifierw830nb-autoeqde qa-edifierw830nb-mhrga qa-edifierw830nb-mhfirefly
[group('qa-autoeq')]
qa-edifierw830nb-autoeqde:
./target/release/autoeq -n 9 \
--curve data_tests/headphones/asr/edifierw830nb/Edifier\ W830NB.csv \
--target ./data_tests/targets/harman-over-ear-2018.csv \
--min-freq 50 --max-freq 16000 --max-q 8 --max-db 8 \
--loss headphone-score \
--min-spacing-oct 0.08 \
--algo autoeq:de --population 70 --maxeval 8000 --seed 42 \
--qa 6.0
[group('qa-autoeq')]
qa-edifierw830nb-mhrga:
./target/release/autoeq -n 5 \
--curve data_tests/headphones/asr/edifierw830nb/Edifier\ W830NB.csv \
--target ./data_tests/targets/harman-over-ear-2018.csv \
--min-freq 50 --max-freq 16000 --max-q 8 --max-db 8 \
--loss headphone-score \
--min-spacing-oct 0.04 --atolerance 0.00000001 --tolerance 0.0000001 --algo mh:rga --population 100 --maxeval 30000 \
--qa 2.5
[group('qa-autoeq')]
qa-edifierw830nb-mhfirefly:
./target/release/autoeq -n 5 \
--curve data_tests/headphones/asr/edifierw830nb/Edifier\ W830NB.csv \
--target ./data_tests/targets/harman-over-ear-2018.csv \
--min-freq 50 --max-freq 16000 --max-q 8 --max-db 8 \
--loss headphone-score \
--min-spacing-oct 0.04 --atolerance 0.00000001 --tolerance 0.000000001 --algo mh:rga --population 80 --maxeval 30000 \
--qa 2.5
# ----------------------------------------------------------------------
# QA ROOMEQ
# ----------------------------------------------------------------------
# Ensure Python venv exists and has dependencies installed
[group('setup')]
ensure-venv:
#!/usr/bin/env bash
set -euo pipefail
if [ ! -f ./venv/bin/python3 ]; then
echo "Creating Python venv..."
python3 -m venv ./venv
fi
if ! ./venv/bin/python3 -c "import plotly" 2>/dev/null; then
echo "Installing Python dependencies..."
./venv/bin/pip install -r ./scripts/requirements.txt
fi
[group('qa-roomeq')]
qa-roomeq: qa-roomeq-small-stereo-20 \
qa-roomeq-small-stereo-21 \
qa-roomeq-small-stereo-22 \
qa-roomeq-convergence \
qa-roomeq-coverage \
qa-roomeq-synthetic \
qa-roomeq-features
# Memory-capped convergence run. The `--jobs` default in
# `roomeq-qa-quality` is `num_cpus/2` so each outer test case still gets
# parallel DE evaluators without OOM'ing the machine when 70+ cases are
# scheduled. Override with `just qa-roomeq-convergence jobs=N` or run the
# binary directly.
[group('qa-roomeq')]
qa-roomeq-convergence jobs="":
#!/usr/bin/env bash
set -euo pipefail
if [ -n "{{jobs}}" ]; then
cargo run --bin roomeq-qa-quality --release -- --jobs {{jobs}}
else
cargo run --bin roomeq-qa-quality --release
fi
[group('qa-roomeq')]
qa-roomeq-small-stereo-20: ensure-venv
@for method in iir fir mixed; do \
for algo in bem fem; do \
mkdir -p ./data_generated/roomeq/generated/$algo/small_stereo_2_0; \
cargo run --bin roomeq --release -- \
--config ./data_tests/roomeq/generated/$algo/small_stereo_2_0/config.json \
--override-config ./data_tests/roomeq/generated/optimiser-config/small_stereo_2_0/optimiser-$method.json \
--output ./data_generated/roomeq/generated/$algo/small_stereo_2_0/dsp_$method.json; \
./venv/bin/python3 ./scripts/display-roomeq.py \
./data_generated/roomeq/generated/$algo/small_stereo_2_0/dsp_$method.json; \
done \
done
[group('qa-roomeq')]
qa-roomeq-small-stereo-21: ensure-venv
@for method in iir fir mixed; do \
for algo in fem; do \
mkdir -p ./data_generated/roomeq/generated/$algo/small_stereo_2_1; \
cargo run --bin roomeq --release -- \
--config ./data_tests/roomeq/generated/$algo/small_stereo_2_1/config.json \
--override-config ./data_tests/roomeq/generated/optimiser-config/small_stereo_2_1/optimiser-$method.json \
--output ./data_generated/roomeq/generated/$algo/small_stereo_2_1/dsp_$method.json; \
./venv/bin/python3 ./scripts/display-roomeq.py \
./data_generated/roomeq/generated/$algo/small_stereo_2_1/dsp_$method.json; \
done \
done
[group('qa-roomeq')]
qa-roomeq-small-stereo-22: ensure-venv
@for method in iir fir mixed; do \
for algo in fem; do \
mkdir -p ./data_generated/roomeq/generated/$algo/small_stereo_2_2; \
cargo run --bin roomeq --release -- \
--config ./data_tests/roomeq/generated/$algo/small_stereo_2_2/config.json \
--override-config ./data_tests/roomeq/generated/optimiser-config/small_stereo_2_2/optimiser-$method.json \
--output ./data_generated/roomeq/generated/$algo/small_stereo_2_2/dsp_$method.json; \
./venv/bin/python3 ./scripts/display-roomeq.py \
./data_generated/roomeq/generated/$algo/small_stereo_2_2/dsp_$method.json; \
done \
done
[group('qa-roomeq')]
qa-roomeq-small-stereo-51: ensure-venv
@for method in iir fir mixed; do \
for algo in fem; do \
mkdir -p ./data_generated/roomeq/generated/$algo/medium_surround_5_1; \
cargo run --bin roomeq --release -- \
--config ./data_tests/roomeq/generated/$algo/medium_surround_5_1/config.json \
--override-config ./data_tests/roomeq/generated/optimiser-config/medium_surround_5_1/optimiser-$method.json \
--output ./data_generated/roomeq/generated/$algo/medium_surround_5_1/dsp_$method.json; \
./venv/bin/python3 ./scripts/display-roomeq.py \
./data_generated/roomeq/generated/$algo/medium_surround_5_1/dsp_$method.json; \
done \
done
# ----------------------------------------------------------------------
# QA ROOMEQ — Multi-Measurement (5 listening positions per speaker)
# Tests the multi-objective optimization across all strategies.
# Requires data generated with 5 LPs (run `just generate-roomeq-data` first).
# ----------------------------------------------------------------------
[group('qa-roomeq-multi')]
qa-roomeq-multi-measurement: \
qa-roomeq-multi-small-stereo-20 \
qa-roomeq-multi-small-stereo-21 \
qa-roomeq-multi-small-stereo-22-mso
[group('qa-roomeq-multi')]
qa-roomeq-multi-small-stereo-20: ensure-venv
@for strategy in minimax weighted_sum variance_penalized; do \
for algo in bem fem; do \
mkdir -p ./data_generated/roomeq/generated/$algo/small_stereo_2_0; \
echo "=== Multi-measurement $strategy ($algo) small_stereo_2_0 ==="; \
cargo run --bin roomeq --release -- \
--config ./data_tests/roomeq/generated/$algo/small_stereo_2_0/config.json \
--override-config ./data_tests/roomeq/generated/optimiser-config/multi_measurement/$strategy.json \
--output ./data_generated/roomeq/generated/$algo/small_stereo_2_0/dsp_iir_multi_$strategy.json; \
./venv/bin/python3 ./scripts/display-roomeq.py \
./data_generated/roomeq/generated/$algo/small_stereo_2_0/dsp_iir_multi_$strategy.json; \
done \
done
[group('qa-roomeq-multi')]
qa-roomeq-multi-small-stereo-21: ensure-venv
@for strategy in minimax weighted_sum variance_penalized; do \
for algo in fem; do \
mkdir -p ./data_generated/roomeq/generated/$algo/small_stereo_2_1; \
echo "=== Multi-measurement $strategy ($algo) small_stereo_2_1 ==="; \
cargo run --bin roomeq --release -- \
--config ./data_tests/roomeq/generated/$algo/small_stereo_2_1/config.json \
--override-config ./data_tests/roomeq/generated/optimiser-config/multi_measurement/$strategy.json \
--output ./data_generated/roomeq/generated/$algo/small_stereo_2_1/dsp_iir_multi_$strategy.json; \
./venv/bin/python3 ./scripts/display-roomeq.py \
./data_generated/roomeq/generated/$algo/small_stereo_2_1/dsp_iir_multi_$strategy.json; \
done \
done
[group('qa-roomeq-multi')]
qa-roomeq-multi-small-stereo-22-mso: ensure-venv
@for strategy in minimax weighted_sum variance_penalized; do \
for algo in fem; do \
mkdir -p ./data_generated/roomeq/generated/$algo/small_stereo_2_2_mso; \
echo "=== Multi-measurement $strategy ($algo) small_stereo_2_2_mso ==="; \
cargo run --bin roomeq --release -- \
--config ./data_tests/roomeq/generated/$algo/small_stereo_2_2_mso/config.json \
--override-config ./data_tests/roomeq/generated/optimiser-config/multi_measurement/$strategy.json \
--output ./data_generated/roomeq/generated/$algo/small_stereo_2_2_mso/dsp_iir_multi_$strategy.json; \
./venv/bin/python3 ./scripts/display-roomeq.py \
./data_generated/roomeq/generated/$algo/small_stereo_2_2_mso/dsp_iir_multi_$strategy.json; \
done \
done
# New comprehensive QA using roomeq-qa-full binary
[group('qa-roomeq')]
qa-roomeq-coverage: prod-autoeq
cargo run --bin roomeq-qa-coverage --release
[group('qa-roomeq')]
qa-roomeq-quick: prod-autoeq
cargo run --bin roomeq-qa-coverage --release -- --quick --maxeval 200
[group('qa-roomeq')]
qa-roomeq-list:
cargo run --bin roomeq-qa-coverage --release -- --list
[group('qa-roomeq')]
qa-roomeq-matrix:
cargo run --bin roomeq-qa-coverage --release -- --matrix
[group('qa-roomeq')]
qa-roomeq-synthetic:
cargo run --bin roomeq-qa-synthetic --no-default-features --release
[group('qa-roomeq')]
qa-roomeq-features:
cargo run --bin roomeq-qa-features --no-default-features --release
# Compact CI-friendly QA run: bounded fuzzer + small coverage subset.
# Typical wall time under 3 minutes on modern hardware.
[group('qa-roomeq')]
qa-roomeq-ci:
cargo run --bin roomeq-fuzzer --release -- -n 50
cargo run --bin roomeq-qa-coverage --release -- --quick --maxeval 200
# Memory-capped integration test runner for autoeq.
#
# The BEM multimode tests spin up one optimizer per test × `cargo test`'s
# worker count. Each optimizer internally forks rayon evaluators over all
# cores, so the effective thread count is num_cpus × num_cpus. On small-
# RAM boxes this OOMs. Cap via `RUST_TEST_THREADS` (default = 2 so BEM
# tests still interleave but memory stays bounded). Override with
# `just test-autoeq threads=N`.
[group('qa-roomeq')]
test-autoeq threads="2":
RUST_TEST_THREADS={{threads}} cargo test -p autoeq --tests --release