npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

loudness-worklet

v1.6.7

Published

A lightweight and efficient AudioWorklet for real-time loudness measurement in the browser, compliant with the ITU-R BS.1770-5 standard.

Downloads

687

Readme

Loudness Worklet

npm version license demo

A loudness meter for the Web Audio API, based on the ITU-R BS.1770-5 standard and implemented as an AudioWorkletProcessor.

screenshot

Features

  • Standard Compliant: Strictly follows ITU-R BS.1770-5 for accurate loudness measurement.
  • Comprehensive Metrics: Calculates Momentary, Short-term, and Integrated Loudness, plus Loudness Range (LRA) and True-Peak levels.
  • Versatile Input: Seamlessly supports both live audio streams ("Microphone/WebRTC") and offline file analysis.
  • Zero Dependencies: Lightweight, pure AudioWorklet implementation requiring no external libraries.

Installation

CDN

Import directly in your code:

const moduleUrl = "https://lcweden.github.io/loudness-worklet/loudness.worklet.js";
await audioContext.audioWorklet.addModule(moduleUrl);
const worklet = new AudioWorkletNode(audioContext, "loudness-processor");

Download

  1. Download the pre-built file: loudness.worklet.js.
  2. Place loudness.worklet.js in your project directory (e.g., /public/).
await audioContext.audioWorklet.addModule("loudness.worklet.js");
const worklet = new AudioWorkletNode(audioContext, "loudness-processor");

NPM

Install via npm:

npm install loudness-worklet

Use helper functions to create and load the worklet:

import { createLoudnessWorklet } from "loudness-worklet";

const worklet = await createLoudnessWorklet(audioContext);

or

import { LoudnessWorkletNode } from "loudness-worklet";

await LoudnessWorkletNode.loadModule(audioContext);
const worklet = new LoudnessWorkletNode(audioContext);

Quick Start

Example

This example shows the easiest way to get started with the loudness-worklet by measuring the loudness of a screen share stream with audio (e.g., a YouTube tab).

<!DOCTYPE html>
<html>
  <body>
    <button>Share Screen</button>
    <pre></pre>
    <script>
      const moduleUrl = "https://lcweden.github.io/loudness-worklet/loudness.worklet.js";
      const button = document.querySelector("button");
      const pre = document.querySelector("pre");

      button.onclick = async () => {
        // Get the display media stream with audio
        const mediaStream = await navigator.mediaDevices.getDisplayMedia({ audio: true });
        const context = new AudioContext();

        // Load the loudness worklet processor
        await context.audioWorklet.addModule(moduleUrl);

        // Create the audio node from the stream
        const source = new MediaStreamAudioSourceNode(context, { mediaStream });
        // Create the loudness worklet node
        const worklet = new AudioWorkletNode(context, "loudness-processor", {
          processorOptions: {
            interval: 0.02, // every 0.02s a message will be sent
            capacity: 600 // 1 minute of history can be stored
          }
        });

        worklet.port.onmessage = (event) => {
          pre.textContent = JSON.stringify(event.data, null, 2);
        };

        // Connect the nodes
        source.connect(worklet);
      };
    </script>
  </body>
</html>

File-based measurement

You can measure the loudness of audio files using OfflineAudioContext.

import { LoudnessWorkletNode } from "loudness-worklet";

const input = document.querySelector("input");

input.addEventListener("change", async (event) => {
  const file = event.target.files[0];
  const arrayBuffer = await file.arrayBuffer();
  const audioBuffer = await new AudioContext().decodeAudioData(arrayBuffer);
  const { numberOfChannels, length, sampleRate } = audioBuffer;
  const context = new OfflineAudioContext(numberOfChannels, length, sampleRate);

  await LoudnessWorkletNode.loadModule(context);

  const source = new AudioBufferSourceNode(context, { buffer: audioBuffer });
  const worklet = new LoudnessWorkletNode(context);

  worklet.port.onmessage = (event) => console.log("Loudness Data:", event.data);

  source.connect(worklet).connect(context.destination);
  source.start();

  await context.startRendering();
});

Live-based measurement

Supports all kinds of audio input.

import { createLoudnessWorklet } from "loudness-worklet";

const mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true });
const context = new AudioContext({ sampleRate: 48000 });
const source = context.createMediaStreamSource(mediaStream);
const worklet = await createLoudnessWorklet(context, {
  processorOptions: { interval: 1, capacity: 600 }
});

worklet.port.onmessage = (event) => console.log("Loudness Data:", event.data);
source.connect(worklet);

// worklet.connect(context.destination);
// Optionally connect to destination for monitoring (echo)

Concepts

Contexts

Provide the execution environment for audio processing.

AudioContext

AudioContext is used for real-time audio processing, such as live audio input from a microphone or media stream.

OfflineAudioContext

OfflineAudioContext is used for processing audio data offline, allowing for rendering and analysis without requiring real-time playback.

Nodes

Nodes are the building blocks of an audio graph, representing audio sources, processing modules, and destinations. The following nodes are commonly used as a source input:

AudioBufferSourceNode

AudioBufferSourceNode is used to play audio data stored in an AudioBuffer, typically for pre-recorded audio files.

const arrayBuffer = await file.arrayBuffer();
const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
const bufferSource = new AudioBufferSourceNode(audioContext, { buffer: audioBuffer });

MediaStreamAudioSourceNode

MediaStreamAudioSourceNode is used to play audio from a MediaStream, such as a live microphone input or a video element.

const mediaStream = await navigator.mediaDevices.getUserMedia({ audio: true });
const mediaStreamSource = new MediaStreamAudioSourceNode(audioContext, { mediaStream });

MediaElementAudioSourceNode

MediaElementAudioSourceNode is used to play audio from an HTML <audio> or <video> element.

const mediaElement = document.querySelector("audio");
const elementSource = new MediaElementAudioSourceNode(audioContext, { mediaElement });

API

Options

The AudioWorkletNode constructor accepts the following options:

Params

| Option | Type | Required | Default | Description | | ------------------------- | ---------- | -------- | ------- | ---------------------------------------------------------------------------------------------------- | | processorOptions.interval | number | No | 0.02 | Message interval in seconds. | | processorOptions.capacity | number | No | 0 | Maximum seconds of history to keep. If set to 0, the processor will not limit the history size. |

Example

Most of the time, you only need to set processorOptions or leave it empty.

const { numberOfChannels, length, sampleRate } = audioBuffer;
const worklet = new AudioWorkletNode(context, "loudness-processor", {
  processorOptions: {
    capacity: length / sampleRate,
    interval: 0.02
  }
});

Message Format

Measurement results are sent back to the main thread via port.onmessage as a LoudnessSnapshot object:

type LoudnessMeasurements = {
  momentaryLoudness: number;
  shortTermLoudness: number;
  integratedLoudness: number;
  maximumMomentaryLoudness: number;
  maximumShortTermLoudness: number;
  maximumTruePeakLevel: number;
  loudnessRange: number;
};

type LoudnessSnapshot = {
  currentFrame: number;
  currentTime: number;
  currentMeasurements: LoudnessMeasurements[];
};

Details

Units

| Metric | Unit | | -------------------------- | ------------- | | momentaryLoudness | LUFS/LKFS | | shortTermLoudness | LUFS/LKFS | | integratedLoudness | LUFS/LKFS | | maximumMomentaryLoudness | LUFS/LKFS | | maximumShortTermLoudness | LUFS/LKFS | | maximumTruePeakLevel | dBTP | | loudnessRange | LU |

Supported Channels

Supported channel counts: 1, 2, 5, 6, 8, 10, 12, 24

[!NOTE] Channel counts not listed above are weighted at 1.0.

Coefficients

The following coefficients are used for the K-weighting filter:

| | highshelf | highpass | | --- | ----------------- | ----------------- | | a1 | -1.69065929318241 | -1.99004745483398 | | a2 | 0.73248077421585 | 0.99007225036621 | | b0 | 1.53512485958697 | 1.0 | | b1 | -2.69169618940638 | -2.0 | | b2 | 1.19839281085285 | 1.0 |

The following FIR filter coefficients are used for true-peak measurement:

| Phase 0 | Phase 1 | Phase 2 | Phase 3 | | ---------------- | ---------------- | ---------------- | ---------------- | | 0.0017089843750 | -0.0291748046875 | -0.0189208984375 | -0.0083007812500 | | 0.0109863281250 | 0.0292968750000 | 0.0330810546875 | 0.0148925781250 | | -0.0196533203125 | -0.0517578125000 | -0.0582275390625 | -0.0266113281250 | | 0.0332031250000 | 0.0891113281250 | 0.1015625000000 | 0.0476074218750 | | -0.0594482421875 | -0.1665039062500 | -0.2003173828125 | -0.1022949218750 | | 0.1373291015625 | 0.4650878906250 | 0.7797851562500 | 0.9721679687500 | | 0.9721679687500 | 0.7797851562500 | 0.4650878906250 | 0.1373291015625 | | -0.1022949218750 | -0.2003173828125 | -0.1665039062500 | -0.0594482421875 | | 0.0476074218750 | 0.1015625000000 | 0.0891113281250 | 0.0332031250000 | | -0.0266113281250 | -0.0582275390625 | -0.0517578125000 | -0.0196533203125 | | 0.0148925781250 | 0.0330810546875 | 0.0292968750000 | 0.0109863281250 | | -0.0083007812500 | -0.0189208984375 | -0.0291748046875 | 0.0017089843750 |

Validation

ITU-R BS.2217

Code correctness is verified against the official ITU-R BS.2217 compliance test suite, ensuring strict adherence to the ITU-R BS.1770 specification.

