Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ jobs:
werror: OFF
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
submodules: recursive

- name: Configure
env:
Expand All @@ -57,6 +59,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
submodules: recursive

- name: Configure
env:
Expand Down Expand Up @@ -89,6 +93,8 @@ jobs:
timeout-minutes: 45
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
submodules: recursive

- name: Install toolchain and QEMU
run: >
Expand Down Expand Up @@ -144,6 +150,8 @@ jobs:
TOOLCHAIN: clang+llvm-19.1.5-cross-hexagon-unknown-linux-musl
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
submodules: recursive

- name: Install QEMU
run: >
Expand Down Expand Up @@ -194,6 +202,8 @@ jobs:
timeout-minutes: 15
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
submodules: recursive

- name: Configure
run: >
Expand All @@ -219,14 +229,16 @@ jobs:
timeout-minutes: 10
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
submodules: recursive
- name: Compile both forms and diff the fingerprint
run: |
set -e
# Ooura is C: compile with gcc so g++ does not name-mangle rdft/rdft_f.
gcc -O2 -c third_party/ooura/fftsg.c -o /tmp/fftsg.o
gcc -O2 -c third_party/ooura/fftsg_float.c -o /tmp/fftsg_float.o
gcc -O2 -c submodules/dsptap/third_party/ooura/fftsg.c -o /tmp/fftsg.o
gcc -O2 -c submodules/dsptap/third_party/ooura/fftsg_float.c -o /tmp/fftsg_float.o
for bl in 0 1; do
g++ -std=c++20 -O2 -DMUTAP_SUPPRESSOR_BRANCHLESS=$bl -Iinclude \
g++ -std=c++20 -O2 -DMUTAP_SUPPRESSOR_BRANCHLESS=$bl -Iinclude -Isubmodules/dsptap/include \
tests/branchless_parity_check.cpp /tmp/fftsg.o /tmp/fftsg_float.o -o /tmp/parity_$bl
/tmp/parity_$bl | tee /tmp/out_$bl
done
Expand Down Expand Up @@ -260,6 +272,8 @@ jobs:
TOOLCHAIN: clang+llvm-19.1.5-cross-hexagon-unknown-linux-musl
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
submodules: recursive

- name: Install toolchains and QEMU
run: >
Expand Down Expand Up @@ -369,6 +383,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
submodules: recursive
# Run the TapHouse pre-commit hook — the exact same pinned clang-format
# developers get from `pre-commit install` (.pre-commit-config.yaml). CI
# and local therefore share one clang-format version by construction, and
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/style.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@ 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-tidy:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install tools
run: sudo apt-get update && sudo apt-get install -y clang-tidy-18 cmake python3
- name: Configure (compile database)
Expand Down
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[submodule "submodules/dsptap"]
path = submodules/dsptap
url = https://github.com/tap/dsptap
branch = main
90 changes: 8 additions & 82 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ cmake_minimum_required(VERSION 3.24)
project(MuTap VERSION 0.1.0 LANGUAGES C CXX)

# ------------------------------------------------------------------------------
# Ooura FFT (vendored) — provides the extern "C" rdft/rdft_f used by
# include/mutap/fft.h. PIC so MODULE/SHARED consumers (host applications,
# Max externals) can link it.
# Shared real FFT (DspTap) — the Ooura wrapper with optional CMSIS-DSP Helium /
# Apple vDSP float32 backends, formerly vendored here (include/mutap/fft.h +
# third_party/{ooura,cmsis-dsp}). Now consumed from the tap/dsptap submodule as
# tap::dsp, which carries the same numeric contract and selects the per-target
# backend itself (CMSIS on the bare-metal M55, vDSP on Apple, Ooura elsewhere).
# Override with -DTAP_DSP_FFT_CMSIS=OFF / -DTAP_DSP_FFT_ACCELERATE=OFF.
# ------------------------------------------------------------------------------

add_library(mutap_fft STATIC third_party/ooura/fftsg.c third_party/ooura/fftsg_float.c)
add_library(MuTap::fft ALIAS mutap_fft)
set_target_properties(mutap_fft PROPERTIES
POSITION_INDEPENDENT_CODE ON
OUTPUT_NAME mutap_fft)
add_subdirectory(submodules/dsptap)

