Skip to content

Latest commit

 

History

History
128 lines (93 loc) · 3.45 KB

README.md

File metadata and controls

128 lines (93 loc) · 3.45 KB

Metronome

A headless metronome built on top of the Web Audio API.

npm install @dougflip/metronome

Basic Usage

Plays a "click" sound on each beat using the Web Audio API. Allows you to update the tempo and volume after creation.

import { createMetronome } from "@dougflip/metronome";

const metronome = createMetronome({
  tempo: 60, // as beats per minute
  beatsPerBar: 4,
  volume: 50, // value from 0-100
});

// the Web Audio API requires a user event to trigger sound!
// make sure you call `start` in response to a user event
function handleMetronomeStartClick() {
  metronome.start();
}

// Update tempo or volume - from form control inputs for example
function handleMetronomeUpdate({ tempo, volume }) {
  metronome.updateConfig({ tempo, volume });
}

// sometime later, when you are done
function handleMetronomeStopClick() {
  metronome.stop();
}

Events

There are also several supported events which can be configured

  • onBeatStart: A callback that fires at the start of each beat. Useful to trigger visual cues or other events.

  • beatInterval: A configuration that allows you to set a specific interval of beats to trigger an event. For example, you can set it to fire every 4 beats.

  • maxBeats: A configuration that allows you to set the total number of beats before the metronome stops automatically. This includes an optional onEnd callback that fires when the metronome stops.

import { createMetronome } from "@dougflip/metronome";

const metronome = createMetronome({
  tempo: 60,
  volume: 50,
  beatsPerBar: 4,

  // fires on every beat
  //   - `beatsPerBar`: beat number relative to `beatsPerBar`
  //   - `totalBeats`: total number of beats since start
  onBeatStart: ({ beatNumber, totalBeats }) =>
    console.log({ beatNumber, totalBeats }),

  // fire an event every 4 beats - starting on beat 1.
  // in this case, beats 1, 5, 9, etc., corresponding to the start of every measure
  beatInterval: {
    count: 4,
    onBeatInterval: ({ currentInterval }) => console.log(currentInterval),
  },

  // play for a maximum of 10 measures (4 beatsPerBar times 10 measures)
  // the last beat will last its full length and then `onEnd` will fire
  maxBeats: {
    count: 4 * 10,
    onEnd: () => console.log("metronome has stopped"),
  },
});

Local Development

# select correct node
nvm use

# install deps
npm install

# build the code
npm run build

# verify the code and build
npm run check

Tests

The e2e dir contains the playwright tests for this package.

npm run e2e

The basic approach is to have an HTML page which creates a metronome, subscribes to all of the metronome's events, and outputs text to the page in response to the events. The tests will start the metronome and then assert that messages appear on the page.

Eventually, I may look into extracting some of the state management and unit testing that in isolation. For now though, I am much more interested in verifying the metronome as a whole and ensuring the callbacks fire.

Inspiration and Credit

An original version of this metronome was based upon:

This version was built using the same principles but adds events and state tracking. Most of the actual code was written by Claude.ai

License

This project is licensed under the MIT License. See the LICENSE file for details.