IEC 61672-1 Sound Level Meter
Project description
soundlevelmeter
An IEC 61672-1 compliant Sound Level Meter (SLM) in Python. Measures LAeq, LCeq, LZeq, LASmax, LAFmax, octave-band levels (1/1, 1/3, 1/6, …), sound exposure levels (LE), and more — from WAV files or a live microphone.
Installation
git clone https://github.com/ninoblumer/python-soundlevelmeter
cd python-soundlevelmeter
python -m venv venv
source venv/bin/activate # macOS / Linux
# venv\Scripts\activate # Windows
pip install -r requirements.txt
To use slm as a shell command instead, you can install this tool directly. For example with pip install --user git+https://github.com/ninoblumer/python-soundlevelmeter.git@main
Usage
One-shot measurement from a WAV file
python -m slm --file recording.wav --fs-db 128.1 --measure LAeq LAFmax LCeq LZeq:bands:63-8000
Results are written to output/measurement_report.csv (broadband) and
output/measurement_rta_report.csv (per-band). Use --output to change the path prefix and
--dt to set the logging interval (default 1 s).
Using a TOML config file
python -m slm --file recording.wav --config config.toml --fs-db 128.1
# config.toml
[measurement]
dt = 1.0
output = "output/my_measurement"
[metrics]
require = [
"LAeq",
"LAFmax",
"LCSmax",
"LAeq_dt",
"LAFmax_dt",
"LZeq:bands:63-8000",
"LAeq:bands:1/3:31-16000",
]
Interactive REPL
python -m slm
The REPL lets you load files, set sensitivity, add metrics, and start/stop measurements
interactively. Type help for a list of commands.
Real-time input (requires PortAudio)
python -m slm --list-devices
python -m slm --device 0 --sensitivity-mv 50 --measure LAeq LAFmax --dt 1.0
Metric name syntax
L[ACZ][FSI?](eq|max|min|E)?[_(dt|Ns|Nm|Nh)][:bands:[N/M:]fmin-fmax]
Frequency weighting
| Letter | Weighting |
|---|---|
A |
A-weighting (IEC 61672-1) |
C |
C-weighting (IEC 61672-1) |
Z |
Z-weighting — flat passthrough (IEC 61672-1 Annex E.5) |
Time weighting (required for max/min and bare metrics; forbidden for eq/E)
| Letter | Filter |
|---|---|
F |
Fast (τ = 0.125 s) |
S |
Slow (τ = 1 s) |
I |
Impulse |
Measure
| Suffix | Description |
|---|---|
eq |
Energy-equivalent level (Leq) — no time-weighting letter |
max |
Maximum — requires time-weighting letter |
min |
Minimum — requires time-weighting letter |
E |
Sound exposure level (LE) — no time-weighting letter |
| (none) | Most-recent time-weighted sample — requires time-weighting letter, no window |
Window suffix (optional)
| Suffix | Description |
|---|---|
| (none) | Accumulating over the whole file/stream |
_dt |
Moving window equal to the engine's logging interval |
_Ns |
Moving N-second window (e.g. _5s, _30s) |
_Nm |
Moving N-minute window (e.g. _1m) |
_Nh |
Moving N-hour window (e.g. _1h) |
Band suffix (optional)
| Suffix | Description |
|---|---|
:bands:63-8000 |
1/1-octave bands, 63 Hz to 8 kHz |
:bands:1/3:31-16000 |
1/3-octave bands, 31 Hz to 16 kHz |
:bands:1/6:63-8000 |
1/6-octave bands, 63 Hz to 8 kHz |
:bands:N/M:fmin-fmax |
Any N/M-octave filter bank (M/N bands per octave) |
Omitting the N/M: fraction defaults to 1/1-octave.
Examples
LAeq # A-weighted Leq, accumulating
LAFmax # A-weighted fast-time max, accumulating
LAFmax_dt # A-weighted fast-time max, moving (dt window)
LZeq_30s # Z-weighted Leq, 30-second moving window
LAF # A-weighted fast-time instantaneous sample
LAE # A-weighted sound exposure level
LZeq:bands:63-8000 # Z-weighted 1/1-octave Leq, 63–8000 Hz
LAeq:bands:1/3:31-16000 # A-weighted 1/3-octave Leq, 31–16000 Hz
Calibration
Derive the controller sensitivity from a recording of a known-level calibrator tone:
python -m slm --calibrate --file cal.wav --cal-level 94.0 --cal-freq 1000.0
A 1/3-octave bandpass filter is applied around --cal-freq before the RMS is computed, so
harmonics and background noise do not corrupt the estimate.
Controller sensitivity vs microphone sensitivity
The value returned by --calibrate is the controller sensitivity (V/Pa) — the factor
that converts raw WAV float samples into Pascal. It is not the same as the physical
microphone sensitivity on a datasheet.
For WAV files recorded by a hardware SLM (e.g. NTi XL2), the FS annotation in the filename
(e.g. FS128.1dB(PK)) encodes the entire recording chain. The controller sensitivity
collapses it to a single number:
controller_sensitivity = 1 / (P_ref × 10^(FS_dB / 20))
Pass this via --fs-db 128.1 or --sensitivity-dbv/--sensitivity-mv on the CLI, or
sensitivity_from_fs_db() in the Python API.
Architecture
Controller (FileController | SounddeviceController)
│ reads audio blocks
▼
Engine
│ routes blocks to each Bus, samples meters every dt seconds
├─► Bus(A) ──► PluginAWeighting ──► [plugins…] ──► [meters…]
├─► Bus(C) ──► PluginCWeighting ──► [plugins…] ──► [meters…]
└─► Bus(Z) ──► PluginZWeighting ──► [plugins…] ──► [meters…]
│
Reporter ◄─────────────────────────────────────────────────┘
│ writes CSV output files
Key components:
Engine— main processing loop; owns buses; callsreporter.record()everydtsecondsBus— one frequency weighting + a chain of downstream plugins and metersPluginAWeighting/PluginCWeighting/PluginZWeighting— IIR frequency-weighting filtersPluginFastTimeWeighting/PluginSlowTimeWeighting— exponential time-weighting filtersPluginOctaveBand— arbitrary N/M-octave filter bank; outputs N channelsLeqAccumulator/MaxAccumulator— whole-file/stream integrating metersLeqMovingMeter/MaxMovingMeter— sliding-window metersReporter— collects meter readings and writes CSV output
build_chain() in slm/assembly.py constructs and wires up the above components from a list
of metric name strings, reusing shared buses and plugins where possible.
Python API
High-level
from slm.app import run_measurement, calibrate_from_file, SLMConfig, sensitivity_from_fs_db
sens = calibrate_from_file("cal.wav", cal_level=94.0, cal_freq=1000.0)
config = SLMConfig.from_toml("config.toml")
run_measurement("recording.wav", sens, config, print_to_console=True)
Mid-level (declarative)
from slm import Engine, build_chain, parse_metric
from slm.io import FileController
controller = FileController("recording.wav", blocksize=1024)
controller.set_sensitivity(sens, unit="V")
engine = Engine(controller, dt=1.0)
specs = [parse_metric(m) for m in ["LAeq", "LAFmax", "LZeq:bands:63-8000"]]
build_chain(specs, engine)
engine.run()
engine.reporter.write("output/measurement")
Low-level (manual)
from slm import Engine
from slm.io import FileController
from slm.frequency_weighting import PluginAWeighting
from slm.time_weighting import PluginFastTimeWeighting
from slm.meter import LeqAccumulator, MaxAccumulator
controller = FileController("recording.wav", blocksize=1024)
controller.set_sensitivity(sens, unit="V")
engine = Engine(controller, dt=1.0)
bus_a = engine.add_bus("A", PluginAWeighting)
la = bus_a.frequency_weighting
laf = bus_a.add_plugin(PluginFastTimeWeighting(input=la))
laf.create_meter(LeqAccumulator, name="LAeq")
laf.create_meter(MaxAccumulator, name="LAFmax")
engine.reporter.add_column("LAeq", laf, "LAeq")
engine.reporter.add_column("LAFmax", laf, "LAFmax")
engine.run()
engine.reporter.write("output/measurement")
License
This project is licensed under the GNU General Public License v3.0.
See LICENSE for full details and NOTICE for third-party attributions.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file soundlevelmeter-0.2.0.tar.gz.
File metadata
- Download URL: soundlevelmeter-0.2.0.tar.gz
- Upload date:
- Size: 75.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
01bb27aa111c09b26f00be0e15706daa1ef14d1c8ad16a68c6493b72c9a14202
|
|
| MD5 |
0fb1d9f88e13afd76c62c861ca87ff1e
|
|
| BLAKE2b-256 |
9e7996135f17907f910463e4fd8b1699dce3df62e54005721b578d4a35497ddb
|
Provenance
The following attestation bundles were made for soundlevelmeter-0.2.0.tar.gz:
Publisher:
pypi-publish.yml on ninoblumer/python-soundlevelmeter
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
soundlevelmeter-0.2.0.tar.gz -
Subject digest:
01bb27aa111c09b26f00be0e15706daa1ef14d1c8ad16a68c6493b72c9a14202 - Sigstore transparency entry: 1185984189
- Sigstore integration time:
-
Permalink:
ninoblumer/python-soundlevelmeter@0f125d127788e877fa1897394149b42db4bf99ab -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/ninoblumer
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yml@0f125d127788e877fa1897394149b42db4bf99ab -
Trigger Event:
release
-
Statement type:
File details
Details for the file soundlevelmeter-0.2.0-py3-none-any.whl.
File metadata
- Download URL: soundlevelmeter-0.2.0-py3-none-any.whl
- Upload date:
- Size: 69.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b9f940b39b4f8a05b1ef8d5c988400b68046b5c024d2a9494bc836c276f3ed67
|
|
| MD5 |
2a729ef984c6a438bf063fc6f07024b9
|
|
| BLAKE2b-256 |
3779c3ee0f48ef782bd63606739326ed8f569cba6dc9eb60f86b34c0bf70e03b
|
Provenance
The following attestation bundles were made for soundlevelmeter-0.2.0-py3-none-any.whl:
Publisher:
pypi-publish.yml on ninoblumer/python-soundlevelmeter
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
soundlevelmeter-0.2.0-py3-none-any.whl -
Subject digest:
b9f940b39b4f8a05b1ef8d5c988400b68046b5c024d2a9494bc836c276f3ed67 - Sigstore transparency entry: 1185984210
- Sigstore integration time:
-
Permalink:
ninoblumer/python-soundlevelmeter@0f125d127788e877fa1897394149b42db4bf99ab -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/ninoblumer
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
pypi-publish.yml@0f125d127788e877fa1897394149b42db4bf99ab -
Trigger Event:
release
-
Statement type: