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

expo-audio-waveform

v0.1.0

Published

Offline audio waveform (peak amplitude) extraction for Expo & React Native. Decodes local or remote audio files natively — no playback — into a normalized 0..1 peak array for drawing waveforms.

Readme

expo-audio-waveform

Offline audio waveform (peak amplitude) extraction for Expo & React Native.

Decodes an audio file natively and offline — no playback, no audio session, no interference with anything else that's playing — and returns a normalized 0..1 array of peak amplitudes you can render as a waveform.

  • 🎧 iOSAVAssetReader (AVFoundation)
  • 🤖 AndroidMediaExtractor + MediaCodec
  • 🌐 Web — Web Audio decodeAudioData
  • 🔗 Works with local and remote URIs (file://, bare paths, content:// on Android, and http(s)://)
  • 🧱 New Architecture (Fabric/bridgeless) compatible — built on the Expo Modules API
  • 📦 Zero third-party native dependencies (platform decoders only)

Built for the common "waveform behind a scrubber" UI where the old trick of playing audio at 16× to sample it no longer works (expo-audio caps playback at 2×). This decodes the file directly instead — faster than realtime and silent.

Installation

npx expo install expo-audio-waveform

Then rebuild the native app (this is a native module — it does not run in Expo Go):

npx expo prebuild
npx expo run:ios      # or run:android

No config plugin is required. On Android, decoding a remote URL needs the INTERNET permission, which the module declares and most apps already have.

Usage

import { extractWaveform } from "expo-audio-waveform";

// Returns number[] of length `samples`, each value 0..1 (peak of that segment
// relative to the loudest segment). Accepts local or remote URIs.
const bars = await extractWaveform(audioUrl, { samples: 64 });

// Analyze only a sub-range (milliseconds):
const chorus = await extractWaveform(audioUrl, {
  samples: 64,
  startMs: 30_000,
  endMs: 45_000,
});

API

function extractWaveform(
  uri: string,
  options?: {
    samples?: number;          // number of bars / array length (default 64)
    startMs?: number;          // window start in ms (default 0)
    endMs?: number;            // window end in ms (default: end of file)
    metric?: "rms" | "peak";   // amplitude metric (default "rms")
  },
): Promise<number[]>;

Returns a promise resolving to an array of exactly samples numbers in the range 0..1. Pure silence yields all zeros.

Throws if the URI can't be read, has no audio track, or has an unknown / open-ended duration (e.g. a live stream). Wrap the call and fall back to a placeholder waveform if you need to render something regardless:

let bars: number[];
try {
  bars = await extractWaveform(uri, { samples: 64 });
} catch {
  bars = myPlaceholderBars; // deterministic fallback
}

Notes & limitations

  • Supported formats follow the OS decoders — MP3, AAC/M4A, WAV, FLAC, and more on both iOS and Android. Anything the platform can't decode will throw.
  • metric: rms (default) vs peak. rms is root-mean-square energy per slice — it tracks perceived loudness, so even loud/compressed tracks keep a varied, natural waveform shape. peak takes the maximum absolute sample per slice; it's punchier but saturates toward 1.0 on mastered music, flattening the shape. Use rms for visualizations; peak when you specifically want transient peaks.
  • Amplitudes are normalized to the loudest bar in the requested window, so a quiet track still fills the display. Compare bars within one result, not across different files.
  • Duration required. Bucketing is done by timestamp, so the source must report a finite duration. Regular files (local or CDN) always do.
  • Use https:// for remote audio. On Android 9+, cleartext http:// is blocked by default; the consuming app must opt in via usesCleartextTraffic / a network-security config for plain HTTP to work. On iOS, remote sources are downloaded to a temp file before decoding.

How it works

Each platform decoder is asked for linear PCM. As decoded frames stream in, the module walks them once, reducing each time-bucket (samples buckets spread evenly across the requested window) to a single value — RMS energy or peak, per metric — then normalizes the buckets to 0..1. Nothing is ever played back, and the whole file is never held in memory at once — only the running per-bucket accumulators.

License

MIT © Yusuf Emirhan Şahin