Skip to main content

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; calls reporter.record() every dt seconds
  • Bus — one frequency weighting + a chain of downstream plugins and meters
  • PluginAWeighting / PluginCWeighting / PluginZWeighting — IIR frequency-weighting filters
  • PluginFastTimeWeighting / PluginSlowTimeWeighting — exponential time-weighting filters
  • PluginOctaveBand — arbitrary N/M-octave filter bank; outputs N channels
  • LeqAccumulator / MaxAccumulator — whole-file/stream integrating meters
  • LeqMovingMeter / MaxMovingMeter — sliding-window meters
  • Reporter — 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

soundlevelmeter-0.2.0.tar.gz (75.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

soundlevelmeter-0.2.0-py3-none-any.whl (69.1 kB view details)

Uploaded Python 3

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

Hashes for soundlevelmeter-0.2.0.tar.gz
Algorithm Hash digest
SHA256 01bb27aa111c09b26f00be0e15706daa1ef14d1c8ad16a68c6493b72c9a14202
MD5 0fb1d9f88e13afd76c62c861ca87ff1e
BLAKE2b-256 9e7996135f17907f910463e4fd8b1699dce3df62e54005721b578d4a35497ddb

See more details on using hashes here.

Provenance

The following attestation bundles were made for soundlevelmeter-0.2.0.tar.gz:

Publisher: pypi-publish.yml on ninoblumer/python-soundlevelmeter

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file soundlevelmeter-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for soundlevelmeter-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b9f940b39b4f8a05b1ef8d5c988400b68046b5c024d2a9494bc836c276f3ed67
MD5 2a729ef984c6a438bf063fc6f07024b9
BLAKE2b-256 3779c3ee0f48ef782bd63606739326ed8f569cba6dc9eb60f86b34c0bf70e03b

See more details on using hashes here.

Provenance

The following attestation bundles were made for soundlevelmeter-0.2.0-py3-none-any.whl:

Publisher: pypi-publish.yml on ninoblumer/python-soundlevelmeter

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page