Skip to content

Installation

Pleco-Xa ships as a single, zero-dependency ES module. There is nothing to compile and nothing to pull in behind it: the entire library — BPM and beat tracking, spectral features, structural analysis, and its signature loop detection — is plain JavaScript that runs the same in Node and in the browser.

Terminal window
npm install pleco-xa
import { beat_track, loop, feature } from 'pleco-xa'

The package is pure ESM ("type": "module") and has no runtime dependencies — installing it adds exactly one entry to your tree. It works with any modern bundler (Vite, esbuild, Rollup, webpack) and with Node’s native ESM loader; no plugin or loader configuration is required.

Because it is native ESM, you can import Pleco-Xa straight from a CDN with no build step — a bare <script type="module"> is enough.

<script type="module">
import { beat_track, loop } from 'https://cdn.jsdelivr.net/npm/pleco-xa@2.0.3/dist/pleco-xa.js'
// ...
</script>

The unpkg mirror works the same way, and a minified build is available beside the main bundle:

// unpkg
import * as pleco from 'https://unpkg.com/pleco-xa@2.0.3/dist/pleco-xa.js'
// minified build (either CDN)
import * as pleco from 'https://cdn.jsdelivr.net/npm/pleco-xa@2.0.3/dist/pleco-xa.min.js'

The core analysis functions are deliberately runtime-blind. They take a mono signal as a Float32Array (a plain number[] works too) plus a sample rate, and return plain arrays or typed arrays — arrays in, arrays out. There is no AudioContext, no DOM, and no window on that path:

import { beat_track, feature } from 'pleco-xa'
// y: Float32Array of mono samples, sr: sample rate in Hz
const { tempo, beats } = beat_track(y, sr)
const mel = feature.melspectrogram(y, { sr }) // Array<Float32Array>, [freq][time]

The exact same import line and the exact same call run in Node and in the browser — that is the point. Where a function genuinely needs the host (playing sound, reading a File, drawing to a <canvas>), it lives in a browser-facing namespace and says so.

beat_track and friends want samples, not files. To turn a URL or a File into a signal, use one of the decoding entry points:

  • loadAudioFile(url) — fetches and decodes to a real AudioBuffer via the Web Audio API. Returns { audioBuffer, audioContext, arrayBuffer }. This is the buffer the loop namespace consumes directly.
  • audioio.load(url, { sr, mono }) — fetches and decodes to { y, sr } (a Float32Array and its sample rate), resampling to sr if you ask. This is the fast path to the (y, sr) core.
  • decodeWav(arrayBuffer) — pure-JS WAV decoder (PCM 16/24/32-bit int and 32-bit float). Returns { channels, sampleRate } and runs identically in Node, the browser, and workers — no AudioContext required.
import { loadAudioFile, beat_track, loop } from 'pleco-xa'
const { audioBuffer } = await loadAudioFile('/audio/break.wav')
const y = audioBuffer.getChannelData(0)
const sr = audioBuffer.sampleRate
const { tempo } = beat_track(y, sr) // (Float32Array, sr) core
const result = await loop.detect(audioBuffer) // AudioBuffer-like in

In Node, decodeWav covers WAV out of the box; for other codecs, decode with a library of your choice and hand the resulting samples to the (y, sr) core.

Node. Version 18 or newer (declared in engines). Nothing else — no native add-ons, no node-gyp, no system libraries.

Browsers. Any evergreen browser with ES module support and, for the audio I/O and playback layers, the Web Audio API:

Browser Notes
Chrome / Edge Full support (desktop and Android)
Firefox Full support
Safari Full support (macOS and iOS)

The pure (y, sr) analysis core needs only ES modules, so it runs anywhere modern JavaScript does — including Web Workers and audio worklets. The AudioContext-backed helpers (loadAudioFile, audioio.play, LoopPlayer, the canvas display layer) require a browser.

With the package installed, head to the Quickstart to load a clip, track its tempo, and find its loop in a dozen lines.