math-rir 0.5.6

Room Impulse Response analysis: SSIR segmentation, ISO 3382 reverberation/clarity metrics, octave-band filtering
Documentation
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [0.5.6] - 2026-05-30

### Added
- Added `SsirResult::direct_sound_doa()` for callers that need the detected
  direct-sound direction without indexing the first segment.
- Added `schroeder_curve()` as a public direct-sound-anchored convenience
  wrapper around `DecayCurve::from_rir`.

### Fixed
- `detection::find_direct_sound_toa` now follows the SSIR 11 dB rule using
  unsuppressed local maxima in time order, so a stronger nearby reflection can
  no longer hide the earlier direct arrival through min-distance suppression.
- Short-RIR direct-sound fallback now prefers the earliest sample when absolute
  peak magnitudes tie.
- Plateau local maxima now report the first plateau sample, avoiding a
  one-sample-late bias on broadened arrivals.
- LER reflection detection now excludes the direct-sound window from the local
  median and can emit multiple local maxima from the same analysis window,
  leaving TOA/DOA validation to merge only non-distinct candidates.
- Reflection merging now re-checks the previous neighbor after replacing an
  event with a higher-energy later event, removing order-dependent leftovers.

### Changed
- Clarified LER window behavior, the peak-relative onset heuristic, and the
  Abel-Huang echo-density mixing-time documentation.

### Tests
- Added regression coverage for direct-sound min-distance suppression,
  short-RIR ties, plateau peaks, same-window reflections, merge re-anchoring,
  direct-sound DOA access, and the public Schroeder curve helper.

## [0.5.5] - 2025-05-13

### Added
- **ISO 3382 room-acoustic metrics** (`metrics.rs`). Computes reverberation
  time (EDT, T20, T30), clarity (C50, C80), definition (D50), and centre
  time (Ts) from a measured RIR. Each fitted reverberation time carries an
  `` so callers can flag non-linear decays (coupled rooms, noise-dominated
  tails). Time integration is anchored at the detected direct-sound arrival
  to keep pre-trigger silence out of the result.
- **Octave-band and third-octave-band analysis** (`bands.rs`). ISO/IEC 61260
  centre frequencies plus zero-phase Butterworth bandpasses (HP ∘ LP cascade
  through `filtfilt`), parallelised per band via rayon.

### Fixed
- `detection::find_direct_sound_toa`: peak-suppression order corrected.
  Previously returned the *first* peak above `−11 dB` in time order, which
  let an early pre-blip shadow the actual direct-sound peak. Now returns the
  **earliest peak within a 1 dB tie band of the global maximum**.
- `compute_bformat_doa`: documented the `+I/|I|` sign convention used for
  first-order Ambisonics pseudo-intensity DOA and added plane-wave test
  fixtures (`+X`, `+Y`) that verify it.

### Performance
- `compute_bformat_doa`: cut allocation count from ~8 large `Vec`s per call
  to 0 in the no-filter branch and 2 per channel in the filter branch.

### Tests
- Added 10 ISO 3382 unit tests: linear-fit primitive, Schroeder
  monotonicity, T20/T30/EDT against synthetic exponential decay, anechoic
  D50/C50/C80, closed-form clarity on a uniform-energy RIR, empty-input
  handling, `fit_is_valid` threshold.
- Added 5 band-filter tests: log-symmetric edges, DC suppression, in-band
  pass-through, out-of-band rejection (> 40 dB), octave dispatch smoke test.
- Added 4 review-driven tests: plane-wave B-format DOA from `+X` and `+Y`;
  `find_direct_sound_toa` tie-band behaviour on two synthetic peak fixtures.
- All 43 lib tests + 1 doctest pass; clippy clean with `-D warnings`.

## [0.5.4] - 2025-05-13

### Fixed
- `segmentation::build_segments`: Fixed short-segment merge logic. The condition `i > 1`
  incorrectly exempted the first reflection from merging; changed to `i > 0` so that only
  the direct sound is always kept, matching the documented behavior.
- `detection::find_direct_sound_toa`: Signals with fewer than 3 samples now fall back
  to the global maximum instead of returning `None`, allowing very short RIRs to be analyzed.
- `detection::median_of`: NaN values no longer corrupt the median. Non-finite values
  are partitioned out before sorting; if no finite values remain, `NaN` is returned.

### Tests
- Added `test_first_reflection_merged_when_too_short` (segmentation).
- Added `test_find_direct_sound_toa_short_rir` (detection).
- Added `test_median_of_with_nan` (detection).
- All 27 lib tests + 1 doctest pass; clippy clean.

## [0.5.3] - 2025-05-13

### Performance
- Local Energy Ratio windows now run in parallel.
- Echo-density windows are computed in parallel.
- Reflection onset refinement is parallelized.
- SRIR B-format channel filtering and DOA vector generation now use Rayon.
- Added Rayon dependency.

## [0.5.2] - 2025-05-13

### Fixed
- Bumped math crates to 0.5: iir-fir now also works with f32, rir is band limited and linear phase.
- Moved many functions from sotf-host to math-dsp and math-iir-fir.