| file | measurement | channels | | | ------------------------------------ | ----------- | -------- | ------------------ | | 1770Comp_2_RelGateTest | -10.0 LKFS | 2 | :white_check_mark: | | 1770Comp_2_AbsGateTest | -69.5 LKFS | 2 | :white_check_mark: | | 1770Comp_2_24LKFS_25Hz_2ch | -24.0 LKFS | 2 | :white_check_mark: | | 1770Comp_2_24LKFS_100Hz_2ch | -24.0 LKFS | 2 | :white_check_mark: | | 1770Comp_2_24LKFS_500Hz_2ch | -24.0 LKFS | 2 | :white_check_mark: | | 1770Comp_2_24LKFS_1000Hz_2ch | -24.0 LKFS | 2 | :white_check_mark: | | 1770Comp_2_24LKFS_2000Hz_2ch | -24.0 LKFS | 2 | :white_check_mark: | | 1770Comp_2_24LKFS_10000Hz_2ch | -24.0 LKFS | 2 | :white_check_mark: | | 1770Comp_2_23LKFS_25Hz_2ch | -23.0 LKFS | 2 | :white_check_mark: | | 1770Comp_2_23LKFS_100Hz_2ch | -23.0 LKFS | 2 | :white_check_mark: | | 1770Comp_2_23LKFS_500Hz_2ch | -23.0 LKFS | 2 | :white_check_mark: | | 1770Comp_2_23LKFS_1000Hz_2ch | -23.0 LKFS | 2 | :white_check_mark: | | 1770Comp_2_23LKFS_2000Hz_2ch | -23.0 LKFS | 2 | :white_check_mark: | | 1770Comp_2_23LKFS_10000Hz_2ch | -23.0 LKFS | 2 | :white_check_mark: | | 1770Comp_2_18LKFS_FrequencySweep | -18.0 LKFS | 1 | :white_check_mark: | | 1770Comp_2_24LKFS_SummingTest | -24.0 LKFS | 6 | :white_check_mark: | | 1770Comp_2_23LKFS_SummingTest | -23.0 LKFS | 6 | :white_check_mark: | | 1770Comp_2_24LKFS_ChannelCheckLeft | -24.0 LKFS | 6 | :white_check_mark: | | 1770Comp_2_24LKFS_ChannelCheckRight | -24.0 LKFS | 6 | :white_check_mark: | | 1770Comp_2_24LKFS_ChannelCheckCentre | -24.0 LKFS | 6 | :white_check_mark: | | 1770Comp_2_24LKFS_ChannelCheckLFE | -inf LKFS | 6 | :white_check_mark: | | 1770Comp_2_24LKFS_ChannelCheckLs | -24.0 LKFS | 6 | :white_check_mark: | | 1770Comp_2_24LKFS_ChannelCheckRs | -24.0 LKFS | 6 | :white_check_mark: | | 1770Comp_2_23LKFS_ChannelCheckLeft | -23.0 LKFS | 6 | :white_check_mark: | | 1770Comp_2_23LKFS_ChannelCheckRight | -23.0 LKFS | 6 | :white_check_mark: | | 1770Comp_2_23LFKS_ChannelCheckCentre | -23.0 LKFS | 6 | :white_check_mark: | | 1770Comp_2_23LKFS_ChannelCheckLFE | -inf LKFS | 6 | :white_check_mark: | | 1770Comp_2_23LKFS_ChannelCheckLs | -23.0 LKFS | 6 | :white_check_mark: | | 1770Comp_2_23LKFS_ChannelCheckRs | -23.0 LKFS | 6 | :white_check_mark: | | 1770-2 Conf 6ch VinCntr-24LKFS | -24.0 LKFS | 6 | :white_check_mark: | | 1770-2 Conf 6ch VinL+R-24LKFS | -24.0 LKFS | 6 | :white_check_mark: | | 1770-2 Conf 6ch VinL-R-C-24LKFS | -24.0 LKFS | 6 | :white_check_mark: | | 1770-2 Conf Stereo VinL+R-24LKFS | -24.0 LKFS | 2 | :white_check_mark: | | 1770-2 Conf Mono Voice+Music-24LKFS | -24.0 LKFS | 1 | :white_check_mark: | | 1770-2 Conf 6ch VinCntr-23LKFS | -23.0 LKFS | 6 | :white_check_mark: | | 1770-2 Conf 6ch VinL+R-23LKFS | -23.0 LKFS | 6 | :white_check_mark: | | 1770-2 Conf 6ch VinL-R-C-23LKFS | -23.0 LKFS | 6 | :white_check_mark: | | 1770-2 Conf Stereo VinL+R-23LKFS | -23.0 LKFS | 2 | :white_check_mark: | | 1770-2 Conf Mono Voice+Music-23LKFS | -23.0 LKFS | 1 | :white_check_mark: | | 1770Conf-8channels_24LKFS | -24.0 LKFS | 8 | :white_check_mark: | | 1770Conf-8channels_23LKFS | -23.0 LKFS | 8 | :white_check_mark: | | 1770Conf-10channels_24LKFS | -24.0 LKFS | 10 | :white_check_mark: | | 1770Conf-10channels_23LKFS | -23.0 LKFS | 10 | :white_check_mark: | | 1770Conf-12channels_24LKFS | -24.0 LKFS | 12 | :white_check_mark: | | 1770Conf-12channels_23LKFS | -23.0 LKFS | 12 | :white_check_mark: | | 1770Conf-24channels_24LKFS | -24.0 LKFS | 24 | :white_check_mark: | | 1770Conf-24channels_23LKFS | -23.0 LKFS | 24 | :white_check_mark: |

[!TIP] If decodeAudioData fails, it's often due to the browser's specific support for the audio file's format (codec), container, or channel layout, rather than a general API incompatibility. Try a different browser or convert the audio file to a more widely supported format. For example, Chrome has limited support for certain codecs in audio files, while Safari offers broader support. (1770Conf-24channels_24LKFS)

EBU TECH 3341 Minimum requirements test signals

Validated against EBU TECH 3341 minimum requirements for loudness metering, including gating behavior, time scales, and true-peak accuracy.

