Metadata-Version: 2.4
Name: multislope
Version: 0.1.0
Summary: Multi-slope sound energy decay estimation: DecayFitNet, Bayesian decay analysis, and friends
Project-URL: Homepage, https://github.com/artificial-audio/multislope
Project-URL: Repository, https://github.com/artificial-audio/multislope
Project-URL: Issues, https://github.com/artificial-audio/multislope/issues
Project-URL: Changelog, https://github.com/artificial-audio/multislope/blob/main/CHANGELOG.md
Author-email: "Sebastian J. Schlecht" <sebastian.schlecht@fau.de>
Maintainer-email: "Sebastian J. Schlecht" <sebastian.schlecht@fau.de>
License-Expression: MIT
License-File: LICENSE
Keywords: acoustics,decay analysis,impulse response,multi-slope,reverberation,reverberation time,room acoustics
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Multimedia :: Sound/Audio :: Analysis
Classifier: Topic :: Scientific/Engineering
Requires-Python: >=3.10
Requires-Dist: numpy>=1.22
Requires-Dist: onnxruntime>=1.15
Requires-Dist: scipy>=1.9
Provides-Extra: dev
Requires-Dist: build>=1.0; extra == 'dev'
Requires-Dist: h5py>=3.7; extra == 'dev'
Requires-Dist: matplotlib>=3.5; extra == 'dev'
Requires-Dist: onnx>=1.14; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Requires-Dist: soundfile>=0.12; extra == 'dev'
Requires-Dist: tensorboard>=2.10; extra == 'dev'
Requires-Dist: torch>=2.0; extra == 'dev'
Requires-Dist: torchaudio>=2.0; extra == 'dev'
Requires-Dist: tqdm>=4.64; extra == 'dev'
Requires-Dist: twine>=5.0; extra == 'dev'
Provides-Extra: plot
Requires-Dist: matplotlib>=3.5; extra == 'plot'
Provides-Extra: torch
Requires-Dist: torch>=2.0; extra == 'torch'
Requires-Dist: torchaudio>=2.0; extra == 'torch'
Provides-Extra: train
Requires-Dist: h5py>=3.7; extra == 'train'
Requires-Dist: onnx>=1.14; extra == 'train'
Requires-Dist: tensorboard>=2.10; extra == 'train'
Requires-Dist: torch>=2.0; extra == 'train'
Requires-Dist: torchaudio>=2.0; extra == 'train'
Requires-Dist: tqdm>=4.64; extra == 'train'
Description-Content-Type: text/markdown

# multislope

Multi-slope sound energy decay estimation for room impulse responses.

Rooms rarely decay with a single reverberation time. Coupled volumes, non-diffuse
fields, and strongly absorbing surfaces produce energy decay curves that need two
or three exponentials to be described well. `multislope` estimates those decay
times, their amplitudes, and the noise floor, per octave band, from a measured RIR.

```bash
pip install multislope
```

The core install is NumPy, SciPy, and ONNX Runtime — no PyTorch required.

## Quickstart

```python
import multislope
import soundfile as sf

rir, fs = sf.read("my_rir.wav")

net = multislope.DecayFitNet(sample_rate=fs)
fit = net.estimate(rir)

print(fit)
# DecayFit(method='DecayFitNet', sample_rate=48000)
#      125 Hz  T = [0.690] s  A = [0.963]  N = 1.9e-08
#      250 Hz  T = [0.530, 2.303] s  A = [0.787, 0.0634]  N = 1.15e-09
#   ...

fit.t          # (n_bands, n_slopes) decay times in seconds; 0 marks an inactive slope
fit.a          # (n_bands, n_slopes) amplitudes, linear scale
fit.n          # (n_bands, 1) noise floor, linear scale
fit.n_slopes   # (n_bands,) number of active slopes per band
```

Reconstruct the fitted EDC to compare it against the measured one:

```python
import numpy as np

pre = multislope.PreprocessRIR(sample_rate=fs)
measured_edc, _ = pre.schroeder(rir)              # (n_channels, n_bands, n_samples)
time_axis = np.arange(measured_edc.shape[-1]) / fs

fitted_edc = fit.edc(time_axis)                   # (n_bands, n_samples)
```

