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

js-beat-emitter

v2.2.0

Published

A JavaScript/TypeScript library for beat detection and rhythm analysis with timer-based and audio-analysis modes

Readme

JS Beat Emitter

npm version License: MIT

English | 中文文档

A high-performance JavaScript/TypeScript library for beat detection and rhythm analysis. Supports both timer-based and audio-analysis modes with configurable beats per measure.

Features

  • 🎵 Dual Mode Support: Timer-based and audio-analysis modes
  • 🎼 Beat Counting: Configurable beats per measure (2/4, 3/4, 4/4, 6/8, 8/8, etc.)
  • 🎯 High Performance: Optimized with tseep-based event system
  • 🌐 Cross Platform: Works in both Node.js and browsers
  • 📊 Real-time Analysis: Live BPM detection and tempo tracking
  • 🔧 TypeScript Support: Full type definitions included
  • 🎨 Audio Integration: Complete audio examples with accent/beat distinction

Installation

npm install js-beat-emitter

Quick Start

Timer-Based Mode (Metronome)

import { BeatEmitter } from 'js-beat-emitter';

const beatEmitter = new BeatEmitter({
  mode: 'timer-based',
  bpm: 120,
  beatsPerMeasure: 4,
  intensity: 0.8
});

beatEmitter.on('beat', (beatData) => {
  const isAccent = beatData.beat === 1; // First beat is accent
  console.log(`Beat ${beatData.beat}/${beatData.totalBeats}`, isAccent ? '(ACCENT)' : '');
});

beatEmitter.start();

Audio Analysis Mode

const beatEmitter = new BeatEmitter({
  mode: 'audio-analysis',
  beatsPerMeasure: 4,
  threshold: 0.1,
  minBpm: 60,
  maxBpm: 180
});

beatEmitter.on('beat', (beatData) => {
  console.log(`Detected beat: ${beatData.beat}/${beatData.totalBeats}, BPM: ${beatData.bpm}`);
});

beatEmitter.on('tempo', (tempoData) => {
  console.log(`Tempo: ${tempoData.bpm} BPM (confidence: ${tempoData.confidence})`);
});

await beatEmitter.start(); // Requires microphone permission

API Reference

Constructor Options

interface BeatEmitterOptions {
  mode: 'timer-based' | 'audio-analysis';
  beatsPerMeasure?: number;  // Default: 4
  
  // Timer-based mode options
  bpm?: number;              // Default: 120
  intensity?: number;        // Default: 0.8 (0-1)
  
  // Audio-analysis mode options
  threshold?: number;        // Default: 0.1 (0-1)
  minBpm?: number;          // Default: 60
  maxBpm?: number;          // Default: 180
}

Methods

| Method | Description | |--------|-------------| | start() | Start beat detection | | stop() | Stop beat detection | | setBPM(bpm: number) | Set BPM (timer mode only) | | setBeatsPerMeasure(beats: number) | Set beats per measure | | getBeatsPerMeasure() | Get current beats per measure | | getCurrentBeat() | Get current beat position (1-based) | | resetToFirstBeat() | Reset to first beat | | updateOptions(options) | Update configuration | | isActive() | Check if currently running | | getMode() | Get current mode |

Events

| Event | Data Type | Description | |-------|-----------|-------------| | beat | BeatData | Triggered on each beat | | tempo | TempoData | Triggered on tempo changes | | started | void | Triggered when started | | stopped | void | Triggered when stopped | | error | Error | Triggered on errors |

Data Types

interface BeatData {
  timestamp: number;    // Timestamp
  intensity: number;    // Intensity (0-1)
  bpm?: number;        // BPM (if available)
  beat: number;        // Current beat position (1-based)
  totalBeats: number;  // Total beats per measure
}

interface TempoData {
  bpm: number;         // Beats per minute
  confidence: number;  // Confidence level (0-1)
  timestamp: number;   // Timestamp
}

Audio Integration

The library itself doesn't include audio playback, but provides complete audio integration examples using Web Audio API:

Audio Features

  • Accent/Beat Distinction: Accents use higher pitch (default 800Hz), beats use lower pitch (default 400Hz)
  • Customizable Parameters: Adjustable pitch frequency, volume, and duration
  • Audio Envelope: Progressive volume control for natural sound
  • Browser Compatible: Uses standard Web Audio API

Audio Integration Example

// Initialize audio context
let audioContext = new (window.AudioContext || window.webkitAudioContext)();

// Play beat sound
function playBeatSound(isAccent = false) {
    const oscillator = audioContext.createOscillator();
    const gainNode = audioContext.createGain();
    
    oscillator.connect(gainNode);
    gainNode.connect(audioContext.destination);
    
    // Use higher pitch for accents, lower for beats
    oscillator.frequency.setValueAtTime(isAccent ? 800 : 400, audioContext.currentTime);
    oscillator.type = 'sine';
    
    // Set volume envelope
    const now = audioContext.currentTime;
    const duration = 0.15; // 150ms
    
    gainNode.gain.setValueAtTime(0, now);
    gainNode.gain.linearRampToValueAtTime(0.5, now + 0.01);
    gainNode.gain.exponentialRampToValueAtTime(0.01, now + duration);
    
    oscillator.start(now);
    oscillator.stop(now + duration);
}