# ------------------------------------------------------------------------------
# The library proper (header-only)
Expand All @@ -23,80 +22,7 @@ target_include_directories(mutap INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
target_compile_features(mutap INTERFACE cxx_std_20)
target_link_libraries(mutap INTERFACE mutap_fft)

# ------------------------------------------------------------------------------
# Helium (Cortex-M55 MVE) FFT backend. When ON, the float32 real FFT in
# include/mutap/fft.h routes through the vendored CMSIS-DSP subset
# (third_party/cmsis-dsp, Apache-2.0) instead of Ooura — measured ~3x fewer
# instructions per transform, ~43% off the whole chain on the M55
# (docs/optimization.md). Double is untouched (always Ooura), so the
# double-precision ITU certification is unaffected; on the float32 embedded
# path CMSIS agrees with Ooura to single-precision rounding (not bit-identical).
#
# Default ON for the bare-metal M55 embedded profile (the deployment target),
# OFF everywhere else — desktop, the Max/C-ABI host builds (incl. Apple
# Silicon arm64, which is not this Generic+arm profile), and Hexagon all keep
# Ooura. Force the Ooura path on the M55 with -DMUTAP_FFT_CMSIS=OFF.
# ------------------------------------------------------------------------------
if(CMAKE_SYSTEM_NAME STREQUAL "Generic" AND CMAKE_SYSTEM_PROCESSOR MATCHES "arm|ARM")
set(_mutap_fft_cmsis_default ON) # bare-metal M55 (cmake/arm-cortex-m55-mps3.cmake)
else()
set(_mutap_fft_cmsis_default OFF)
endif()
option(MUTAP_FFT_CMSIS "Route the float32 FFT through the vendored CMSIS-DSP Helium backend (Arm/Helium only)" ${_mutap_fft_cmsis_default})
if(MUTAP_FFT_CMSIS)
if(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "arm|ARM")
message(FATAL_ERROR
"MUTAP_FFT_CMSIS is an Arm/Helium backend; configure with the "
"cortex-m55 toolchain (cmake/arm-cortex-m55-mps3.cmake).")
endif()
file(GLOB _mutap_cmsis_src CONFIGURE_DEPENDS
${CMAKE_CURRENT_SOURCE_DIR}/third_party/cmsis-dsp/Source/*/*.c)
target_sources(mutap_fft PRIVATE ${_mutap_cmsis_src})
# PRIVATE for the vendored .c compiles; the same dirs are exposed on the
# INTERFACE below so consumers' fft.h can resolve "arm_math.h".
set(_mutap_cmsis_inc
${CMAKE_CURRENT_SOURCE_DIR}/third_party/cmsis-dsp/Include
${CMAKE_CURRENT_SOURCE_DIR}/third_party/cmsis-dsp/PrivateInclude
${CMAKE_CURRENT_SOURCE_DIR}/third_party/cmsis-dsp/cmsis-core/Include)
target_include_directories(mutap_fft PRIVATE ${_mutap_cmsis_inc})
target_include_directories(mutap INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/third_party/cmsis-dsp/Include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/third_party/cmsis-dsp/PrivateInclude>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/third_party/cmsis-dsp/cmsis-core/Include>)
target_compile_definitions(mutap INTERFACE MUTAP_FFT_CMSIS)
message(STATUS "MuTap: float32 FFT backend = CMSIS-DSP Helium")
endif()

# ------------------------------------------------------------------------------
# Apple vDSP (Accelerate) FFT backend. When ON, the float32 real FFT in
# include/mutap/fft.h routes through Apple's vDSP instead of Ooura — measured
# ~3x faster per transform than clang-autovectorized Ooura on Apple Silicon
# (docs/optimization.md), which is what the mutap.aec~ Max external runs.
# Double is untouched (always Ooura), so the double-precision ITU certification
# is unaffected; on the float32 path vDSP agrees with Ooura to single-precision
# rounding (not bit-identical). Default ON for Apple, OFF everywhere else; it is
# mutually exclusive with the CMSIS backend. Force Ooura with
# -DMUTAP_FFT_ACCELERATE=OFF.
# ------------------------------------------------------------------------------
if(APPLE AND NOT MUTAP_FFT_CMSIS)
set(_mutap_fft_accel_default ON)
else()
set(_mutap_fft_accel_default OFF)
endif()
option(MUTAP_FFT_ACCELERATE "Route the float32 FFT through Apple's vDSP (Accelerate) backend (Apple only)" ${_mutap_fft_accel_default})
if(MUTAP_FFT_ACCELERATE)
if(NOT APPLE)
message(FATAL_ERROR "MUTAP_FFT_ACCELERATE requires Apple's Accelerate framework (macOS).")
endif()
if(MUTAP_FFT_CMSIS)
message(FATAL_ERROR "MUTAP_FFT_ACCELERATE and MUTAP_FFT_CMSIS are mutually exclusive.")
endif()
target_compile_definitions(mutap INTERFACE MUTAP_FFT_ACCELERATE)
target_link_libraries(mutap INTERFACE "-framework Accelerate")
message(STATUS "MuTap: float32 FFT backend = Apple vDSP (Accelerate)")
endif()
target_link_libraries(mutap INTERFACE tap::dsp)

# ------------------------------------------------------------------------------
# Options
Expand Down
28 changes: 14 additions & 14 deletions bench/bench_aec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ namespace {
};

template <typename S>
typename mutap::aec_chain<S>::config preset_of(const geometry& g) {
return mutap::aec_chain_preset<S>(g.block, g.partitions, g.fs);
typename tap::mu::aec_chain<S>::config preset_of(const geometry& g) {
return tap::mu::aec_chain_preset<S>(g.block, g.partitions, g.fs);
}

template <typename Proc, typename S>
Expand All @@ -82,9 +82,9 @@ namespace {

template <typename S>
void bench_fdkf(benchmark::State& state, geometry g) {
mutap::partitioned_fdkf<S> core(preset_of<S>(g).canceller);
corpus<S> c(g);
std::vector<S> e(g.block);
tap::mu::partitioned_fdkf<S> core(preset_of<S>(g).canceller);
corpus<S> c(g);
std::vector<S> e(g.block);
warm(core, c, e);
size_t i = 2000;
for (auto _ : state) {
Expand All @@ -99,9 +99,9 @@ namespace {
void bench_suppressor(benchmark::State& state, geometry g) {
auto pf = preset_of<S>(g).postfilter;
pf.block_size = g.block;
mutap::residual_suppressor<S> sup(pf);
corpus<S> c(g);
std::vector<S> e(g.block);
tap::mu::residual_suppressor<S> sup(pf);
corpus<S> c(g);
std::vector<S> e(g.block);
// mid = the corpus mic, yhat = the corpus echo estimate stand-in
for (size_t i = 0; i < 2000; ++i) {
sup.process_block(c.yb(i), c.xb(i), e.data());
Expand All @@ -121,9 +121,9 @@ namespace {
auto sc = cfg.canceller;
sc.partitions = cfg.shadow_partitions;
sc.transition = cfg.shadow_transition;
mutap::partitioned_fdkf<S> shadow(sc);
corpus<S> c(g);
std::vector<S> e(g.block);
tap::mu::partitioned_fdkf<S> shadow(sc);
corpus<S> c(g);
std::vector<S> e(g.block);
warm(shadow, c, e);
size_t i = 2000;
for (auto _ : state) {
Expand All @@ -136,9 +136,9 @@ namespace {

template <typename S>
void bench_chain(benchmark::State& state, geometry g) {
mutap::aec_chain<S> chain(preset_of<S>(g));
corpus<S> c(g);
std::vector<S> e(g.block);
tap::mu::aec_chain<S> chain(preset_of<S>(g));
corpus<S> c(g);
std::vector<S> e(g.block);
warm(chain, c, e);
size_t i = 2000;
for (auto _ : state) {
Expand Down
10 changes: 5 additions & 5 deletions bench/icount/icount_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ namespace {
};

auto preset() {
return mutap::aec_chain_preset<float>(k_geo.block, k_geo.partitions, k_geo.fs);
return tap::mu::aec_chain_preset<float>(k_geo.block, k_geo.partitions, k_geo.fs);
}

// Accumulate a checksum over the timed output so nothing is dead code.
Expand All @@ -105,7 +105,7 @@ namespace {
double sink = 0.0;

#if MUTAP_SC_LAYER == 0
mutap::partitioned_fdkf<float> core(preset().canceller);
tap::mu::partitioned_fdkf<float> core(preset().canceller);
for (std::size_t i = 0; i < k_warm; ++i) {
core.process_block(c.xb(i), c.yb(i), e.data());
}
Expand All @@ -116,7 +116,7 @@ namespace {
#elif MUTAP_SC_LAYER == 1
auto pf = preset().postfilter;
pf.block_size = k_geo.block;
mutap::residual_suppressor<float> sup(pf);
tap::mu::residual_suppressor<float> sup(pf);
for (std::size_t i = 0; i < k_warm; ++i) {
sup.process_block(c.yb(i), c.xb(i), e.data());
}
Expand All @@ -129,7 +129,7 @@ namespace {
auto sc = cfg.canceller;
sc.partitions = cfg.shadow_partitions;
sc.transition = cfg.shadow_transition;
mutap::partitioned_fdkf<float> shadow(sc);
tap::mu::partitioned_fdkf<float> shadow(sc);
for (std::size_t i = 0; i < k_warm; ++i) {
shadow.process_block(c.xb(i), c.yb(i), e.data());
}
Expand All @@ -138,7 +138,7 @@ namespace {
sink += sum_out(e);
}
#else
mutap::aec_chain<float> chain(preset());
tap::mu::aec_chain<float> chain(preset());
for (std::size_t i = 0; i < k_warm; ++i) {
chain.process_block(c.xb(i), c.yb(i), e.data());
}
Expand Down
4 changes: 2 additions & 2 deletions include/mutap/fd_kalman.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
#include "mutap/fdaf.h"
#include "mutap/fft.h"

namespace mutap {
namespace tap::mu {

/// Partitioned-block frequency-domain Kalman filter (after Enzner & Vary
/// 2006; Kuech, Mabande & Enzner 2014; PEM-wrapped for feedback
Expand Down Expand Up @@ -549,4 +549,4 @@ namespace mutap {
bool m_adapt = true;
};

} // namespace mutap
} // namespace tap::mu
4 changes: 2 additions & 2 deletions include/mutap/fdaf.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

#include "mutap/fft.h"

namespace mutap {
namespace tap::mu {

namespace detail {
/// Packed-spectrum multiply-accumulate: y += a * b, in the Ooura real-FFT
Expand Down Expand Up @@ -448,4 +448,4 @@ namespace mutap {
Sample m_ee_weight = Sample(0); ///< 1 - a^n debiasing weight for m_s_ee
};

} // namespace mutap
} // namespace tap::mu
Loading
Loading