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
16 changes: 11 additions & 5 deletions .github/workflows/audit-on-push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,17 @@ on:
paths:
- '**/Cargo.toml'
- '**/Cargo.lock'
- 'deny.toml'
pull_request:
paths:
- '**/Cargo.toml'
- '**/Cargo.lock'
- 'deny.toml'
schedule:
- cron: '0 0 * * 0'
jobs:
security_audit:
cargo-deny:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions-rs/audit-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/checkout@v4
- uses: EmbarkStudios/cargo-deny-action@v2
100 changes: 53 additions & 47 deletions .github/workflows/general.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
name: Rust

on: [push, pull_request]
on:
push:
branches: [main]
pull_request:

env:
CARGO_TERM_COLOR: always
Expand All @@ -11,25 +14,25 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macOS-latest]
os: [ubuntu-latest, macos-latest]
rust: [stable, beta]

steps:
- uses: hecrj/setup-rust-action@v2
with:
rust-version: ${{ matrix.rust }}${{ matrix.toolchain }}
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
submodules: true
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
- uses: Swatinem/rust-cache@v2.8.2
- name: Install dependencies
if: matrix.os == 'ubuntu-latest'
run: |
export DEBIAN_FRONTED=noninteractive
export DEBIAN_FRONTEND=noninteractive
sudo apt-get -qq update
sudo apt-get install -y libasound2-dev
- name: Run tests
run: |
cargo test --verbose --workspace --all-features
run: cargo test --workspace --all-features

test-windows:
name: Test (Windows)
Expand All @@ -39,73 +42,76 @@ jobs:
rust: [stable, beta]

steps:
- uses: hecrj/setup-rust-action@v2
with:
rust-version: ${{ matrix.rust }}
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
submodules: true
- uses: crazy-max/ghaction-chocolatey@v1
- uses: dtolnay/rust-toolchain@master
with:
args: install -y pkgconfiglite --checksum 6004df17818f5a6dbf19cb335cc92702
toolchain: ${{ matrix.rust }}
- uses: Swatinem/rust-cache@v2.8.2
- name: Install pkg-config
run: choco install -y pkgconfiglite
- name: Run tests
run: |
cargo test --verbose --workspace --all-features
run: cargo test --workspace --all-features

fmt:
name: Rustfmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
submodules: true
- uses: actions-rs/toolchain@v1
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
override: true
components: rustfmt
- uses: actions-rs/cargo@v1
with:
command: fmt
args: --all -- --check
- run: cargo fmt --all -- --check

clippy:
name: Clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
submodules: true
- uses: actions-rs/toolchain@v1
- name: Install dependencies
run: |
export DEBIAN_FRONTEND=noninteractive
sudo apt-get -qq update
sudo apt-get install -y libasound2-dev
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
override: true
components: clippy
- uses: actions-rs/clippy-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
args: -- -D warnings
- uses: Swatinem/rust-cache@v2.8.2
- run: cargo clippy --workspace --all-features -- -D warnings

coverage:
name: Code coverage
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
submodules: true

- name: Install alsa dev
run: sudo apt-get install -y libasound2-dev

- name: Install stable toolchain
uses: actions-rs/toolchain@v1
- name: Install dependencies
run: |
export DEBIAN_FRONTEND=noninteractive
sudo apt-get -qq update
sudo apt-get install -y libasound2-dev
- uses: dtolnay/rust-toolchain@stable
- uses: Swatinem/rust-cache@v2.8.2
- uses: taiki-e/install-action@v2
with:
toolchain: stable
override: true

tool: cargo-tarpaulin
- name: Run cargo-tarpaulin
uses: actions-rs/tarpaulin@v0.1
run: cargo tarpaulin --workspace --all-features --ignore-tests

wasm:
name: WASM
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
version: '0.15.0'
args: '--ignore-tests'
targets: wasm32-unknown-unknown
- uses: Swatinem/rust-cache@v2.8.2
- name: Check WASM build
run: cargo check --lib --target wasm32-unknown-unknown --all-features
46 changes: 46 additions & 0 deletions .github/workflows/release-plz.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: Release-plz

on:
push:
branches:
- main

jobs:
release-plz-release:
name: Release
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false
- uses: dtolnay/rust-toolchain@stable
- uses: release-plz/action@v0.5
with:
command: release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}

release-plz-pr:
name: Release PR
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
concurrency:
group: release-plz-${{ github.ref }}
cancel-in-progress: false
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false
- uses: dtolnay/rust-toolchain@stable
- uses: release-plz/action@v0.5
with:
command: release-pr
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
20 changes: 14 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,35 +1,43 @@
[package]
name = "sofar"
version = "0.2.1"
edition = "2021"
edition = "2024"
readme = "README.md"
license = "MIT OR Apache-2.0"
authors = ["Tomasz Andrzejak <andreiltd@gmail.com>"]
keywords = ["libmysofa", "hrtf", "aes69"]
description = "Rust bindings for the libmysofa library"
description = "Pure Rust SOFA/HRTF reader and renderer"
repository = "https://github.com/andreiltd/sofar"
homepage = "https://github.com/andreiltd/sofar"
categories = ["algorithms", "filesystem", "multimedia::audio"]