// Integrate with beat events
beatEmitter.on('beat', (beatData) => {
    const isAccent = beatData.beat === 1;
    playBeatSound(isAccent); // true for accent, false for beat
});

See examples/index.html and examples/audio-test.html for complete audio integration implementations.

Examples

Creating a Metronome App

import { BeatEmitter } from 'js-beat-emitter';

class Metronome {
  private beatEmitter: BeatEmitter;
  private isPlaying: boolean = false;

  constructor(bpm: number = 120) {
    this.beatEmitter = new BeatEmitter({
      mode: 'timer-based',
      bpm,
      beatsPerMeasure: 4,
      intensity: 0.8
    });

    this.setupEventListeners();
  }

  private setupEventListeners(): void {
    this.beatEmitter.on('beat', (beatData) => {
      const isAccent = beatData.beat === 1;
      this.playClick(isAccent);
      this.updateUI(beatData);
    });

    this.beatEmitter.on('error', (error) => {
      console.error('Metronome error:', error);
      this.stop();
    });
  }

  public async start(): Promise<void> {
    if (!this.isPlaying) {
      await this.beatEmitter.start();
      this.isPlaying = true;
    }
  }

  public stop(): void {
    if (this.isPlaying) {
      this.beatEmitter.stop();
      this.isPlaying = false;
    }
  }

  public setBPM(bpm: number): void {
    this.beatEmitter.setBPM(bpm);
  }

  public setTimeSignature(beats: number): void {
    this.beatEmitter.setBeatsPerMeasure(beats);
  }

  private playClick(isAccent: boolean): void {
    // Implement audio playback (see audio integration example)
  }

  private updateUI(beatData: BeatData): void {
    // Update visual indicators
  }
}

Real-time Audio Analysis

import { BeatEmitter } from 'js-beat-emitter';

class BeatDetector {
  private beatEmitter: BeatEmitter;
  private onBeatCallback?: (beatData: BeatData) => void;

  constructor() {
    this.beatEmitter = new BeatEmitter({
      mode: 'audio-analysis',
      beatsPerMeasure: 4,
      threshold: 0.15,
      minBpm: 80,
      maxBpm: 160
    });

    this.setupEventListeners();
  }

  private setupEventListeners(): void {
    this.beatEmitter.on('beat', (beatData) => {
      console.log(`Beat detected: ${beatData.beat}/${beatData.totalBeats}`);
      console.log(`Intensity: ${beatData.intensity.toFixed(3)}`);
      
      if (this.onBeatCallback) {
        this.onBeatCallback(beatData);
      }
    });

    this.beatEmitter.on('tempo', (tempoData) => {
      console.log(`Tempo: ${tempoData.bpm} BPM`);
      console.log(`Confidence: ${(tempoData.confidence * 100).toFixed(1)}%`);
    });
  }

  public async startDetection(): Promise<void> {
    try {
      await this.beatEmitter.start();
      console.log('Beat detection started');
    } catch (error) {
      console.error('Failed to start beat detection:', error);
    }
  }

  public stopDetection(): void {
    this.beatEmitter.stop();
    console.log('Beat detection stopped');
  }

  public onBeat(callback: (beatData: BeatData) => void): void {
    this.onBeatCallback = callback;
  }
}

Browser Usage

For browser environments, use the pre-built UMD bundle:

<script src="node_modules/js-beat-emitter/dist/js-beat-emitter.browser.js"></script>
<script>
  const beatEmitter = new BeatEmitter({
    mode: 'timer-based',
    bpm: 120,
    beatsPerMeasure: 4
  });

  beatEmitter.on('beat', (beatData) => {
    console.log(`Beat ${beatData.beat}/${beatData.totalBeats}`);
  });

  beatEmitter.start();
</script>

Performance

JS Beat Emitter is optimized for high performance:

  • Low Latency: Sub-millisecond timing precision in timer mode
  • Memory Efficient: Minimal memory footprint with smart event handling
  • CPU Optimized: Efficient algorithms for real-time audio processing
  • Scalable: Supports multiple concurrent instances

Benchmarks

  • Timer mode: ~0.1ms average latency
  • Audio analysis: ~5ms processing time per frame
  • Memory usage: <1MB baseline
  • CPU usage: <2% on modern devices

Browser Compatibility

  • Modern Browsers: Chrome 66+, Firefox 60+, Safari 11.1+, Edge 79+
  • Audio Analysis: Requires getUserMedia API support
  • Web Audio: Requires Web Audio API for audio integration examples

Node.js Compatibility

  • Node.js: 14.0+ (ES2020 support required)
  • Audio Analysis: Requires additional audio input setup (not included)

Examples and Demos

Check out the examples/ directory for:

  • Basic Usage: Simple timer and audio analysis examples
  • Interactive Demo: Full-featured web interface with audio
  • Audio Integration: Complete metronome with sound
  • Performance Tests: Benchmarking and stress tests

Contributing

We welcome contributions! Please see CONTRIBUTING.md for guidelines.

License

MIT License - see LICENSE file for details.

Links


Built with ❤️ for the music and rhythm community.