Metadata-Version: 2.4
Name: dsp-audio-metrics
Version: 0.1.0
Summary: BS.1770-4 loudness metering and audio analysis: LUFS, LRA, true peak, spectral balance, stereo width.
Author-email: Gaetano <gtno.sound@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/gtno-sound/dsp-audio-metrics
Project-URL: Repository, https://github.com/gtno-sound/dsp-audio-metrics
Keywords: audio,dsp,metrics,loudness,lufs,lra,metering,bs1770,ebur128,true-peak,analysis
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
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.9
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
Classifier: Topic :: Multimedia :: Sound/Audio :: Analysis
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.21
Requires-Dist: scipy>=1.7
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: build>=1; extra == "dev"
Requires-Dist: twine>=5; extra == "dev"
Dynamic: license-file

# dsp-audio-metrics

Pure **numpy/scipy** BS.1770-4 loudness metering and audio analysis for Python.

Measures **integrated loudness (LUFS)**, **loudness range (LRA)**, **true peak
(dBTP)** per ITU-R BS.1770-4 / EBU R128, plus spectral balance, stereo-width
and level helpers — with zero dependencies beyond numpy and scipy.

## Install

```bash
pip install dsp-audio-metrics
```

## Quick start

```python
import numpy as np
import dsp_audio_metrics as dm

sr = 44100
t = np.arange(sr * 60) / sr
programme = 0.5 * np.sin(2 * np.pi * 997 * t)

res = dm.measure(programme, sr)
print(res.integrated_lufs)      # ~ -9.0 LUFS
print(res.true_peak_db)         # ~ -6.0 dBTP
print(res.gain_to_target_db)    # gain to hit -14 LUFS

normalized = dm.normalize_loudness(programme, sr, target_lufs=-14.0)
```

## API

### Loudness (BS.1770-4 / EBU R128)

| Function | Returns |
|---|---|
| `integrated_lufs(audio, sr)` | integrated programme loudness in LUFS (`-inf` on silence) |
| `short_term_lufs(audio, sr)` | `(lkfs, times_s)` per-window loudness |
| `loudness_range(audio, sr)` | LRA in LU (`NaN` when unmeasurable) |
| `true_peak_db(audio, sr)` | true-peak level in dBTP (oversampled to ≥ 192 kHz) |
| `measure(audio, sr)` | `LoudnessResult` dataclass summary |
| `normalize_loudness(audio, sr, target_lufs)` | gain-normalized copy |

### Analysis

| Function | Returns |
|---|---|
| `band_balance(audio, sr)` | `{sub, low, mid, high}` energy percentages (mono mix) |
| `stereo_width(audio, sr)` | `(times_s, width_db, mid_db)` per-window mid/side stats |
| `rms_db(audio)` / `peak_db(audio)` | broadband level, dBFS |
| `crest_factor_db(audio)` | peak/RMS ratio in dB |

All functions accept mono `(n,)`, `(n, 1)`, stereo `(n, 2)` or multichannel
`(n, c)` input and internally resample to the 48 kHz rate the standards
mandate, so 44.1 kHz files are measured correctly.

## Why this package

* Correct: every loudness path follows BS.1770-4 (48 kHz measurement rate,
  K-weighting, two-stage gating, 4×-or-more true-peak oversampling).
* Honest: silence is `-inf`, unmeasurable LRA is `NaN` — no fake `0.0`.
* Small: two hard dependencies, ~400 lines, no audio I/O, no UI.

## References

* ITU-R BS.1770-4 — *Algorithms to measure audio programme loudness and
  true-peak audio level*
* EBU Tech 3341 / R128 — *Loudness normalisation and permitted maximum level*

## License

MIT