[features]
default = ["dsp"]
dsp = ["dep:realfft"]
resample = ["dep:rubato", "dep:audioadapter-buffers"]

[workspace]
members = ["libmysofa-sys"]

[dependencies]
ffi = { package = "libmysofa-sys", version = "0.2.1", path = "libmysofa-sys" }
arrayvec = "0.7.6"
bitflags = "2.9.1"
log = "0.4.27"
miniz_oxide = "0.8.9"
realfft = {version = "3.4", optional = true}
thiserror = "1"
rubato = {version = "1.0.1", optional = true}
audioadapter-buffers = {version = "2.0", optional = true}
thiserror = "2"
winnow = "0.7.11"

[dev-dependencies]
anyhow = "1.0"
arc-swap = "1"
assert_approx_eq = "1.1"
hound = "3.5"
cpal = "0.15"
cpal = "0.17"
criterion = "0.5"
rand = "0.8"
rand = "0.9"
ringbuf = "0.4"

[[bench]]
Expand Down
20 changes: 20 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
NOTICE

This software contains code derived from the libmysofa project.

libmysofa
---------
Copyright (c) 2016-2017, Symonics GmbH, Christian Hoene
Licensed under the BSD 3-Clause License
https://github.com/hoene/libmysofa

The following components are derived from libmysofa:

- HDF5 file format parser (src/hdf/)
- SOFA/HRTF algorithms (src/sofa/): spatial lookup, interpolation,
coordinate conversion, loudness normalization, validation

The KD-tree implementation is based on work by:

Copyright (C) 2007-2011 John Tsiombikas <nuclear@member.fsf.org>
Licensed under BSD 3-Clause License
23 changes: 17 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,19 @@
<img src="docs/homer-sofar.png"/>

# Sofar
Sofa Reader and Renderer
Pure Rust SOFA Reader and HRTF Renderer

</div>

## Features
This crate provides high level bindings to [`libmysofa`] API allows to read
`HRTF` filters from `SOFA` files (Spatially Oriented Format for Acoustics).
A pure Rust implementation for reading `HRTF` filters from `SOFA` files
(Spatially Oriented Format for Acoustics).

The [`render`] module implements uniformly partitioned convolution algorithm
for rendering HRTF filters.

Based on the [`libmysofa`] C library by Christian Hoene / Symonics GmbH.

[`libmysofa`]: https://github.com/hoene/libmysofa
[`render`]: `crate::render`

Expand All @@ -33,7 +35,7 @@ let sofa = OpenOptions::new()
let filt_len = sofa.filter_len();
let mut filter = Filter::new(filt_len);

// Get filter at poistion
// Get filter at position
sofa.filter(0.0, 1.0, 0.0, &mut filter);

let mut render = Renderer::builder(filt_len)
Expand All @@ -42,7 +44,7 @@ let mut render = Renderer::builder(filt_len)
.build()
.unwrap();

render.set_filter(&filter);
render.set_filter(&filter).unwrap();

let input = vec![0.0; 256];
let mut left = vec![0.0; 256];
Expand All @@ -57,9 +59,18 @@ You can run `cpal` renderer example like this:

``` shell
cargo run --example renderer -- <FILENAME-MONO.wav> libmysofa-sys/libmysofa/share/default.sofa

```

## Acknowledgments

This project is a Rust port of [libmysofa](https://github.com/hoene/libmysofa),
a C library for reading SOFA files.

- **libmysofa** Copyright © 2016-2017 Symonics GmbH, Christian Hoene (BSD-3-Clause)
- **KD-tree** Copyright © 2007-2011 John Tsiombikas (BSD-3-Clause)

See the [NOTICE](NOTICE) file for full attribution details.

# License

This project is licensed under either of
Expand Down
10 changes: 5 additions & 5 deletions benches/renderer.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
use criterion::{criterion_group, criterion_main, Bencher, BenchmarkId, Criterion};
use sofar::{reader::Filter, render::Renderer};
use criterion::{Bencher, BenchmarkId, Criterion, criterion_group, criterion_main};
use sofar::{filter::Filter, render::Renderer};

use rand::Rng;

fn bench_renderer(b: &mut Bencher, blocks: usize, block_len: usize, filt_len: usize) {
let mut filt = Filter::new(filt_len);

rand::thread_rng().fill(&mut *filt.left);
rand::thread_rng().fill(&mut *filt.right);
rand::rng().fill(&mut *filt.left);
rand::rng().fill(&mut *filt.right);

let mut input = vec![0.0; blocks * block_len];
let mut left = vec![0.0; blocks * block_len];
let mut right = vec![0.0; blocks * block_len];

rand::thread_rng().fill(input.as_mut_slice());
rand::rng().fill(input.as_mut_slice());

let mut renderer = Renderer::builder(filt_len)
.with_partition_len(block_len)
Expand Down
Loading
Loading