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

tuner-core

v2026.4.2

Published

Pitch detection (YIN, pYIN, MPM, autocorrelation) and tuner session types for instrument apps — ESM-only, Node 20+.

Readme

tuner-core

Pitch detection (YIN, pYIN / HMM, MPM / McLeod, autocorrelation) and a small tuner session API (smoothing, confidence gating, note / cents, tunings registry). Made for browsers, Node, or native shells by injecting an AudioProvider.

Requirements

  • Node.js 20+
  • ESM only (import, not require). CommonJS callers must use dynamic import().

Install

npm install tuner-core

Why several detectors?

Different algorithms trade off latency, stability, CPU cost, and robustness to noise, vibrato, and false subharmonics. Shipping multiple implementations lets you benchmark under real rooms and instruments, A/B in your UI, and fall back when one misbehaves on a given platform.

YIN is the default in DEFAULT_TUNER_SETTINGS**: a direct **cumulative mean normalized difference (CMND)** detector with **yinThreshold`** as the main knob. Predictive YIN (pYIN) uses the same observations with a small HMM for a steadier monophonic track—pick it when that trade-off suits your app. MPM and autocorrelation stay in the box for comparison and platform-specific behavior.

Using TunerSession and reading results

You bring an AudioProvider (mic / AudioWorklet / native capture): it exposes sample rate, registers a frame callback, and implements start() / stop(). TunerSession wires that stream to a PitchDetector, applies median smoothing and confidence gating, then emits TunerResult on each analyzed frame.

import {
  TunerSession,
  createPitchDetector,
  mergeTunerSettings,
  findTuning,
  type AudioProvider,
  type TunerResult,
} from 'tuner-core'

const settings = mergeTunerSettings({
  pitchDetector: 'yin', // or 'pyin' | 'mpm' | 'autocorrelation'
  medianWindowSize: 7,
  minConfidence: 0.28,
})

const audio: AudioProvider = {
  /* your implementation: getSampleRate, onFrame, start, stop */
}
const detector = createPitchDetector(settings)
const session = new TunerSession(audio, detector, settings)

// Optional: guitar / bass context for string dots and in-tune hints
const tuning = findTuning('guitar', 'guitar-standard')
session.setTuning(tuning ?? null)
session.applyPreferences({ centsThreshold: 5 })

session.on('started', () => {
  console.log('capture started')
})
session.on('stopped', () => {
  console.log('capture stopped')
})
session.on('error', (err) => {
  console.error(err.message)
})

session.on('result', (r: TunerResult) => {
  // Smoothed display pitch (Hz); may hold last confident value if current frame is weak
  console.log(r.frequency)

  // Nearest chromatic note
  console.log(r.note, r.octave) // e.g. "A", 4

  // Cents from that semitone (-50 … +50 after rounding in core helpers)
  console.log(r.cents)

  // If setTuning() was used: nearest string, how far in cents, and in-tune vs prefs
  if (r.closestString) {
    console.log(
      r.closestString.name,
      r.closestString.centsOff,
      r.closestString.inTune,
    )
  }

  // Copy of open strings for UI pills / labels, or null if no tuning selected
  console.log(r.tuningStrings)
})

await session.start()
// … later …
session.stop()

Each result event is one synthesis of the pipeline: raw detector output → median window → confidence gate (hold last good pitch when unsure) → MIDI / note / cents / optional string math.

More

Source and CLI: github.com/mducharme/Tuner.

Publish (maintainers)

From the monorepo root (with a clean build and tests green):

pnpm --filter tuner-core build
pnpm --filter tuner-core run package:assert
pnpm --filter tuner-core publish --access public

Prefer npm provenance via GitHub Actions (see .github/workflows/publish.yml) and trusted publishers.

prepublishOnly runs tsc, publint --strict, and Are The Types Wrong? (attw --pack . --profile esm-only).

License

MIT — see LICENSE.