| file | expected response and accepted tolerances | | | ------------------------------------ | ----------------------------------------------------------- | ------------------ | | seq-3341-1-16bit | M, S, I = -23.0 ±0.1 LUFS | :white_check_mark: | | seq-3341-2-16bit | M, S, I = -33.0 ±0.1 LUFS | :white_check_mark: | | seq-3341-3-16bit-v02 | I = -23.0 ±0.1 LUFS | :white_check_mark: | | seq-3341-4-16bit-v02 | I = -23.0 ±0.1 LUFS | :white_check_mark: | | seq-3341-5-16bit-v02 | I = -23.0 ±0.1 LUFS | :white_check_mark: | | seq-3341-6-5channels-16bit | I = -23.0 ±0.1 LUFS | :white_check_mark: | | seq-3341-6-6channels-WAVEEX-16bit | I = -23.0 ±0.1 LUFS | :white_check_mark: | | seq-3341-7_seq-3342-5-24bit | I = -23.0 ±0.1 LUFS | :white_check_mark: | | seq-3341-2011-8_seq-3342-6-24bit-v02 | I = -23.0 ±0.1 LUFS | :white_check_mark: | | seq-3341-9-24bit | S = -23.0 ±0.1 LUFS, constant after 3 s | :white_check_mark: | | seq-3341-10-*-24bit | Max S = -23.0 ±0.1 LUFS, for each segment | :white_check_mark: | | seq-3341-11-24bit | Max S = -38.0, -37.0, …, -19.0 ±0.1 LUFS, successive values | :white_check_mark: | | seq-3341-12-24bit | M = -23.0 ±0.1 LUFS, constant after 1 s | :white_check_mark: | | seq-3341-13-*-24bit | Max M = -23.0 ±0.1 LUFS, for each segment | :white_check_mark: | | seq-3341-14-24bit | Max M = -38.0, …, -19.0 ±0.1 LUFS, successive values | :white_check_mark: | | seq-3341-15-24bit | Max true-peak = -6.0 +0.2/-0.4 dBTP | :white_check_mark: | | seq-3341-16-24bit | Max true-peak = -6.0 +0.2/-0.4 dBTP | :white_check_mark: | | seq-3341-17-24bit | Max true-peak = -6.0 +0.2/-0.4 dBTP | :white_check_mark: | | seq-3341-18-24bit | Max true-peak = -6.0 +0.2/-0.4 dBTP | :white_check_mark: | | seq-3341-19-24bit | Max true-peak = +3.0 +0.2/-0.4 dBTP | :white_check_mark: | | seq-3341-20-24bit | Max true-peak = 0.0 +0.2/-0.4 dBTP | :white_check_mark: | | seq-3341-21-24bit | Max true-peak = 0.0 +0.2/-0.4 dBTP | :white_check_mark: | | seq-3341-22-24bit | Max true-peak = 0.0 +0.2/-0.4 dBTP | :white_check_mark: | | seq-3341-23-24bit | Max true-peak = 0.0 +0.2/-0.4 dBTP | :white_check_mark: |

EBU TECH 3342 Minimum requirements test signals

EBU TECH 3342 focuses on the measurement of loudness range.

| file | expected response and accepted tolerances | | | ------------------------------------ | ----------------------------------------- | ------------------ | | seq-3342-1-16bit | LRA = 10 ±1 LU | :white_check_mark: | | seq-3342-2-16bit | LRA = 5 ±1 LU | :white_check_mark: | | seq-3342-3-16bit | LRA = 20 ±1 LU | :white_check_mark: | | seq-3342-4-16bit | LRA = 15 ±1 LU | :white_check_mark: | | seq-3341-7_seq-3342-5-24bit | LRA = 5 ±1 LU | :white_check_mark: | | seq-3341-2011-8_seq-3342-6-24bit-v02 | LRA = 15 ±1 LU | :white_check_mark: |

Acknowledgments

This project is a learning experiment aimed at exploring audio signal processing and ITU-R BS.1770 loudness measurement standards. I am not an expert in audio engineering or signal processing, and this project was developed as a way to better understand the concepts of audio loudness and implementation techniques. Thanks to the ITU-R BS.1770 standards for providing the theoretical basis for loudness measurement.

License

This project is licensed under the MIT License.

References