diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml index 0d7eb3e..172dc5b 100644 --- a/.github/workflows/style.yml +++ b/.github/workflows/style.yml @@ -11,9 +11,9 @@ on: [push, pull_request] jobs: drift: - uses: tap/taphouse/.github/workflows/drift-check.yml@v3 + uses: tap/taphouse/.github/workflows/drift-check.yml@v4 with: - ref: v3 + ref: v4 clang-format: runs-on: ubuntu-latest diff --git a/scripts/tidy.sh b/scripts/tidy.sh new file mode 100755 index 0000000..45fc009 --- /dev/null +++ b/scripts/tidy.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash +# Local mirror of the CI clang-tidy gate (.github/workflows/style.yml): the +# TapHouse .clang-tidy naming + mandatory-braces checks over this project's +# own translation units. Run it before pushing. +# +# WHY THIS EXISTS (and is not a pre-commit hook): the pre-commit hook only +# runs clang-FORMAT, which is cheap and context-free. clang-TIDY needs a +# compile database (a configured CMake build) and compiles every TU to reason +# about types — too slow and stateful for a per-commit hook, so CI keeps it as +# its own gate. This script is the fast local equivalent of that gate. +# +# Usage: +# scripts/tidy.sh # sweep every project TU (full CI mirror) +# scripts/tidy.sh tests/test_foo.cpp … # only the given TU(s) — fast, for a change +# +# Env: +# CLANG_TIDY=clang-tidy-18 # binary to use (default: clang-tidy-18, then clang-tidy) +# TIDY_BUILD=build-tidy # compile-database build dir (kept separate from ./build) +# TIDY_RECONFIGURE=1 # force a cmake re-configure of the compile database +set -euo pipefail + +repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$repo_root" + +# Prefer clang-tidy-18 — the version the CI gate installs and the .clang-tidy +# checks are validated against; a different major version may disagree. +tidy="${CLANG_TIDY:-}" +if [ -z "$tidy" ]; then + if command -v clang-tidy-18 >/dev/null 2>&1; then + tidy=clang-tidy-18 + elif command -v clang-tidy >/dev/null 2>&1; then + tidy=clang-tidy + echo "warning: clang-tidy-18 not found; using '$tidy'. CI pins v18 — results may differ." >&2 + else + echo "error: no clang-tidy found. Install clang-tidy-18 (apt) or set CLANG_TIDY=..." >&2 + exit 127 + fi +fi + +build="${TIDY_BUILD:-build-tidy}" + +# A compile database is what clang-tidy needs; reuse it across runs unless it is +# missing or a reconfigure is forced. This does not touch your ./build dir. +if [ "${TIDY_RECONFIGURE:-0}" = "1" ] || [ ! -f "$build/compile_commands.json" ]; then + echo "== configuring compile database in $build/ (one-time; reuses cached deps) ==" + cmake -B "$build" -DCMAKE_EXPORT_COMPILE_COMMANDS=ON >/dev/null +fi + +# File list: the given TUs, or — matching CI exactly — every project TU in the +# database with third_party/ and fetched deps (_deps) excluded. +if [ "$#" -gt 0 ]; then + files=("$@") +else + mapfile -t files < <(python3 -c " +import json +for e in json.load(open('$build/compile_commands.json')): + f = e['file'] + if 'third_party' not in f and '_deps' not in f: + print(f)") +fi + +echo "== clang-tidy ($tidy) over ${#files[@]} file(s) ==" +fail=0 +for f in "${files[@]}"; do + out="$("$tidy" -p "$build" "$f" 2>/dev/null || true)" + if printf '%s\n' "$out" | grep -qE "warning:|error:"; then + printf '%s\n' "$out" + fail=1 + fi +done + +if [ "$fail" -eq 0 ]; then + echo "clang-tidy clean." +else + echo "clang-tidy found violations (above); fix before pushing." >&2 + exit 1 +fi diff --git a/source/projects/mutap.aec_tilde/CMakeLists.txt b/source/projects/mutap.aec_tilde/CMakeLists.txt index 476990c..2da4d2b 100644 --- a/source/projects/mutap.aec_tilde/CMakeLists.txt +++ b/source/projects/mutap.aec_tilde/CMakeLists.txt @@ -19,8 +19,8 @@ add_library( ${SOURCE_FILES} ) -# MuTap headers (header-only pem_afc/fdaf/lpc) + MuTap::fft (the vendored -# Ooura rdft that mutap::basic_real_fft calls); the `mutap` interface target +# MuTap headers (header-only pem_afc/fdaf/lpc) + tap::dsp (the vendored +# Ooura rdft that tap::mu::basic_real_fft calls); the `mutap` interface target # carries both. target_link_libraries(${PROJECT_NAME} PRIVATE mutap) target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20) diff --git a/source/projects/mutap.aec_tilde/mutap.aec_tilde.cpp b/source/projects/mutap.aec_tilde/mutap.aec_tilde.cpp index 71c7c7c..1d354fa 100644 --- a/source/projects/mutap.aec_tilde/mutap.aec_tilde.cpp +++ b/source/projects/mutap.aec_tilde/mutap.aec_tilde.cpp @@ -5,7 +5,7 @@ /// the patch sends to the speaker), so nothing the canceller does feeds back /// around — what survives from the feedback problem is DOUBLE-TALK, the /// near-end talker speaking over the echo. Wraps the same -/// mutap::pem_afc engines as mutap.afc~ (the paper the PEM structure +/// tap::mu::pem_afc engines as mutap.afc~ (the paper the PEM structure /// implements — Gil-Cacho et al. 2014 — is an open-loop double-talk-robust /// AEC framework before MuTap borrowed it for feedback): the near-end model /// is re-fit every block and whitened out of the adaptive update, which is @@ -27,14 +27,14 @@ /// dominates) every few processed blocks. /// /// @postfilter swaps the whole engine for the measured AEC CHAIN -/// (mutap::aec_chain): the RAW frequency-domain Kalman canceller — not PEM; +/// (tap::mu::aec_chain): the RAW frequency-domain Kalman canceller — not PEM; /// open-loop AEC has an exogenous far end, so the predictor refit buys /// nothing and measurably floors the misalignment — plus the /// coherence-driven residual suppressor, comfort noise matched to the /// near-end noise floor, and the initial receive guard. This is the /// configuration MuTap's ITU-T compliance battery certifies at 48 and /// 16 kHz (docs/itu-compliance.md in MuTap; every requirement met at both -/// rates), built from the library's own preset (mutap::aec_chain_preset), +/// rates), built from the library's own preset (tap::mu::aec_chain_preset), /// which rescales every per-block time constant for the actual @block and /// host sample rate. With @postfilter on, @mu, @warp and @kalman are ignored (the /// chain's canceller is already the Kalman core) and @gate selects the @@ -76,12 +76,13 @@ using namespace c74::min; class mutap_aec : public object, public vector_operator<> { - using speech_aec = mutap::pem_afc; - using warped_aec = mutap::pem_afc>; - using kalman_speech_aec = mutap::pem_afc, mutap::partitioned_fdkf>; + using speech_aec = tap::mu::pem_afc; + using warped_aec = tap::mu::pem_afc>; + using kalman_speech_aec = + tap::mu::pem_afc, tap::mu::partitioned_fdkf>; using kalman_warped_aec = - mutap::pem_afc, mutap::partitioned_fdkf>; - using chain_aec = mutap::aec_chain; ///< raw Kalman canceller + suppressor + comfort noise + tap::mu::pem_afc, tap::mu::partitioned_fdkf>; + using chain_aec = tap::mu::aec_chain; ///< raw Kalman canceller + suppressor + comfort noise /// One canceller plus its vector-size bridging buffers, all sized for one /// block. Built on the control thread; used (and only used) on the audio @@ -458,14 +459,14 @@ class mutap_aec : public object, public vector_operator<> { return cfg; } - /// The compliance chain IS the library preset (mutap::aec_chain_preset — + /// The compliance chain IS the library preset (tap::mu::aec_chain_preset — /// the configuration MuTap's ITU battery certifies, with every per-block /// time constant rescaled for the actual block and sample rate; its /// header documents the rule and the two deliberate exceptions). Only the /// external's own toggles are applied on top. typename chain_aec::config make_chain_config(double sr) const { const auto b = static_cast(m_block_size); - auto cfg = mutap::aec_chain_preset( + auto cfg = tap::mu::aec_chain_preset( b, std::max(1, (static_cast(m_filter_length) + b - 1) / b), sr); cfg.postfilter.comfort_noise = m_comfort; // @gate selects the initial receive guard (switched < 14 dB send loss diff --git a/source/projects/mutap.afc_tilde/CMakeLists.txt b/source/projects/mutap.afc_tilde/CMakeLists.txt index 7b08551..1bc677e 100644 --- a/source/projects/mutap.afc_tilde/CMakeLists.txt +++ b/source/projects/mutap.afc_tilde/CMakeLists.txt @@ -19,8 +19,8 @@ add_library( ${SOURCE_FILES} ) -# MuTap headers (header-only pem_afc/fdaf/lpc) + MuTap::fft (the vendored -# Ooura rdft that mutap::basic_real_fft calls); the `mutap` interface target +# MuTap headers (header-only pem_afc/fdaf/lpc) + tap::dsp (the vendored +# Ooura rdft that tap::mu::basic_real_fft calls); the `mutap` interface target # carries both. target_link_libraries(${PROJECT_NAME} PRIVATE mutap) target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20) diff --git a/source/projects/mutap.afc_tilde/mutap.afc_tilde.cpp b/source/projects/mutap.afc_tilde/mutap.afc_tilde.cpp index 634e333..8da4d9b 100644 --- a/source/projects/mutap.afc_tilde/mutap.afc_tilde.cpp +++ b/source/projects/mutap.afc_tilde/mutap.afc_tilde.cpp @@ -1,17 +1,17 @@ /// @file /// mutap.afc~ — acoustic feedback (howling) canceller: subtract an adaptive /// estimate of the loudspeaker→microphone feedback path from the microphone -/// signal. Wraps mutap::pem_afc (FDAF-PEM-AFROW: a partitioned-block +/// signal. Wraps tap::mu::pem_afc (FDAF-PEM-AFROW: a partitioned-block /// frequency-domain adaptive filter whose update is decorrelated from the /// near-end source by prediction-error-method prewhitening — the closed loop /// biases any naive adaptive estimate, and the PEM prewhitening removes that /// bias; Gil-Cacho et al. 2014, Rombouts et al. 2007). @warp swaps the /// speech-cascade near-end model for the frequency-warped one built for -/// music/tonal material (mutap::warped_lpc_predictor), and keeps IPC step +/// music/tonal material (tap::mu::warped_lpc_predictor), and keeps IPC step /// scaling on while it is active — the warped whitener requires it for /// room-robust closed-loop stability (see include/mutap/lpc.h in MuTap). /// @kalman swaps the NLMS core for the frequency-domain Kalman filter -/// (mutap::partitioned_fdkf, the v2 engine): @mu is ignored, @gate selects +/// (tap::mu::partitioned_fdkf, the v2 engine): @mu is ignored, @gate selects /// the burst floor, and the warped model needs no IPC pairing there. /// /// Signal inlet 0 is the microphone signal y; signal inlet 1 is the @@ -54,11 +54,12 @@ using namespace c74::min; class mutap_afc : public object, public vector_operator<> { - using speech_afc = mutap::pem_afc; - using warped_afc = mutap::pem_afc>; - using kalman_speech_afc = mutap::pem_afc, mutap::partitioned_fdkf>; + using speech_afc = tap::mu::pem_afc; + using warped_afc = tap::mu::pem_afc>; + using kalman_speech_afc = + tap::mu::pem_afc, tap::mu::partitioned_fdkf>; using kalman_warped_afc = - mutap::pem_afc, mutap::partitioned_fdkf>; + tap::mu::pem_afc, tap::mu::partitioned_fdkf>; /// One canceller plus its vector-size bridging buffers, all sized for one /// block. Built on the control thread; used (and only used) on the audio diff --git a/submodules/MuTap b/submodules/MuTap index 6897f55..2e02473 160000 --- a/submodules/MuTap +++ b/submodules/MuTap @@ -1 +1 @@ -Subproject commit 6897f55991f2363b436c7eb4ca24348e878fb111 +Subproject commit 2e024739bfb54aab8c23224a5b1ef28b1870c1ad