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:

BrowserNotes
Chrome / EdgeFull support (desktop and Android)
FirefoxFull support
SafariFull 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.