Skip to content

Bump the DspTap pin to 28a34a1 #63

Bump the DspTap pin to 28a34a1

Bump the DspTap pin to 28a34a1 #63

Workflow file for this run

name: CI
on:
push:
branches: [main]
pull_request:
jobs:
format:
# The one-time reformat landed with the matching .clang-format; from here
# on, formatting is enforced. Generated tables are excluded via
# .clang-format-ignore and the explicit pathspecs below.
name: clang-format
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Check formatting
run: |
sudo apt-get update && sudo apt-get install -y clang-format-18
clang-format-18 --dry-run --Werror \
$(git ls-files '*.h' '*.cpp' \
':!:third_party/**' \
':!:bench/compare/**' \
':!:include/ambitap/dsp/room_data.h' \
':!:include/ambitap/math/binaural/hrtf_data.h' \
':!:include/ambitap/math/geometry/tdesigns.h')
build-test:
# Compiler/OS matrix, warnings-as-errors everywhere.
strategy:
fail-fast: false
matrix:
include:
- name: linux-gcc
os: ubuntu-latest
cc: gcc
cxx: g++
- name: linux-clang
os: ubuntu-latest
cc: clang
cxx: clang++
- name: macos-appleclang
os: macos-latest
cc: cc
cxx: c++
- name: windows-msvc
os: windows-latest
cc: cl
cxx: cl
name: build-test (${{ matrix.name }})
runs-on: ${{ matrix.os }}
timeout-minutes: 40
env:
CC: ${{ matrix.cc }}
CXX: ${{ matrix.cxx }}
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Configure
run: >
cmake -B build -DCMAKE_BUILD_TYPE=Release
-DAMBITAP_WERROR=ON
-DAMBITAP_BUILD_EXAMPLES=ON
-DAMBITAP_BUILD_BENCH=ON
-DAMBITAP_BUILD_CAPI=ON
- name: Build
run: cmake --build build --parallel --config Release
- name: Test
run: ctest --test-dir build --output-on-failure --build-config Release
- name: Run examples (smoke)
if: runner.os != 'Windows'
run: |
./build/examples/encode_rotate_decode
./build/examples/binaural_render /tmp/orbit.wav
sanitize:
# ASan+UBSan and TSan legs. TSan is what guards the wait-free publish
# path (rt_published / async_rebuilder) and the setter/process stress
# tests in tests/test_dsp_threads.cpp.
strategy:
fail-fast: false
matrix:
include:
- name: asan-ubsan
flags: "-fsanitize=address,undefined -fno-sanitize-recover=all"
- name: tsan
flags: "-fsanitize=thread -fno-sanitize-recover=all -O1"
name: sanitize (${{ matrix.name }})
runs-on: ubuntu-latest
timeout-minutes: 40
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Configure
run: >
cmake -B build -DCMAKE_BUILD_TYPE=Debug
-DCMAKE_CXX_FLAGS="${{ matrix.flags }}"
- name: Build
run: cmake --build build --parallel
- name: Test
run: ctest --test-dir build --output-on-failure
sofa:
# The optional SOFA path is real code; build it so it cannot rot.
name: sofa (build with AMBITAP_ENABLE_SOFA)
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Configure
run: >
cmake -B build -DCMAKE_BUILD_TYPE=Release
-DAMBITAP_ENABLE_SOFA=ON -DAMBITAP_WERROR=ON
- name: Build
run: cmake --build build --parallel
- name: Test
run: ctest --test-dir build --output-on-failure
fuzz:
# The SOFA reader is the library's only untrusted-file surface. Build the
# libFuzzer harness (Clang + ASan/UBSan) and run it for a bounded time
# over the checked-in seed corpus — a regression gate that replays known
# crash reproducers and does light exploratory fuzzing on every push.
# For deep campaigns, run tests/fuzz/fuzz_sofa_reader locally for hours.
name: fuzz (sofa reader smoke)
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Clang + sanitizer/fuzzer runtimes
run: >
sudo apt-get update &&
sudo apt-get install -y clang-18 libclang-rt-18-dev
- name: Configure (Clang + SOFA + fuzzers)
run: >
cmake -B build -DCMAKE_BUILD_TYPE=Debug
-DCMAKE_C_COMPILER=clang-18 -DCMAKE_CXX_COMPILER=clang++-18
-DAMBITAP_ENABLE_SOFA=ON -DAMBITAP_BUILD_FUZZERS=ON
-DAMBITAP_BUILD_TESTS=OFF -DAMBITAP_INSTALL=OFF
- name: Build the fuzzer
run: cmake --build build --target fuzz_sofa_reader --parallel
# Two stages so the gate is genuinely bounded. libFuzzer's per-input
# timeout defaults to 1200s, so without -timeout a single slow input
# (a large structurally-valid mutation takes minutes under Debug+ASan)
# can blow straight past -max_total_time and hit the job kill with no
# reproducer. Stage 1 replays every seed unmodified (full-size valid
# file included); stage 2 fuzzes with mutations capped at 64 KiB so no
# single input can stall the run.
- name: Replay the seed corpus
run: >
ASAN_OPTIONS=detect_leaks=0
./build/tests/fuzz/fuzz_sofa_reader
-timeout=60 -rss_limit_mb=4096 -close_fd_mask=3
tests/fuzz/corpus/*
- name: Fuzz (bounded exploration)
run: >
ASAN_OPTIONS=detect_leaks=0
./build/tests/fuzz/fuzz_sofa_reader
-runs=100000 -max_total_time=180 -timeout=30 -max_len=65536
-rss_limit_mb=4096 -close_fd_mask=3
tests/fuzz/corpus
- name: Upload reproducers on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: fuzz-reproducers
path: |
crash-*
timeout-*
slow-unit-*
oom-*
if-no-files-found: ignore
embedded:
# The embedded real-time profile must stay bare-metal-clean: the RT
# subset (tools/embedded/rt_core_check.cpp documents it) cross-compiles
# for Cortex-M55 with no exceptions, no RTTI, no threads, no Eigen, and
# no hardware doubles (-Wdouble-promotion catches accidental promotion
# in the per-sample paths) — and then actually RUNS, with per-processor
# self-checks, on QEMU's Cortex-M55 machine (mps3-an547, semihosting).
# The nosys link proves nothing hidden is pulled in; the trimmed-table
# variant proves tools/hrtf_trim output is a working drop-in.
name: embedded (cortex-m55 RT-profile gate + QEMU run)
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install the Arm bare-metal toolchain and QEMU
run: >
sudo apt-get update &&
sudo apt-get install -y gcc-arm-none-eabi qemu-system-arm
- name: Cross-compile the RT profile for Cortex-M55 (bare-metal link)
run: |
arm-none-eabi-g++ -std=c++20 -mcpu=cortex-m55 -mthumb -mfloat-abi=hard \
-fno-exceptions -fno-rtti -Os \
-Wall -Wextra -Werror -Wdouble-promotion \
-Iinclude -Isubmodules/dsptap/include \
-c tools/embedded/rt_core_check.cpp -o rt_core_check.o
arm-none-eabi-gcc -mcpu=cortex-m55 -mthumb -mfloat-abi=hard -Os \
-c submodules/dsptap/third_party/ooura/fftsg_float.c -o fftsg_float.o
arm-none-eabi-g++ -mcpu=cortex-m55 -mthumb -mfloat-abi=hard \
--specs=nosys.specs --specs=nano.specs \
rt_core_check.o fftsg_float.o -o rt_core_check.elf
arm-none-eabi-size rt_core_check.elf
- name: Run the RT profile self-checks on QEMU (mps3-an547)
run: |
set -o pipefail
arm-none-eabi-gcc -mcpu=cortex-m55 -mthumb -mfloat-abi=hard -Os -Wall \
-c tools/embedded/qemu/startup_an547.c -o startup_an547.o
arm-none-eabi-g++ -mcpu=cortex-m55 -mthumb -mfloat-abi=hard \
--specs=rdimon.specs --specs=nano.specs -nostartfiles \
-T tools/embedded/qemu/mps3_an547.ld -Wl,--no-warn-rwx-segments \
rt_core_check.o startup_an547.o fftsg_float.o -o rt_core_qemu.elf
timeout 120 qemu-system-arm -machine mps3-an547 -semihosting -nographic \
-kernel rt_core_qemu.elf | tee qemu.log
grep -q "RT-PROFILE-PASS" qemu.log
- name: Trimmed HRTF table is a working drop-in (tools/hrtf_trim)
run: |
set -o pipefail
g++ -std=c++20 -O1 -Iinclude -Isubmodules/dsptap/include tools/hrtf_trim/hrtf_trim.cpp -o hrtf_trim
mkdir -p trimmed/ambitap/math/binaural
./hrtf_trim --order 3 --projection ls \
--out trimmed/ambitap/math/binaural/hrtf_data.h
arm-none-eabi-g++ -std=c++20 -mcpu=cortex-m55 -mthumb -mfloat-abi=hard \
-fno-exceptions -fno-rtti -Os \
-Wall -Wextra -Werror -Wdouble-promotion \
-Itrimmed -Iinclude -Isubmodules/dsptap/include \
-c tools/embedded/rt_core_check.cpp -o rt_trim.o
arm-none-eabi-g++ -mcpu=cortex-m55 -mthumb -mfloat-abi=hard \
--specs=rdimon.specs --specs=nano.specs -nostartfiles \
-T tools/embedded/qemu/mps3_an547.ld -Wl,--no-warn-rwx-segments \
rt_trim.o startup_an547.o fftsg_float.o -o rt_trim_qemu.elf
arm-none-eabi-size rt_trim_qemu.elf
timeout 120 qemu-system-arm -machine mps3-an547 -semihosting -nographic \
-kernel rt_trim_qemu.elf | tee qemu_trim.log
grep -q "RT-PROFILE-PASS" qemu_trim.log
install:
# find_package(AmbiTap) must actually work: install to a prefix, then
# configure and build a minimal downstream consumer against it.
name: install + find_package smoke test
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install Eigen (the exported package declares it as a dependency)
run: sudo apt-get update && sudo apt-get install -y libeigen3-dev
- name: Configure, build, install
run: |
cmake -B build -DCMAKE_BUILD_TYPE=Release -DAMBITAP_BUILD_TESTS=OFF
cmake --build build --parallel
cmake --install build --prefix "$PWD/prefix"
- name: Build a downstream consumer via find_package
run: |
mkdir consumer && cd consumer
cat > main.cpp <<'EOF'
#include <ambitap/ambitap.h>
#include <cstdio>
int main() {
tap::ambi::dsp::encoder enc(3);
enc.set_direction(0.5f, 0.1f);
enc.snap_parameters();
float out[16];
enc.process_sample(1.0f, out);
std::printf("W=%f\n", out[0]);
return out[0] == 1.0f ? 0 : 1;
}
EOF
cat > CMakeLists.txt <<'EOF'
cmake_minimum_required(VERSION 3.24)
project(consumer CXX)
find_package(AmbiTap CONFIG REQUIRED)
add_executable(consumer main.cpp)
target_link_libraries(consumer PRIVATE AmbiTap::ambitap)
EOF
cmake -B build -DCMAKE_PREFIX_PATH="$GITHUB_WORKSPACE/prefix"
cmake --build build
./build/consumer