## Methods

| | `DecayFitNet` | `BayesianDecayAnalysis` |
|---|---|---|
| Approach | trained neural network (bundled, ~10 MB of ONNX weights) | slice sampling over a discrete parameter grid |
| Speed | milliseconds per RIR | seconds to minutes per RIR |
| Slopes | 1–3, either fixed or estimated by the network | 1–3, either fixed or selected by BIC |
| Needs training data | already trained | no |
| Determinism | deterministic | stochastic; pass `seed=` to reproduce |

Both take the same arguments and return the same `DecayFit`:

```python
net = multislope.DecayFitNet(n_slopes=0, sample_rate=fs)          # 0 = estimate the count
bda = multislope.BayesianDecayAnalysis(n_slopes=0, sample_rate=fs, n_iterations=100, seed=0)

fit_net = net.estimate(rir)
fit_bayes = bda.estimate(rir)
```

## Options

**Fixing the number of slopes.** `n_slopes=2` fits exactly two slopes and skips
model-order selection. `n_slopes=0` lets the estimator decide, and inactive
slopes come back with `T = A = 0`.

**Frequency bands.** The default bands are 125 Hz to 4 kHz. Pass your own centre
frequencies; a `0` adds a lowpass band below the lowest octave, and
`sample_rate / 2` adds a highpass band above the highest one.

```python
net = multislope.DecayFitNet(sample_rate=fs, filter_frequencies=[0, 125, 250, 500, 1000, 2000, 4000, fs / 2])
```

**Direct sound.** By default the whole RIR is analysed. Pass
`analyse_full_rir=False` to detect the direct-sound onset and discard everything
before it.

**Analysing an EDC directly.** If you already have an energy decay curve, pass
`input_is_edc=True` to skip filtering and backwards integration.

## Example data

The example RIRs from the DecayFitNet repository are downloaded on first use and
cached locally, so they are not part of the wheel:

```python
from multislope import data

rir, fs = data.example_rir("doubleslope")
print(data.available_examples())
```

## Optional extras

```bash
pip install multislope[plot]    # matplotlib helpers in multislope.plotting
pip install multislope[train]   # PyTorch training code in multislope.training
```

`multislope.training` re-exports the original DecayFitNet training pipeline
(dataset, model definition, and EDC loss) for anyone who wants to retrain or
fine-tune the network. It is not needed for inference.

## Attribution

The DecayFitNet and Bayesian estimators, and the bundled network weights, are
derived from the [DecayFitNet toolbox](https://github.com/georg-goetz/DecayFitNet)
by Georg Götz, Sebastian J. Schlecht, and Ville Pulkki, used under the MIT
license. This package ports the Python toolbox to NumPy/SciPy, packages it for
PyPI, and keeps its numerics unchanged (verified by regression tests against the
reference implementation).

If you use this software, please cite:

```bibtex
@article{goetz2022decayfitnet,
  title   = {Neural network for multi-exponential sound energy decay analysis},
  author  = {G{\"o}tz, Georg and Schlecht, Sebastian J. and Pulkki, Ville},
  journal = {The Journal of the Acoustical Society of America},
  volume  = {152},
  number  = {2},
  pages   = {942--953},
  year    = {2022},
  doi     = {10.1121/10.0013416}
}
```

The Bayesian analysis follows Xiang et al., "Bayesian characterization of
multiple-slope sound energy decays in coupled-volume systems", JASA 129(2),
741–752, 2011, and Jasa & Xiang, "Efficient estimation of decay parameters in
acoustically coupled-spaces using slice sampling", JASA 126(3), 1269–1279, 2009.

## Development

```bash
git clone https://github.com/artificial-audio/multislope
cd multislope
pip install -e ".[dev]"

python -m multislope.data download   # the regression tests analyse the example RIRs
pytest                               # full suite, including torch parity and slow Bayesian tests
pytest -m "not slow"                 # fast subset
ruff check .
```

The regression tests compare every estimate against
`tests/data/golden_upstream.npz`, captured by running the reference PyTorch
implementation. `scripts/make_golden_fixtures.py` regenerates it; see its
docstring for how.

## License

MIT. See [LICENSE](LICENSE).
