/** * Estimate the global tempo (BPM) with aggregate='mean'. * * The pseudo-log-normal prior formula: * logprior = -0.5 * ((log2(bpms) - log2(start_bpm)) / std_bpm) ** 2 * and the estimate is * argmax(log1p(1e6 * tempogram_mean) + logprior) over lag bins, * with all bins at or above max_tempo masked to -Infinity. * * @param {Float32Array|Array|null} y - audio time series (may be null when * opts.onsetEnvelope is provided) * @param {Object|number} [opts] - options object, or sr as a number * (positional call: tempo(y, sr)) * @param {number} [opts.sr=22050] - sample rate * @param {Float32Array|Array} [opts.onsetEnvelope=null] - pre-computed onset * strength envelope (onset_strength output) * @param {number} [opts.hopLength=512] * @param {number} [opts.startBpm=120] - center of the log-normal prior * @param {number} [opts.stdBpm=1.0] - prior standard deviation (log2 space) * @param {number} [opts.acSize=8.0] - autocorrelation window in seconds * @param {number|null} [opts.maxTempo=320.0] - mask tempi at/above this value * @param {'mean'|null} [opts.aggregate='mean'] - aggregation mode: * 'mean' (default) scores the time-mean tempogram and returns a * single BPM; null skips aggregation and returns a per-frame Float64Array * of BPM estimates (dynamic tempo) * @returns {number|Float64Array} estimated tempo in BPM (scalar for * aggregate='mean', one BPM per onset-envelope frame for aggregate=null) * @throws {Error} on missing/empty input, invalid parameters, or an all-zero * onset envelope (silent or constant input) — never returns a fabricated * default such as the prior's argmax */ export function tempo(y: Float32Array | any[] | null, opts?: any | number): number | Float64Array; /** * Dynamic programming beat tracker. * * Pipeline (Ellis 2007): * 1. onset_strength(y, aggregate='median') (skipped if onsetEnvelope given) * 2. tempo(onsetEnvelope) with the log-normal prior (skipped if bpm given) * 3. DP peak picking consistent with the estimated tempo * * @param {Float32Array|Array|null} y - audio time series (may be null when * opts.onsetEnvelope is provided) * @param {number} [sr=22050] - sample rate * @param {Object} [opts] * @param {Float32Array|Array} [opts.onsetEnvelope=null] - pre-computed onset envelope * @param {number} [opts.hopLength=512] * @param {number} [opts.startBpm=120] - prior center for tempo estimation * @param {number} [opts.tightness=100] - beat distribution tightness * @param {boolean} [opts.trim=true] - trim weak leading/trailing beats * @param {number|Array|Float64Array} [opts.bpm=null] - known tempo * (skips estimation). A scalar tracks a static tempo; an ARRAY of * per-frame BPM values (length 1 or one per onset-envelope frame, e.g. * the output of tempo(..., {aggregate: null})) tracks time-varying tempo. * @param {string} [opts.units='frames'] - 'frames' | 'samples' | 'time' * (default is 'frames') * @param {boolean} [opts.sparse=true] - sparse indices vs dense boolean array * @returns {{tempo: number|Array|Float64Array, beats: Array|Array}} * tempo echoes a caller-provided bpm as given; when estimated it is a scalar * @throws {Error} on missing/empty input or invalid parameters */ export function beat_track(y: Float32Array | any[] | null, sr?: number, opts?: { onsetEnvelope?: Float32Array | any[]; hopLength?: number; startBpm?: number; tightness?: number; trim?: boolean; bpm?: number | Array | Float64Array; units?: string; sparse?: boolean; }): { tempo: number | Array | Float64Array; beats: Array | Array; }; /** * QUICK TIER — windowed live tempo estimate. * * Analyzes only the last `windowSec` seconds of audio with a normalized * autocorrelation over the onset envelope. This is intentionally cheaper * and coarser than tempo(): lag-quantized BPM, no tempogram, no log-normal * prior. * * This is NOT the precise tier and is NEVER used as a fallback by tempo() or * beat_track(). Callers opt into the quick tier explicitly. * * @param {Float32Array|Array} y - audio time series * @param {number} [sr=22050] - sample rate * @param {Object} [opts] * @param {number} [opts.windowSec=8] - analysis window: last N seconds of y * @param {number} [opts.hopLength=512] * @param {number} [opts.minBpm=70] - lower edge of the search range * @param {number} [opts.maxBpm=180] - upper edge of the search range * @returns {{bpm: number, confidence: number, tier: 'quick', windowSec: number}} * confidence is the measured prominence of the best autocorrelation peak * over the runner-up (0..1), not a constant. * @throws {Error} if the window contains no detectable onsets or is too * short for the requested BPM range — never returns a default BPM. */ export function quickTempo(y: Float32Array | any[], sr?: number, opts?: { windowSec?: number; hopLength?: number; minBpm?: number; maxBpm?: number; }): { bpm: number; confidence: number; tier: "quick"; windowSec: number; }; /** * Stateful convenience wrapper around the canonical engine. All numerical * work happens in the module-level functions above. */ export class BeatTracker { /** @type {number|null} optional tempo hint set via setTempo() */ tempoHint: number | null; /** * Set a tempo hint (BPM) used by beatTrack() when no explicit bpm option * is provided. Pass null to clear. * @param {number|null} bpm */ setTempo(bpm: number | null): void; /** * Beat tracking (options-object API). * @param {Object} options - {y, sr, onsetEnvelope, hopLength, startBpm, * tightness, trim, bpm, units, sparse} — see beat_track() * @returns {{tempo: number, beats: Array}} */ beatTrack(options?: any): { tempo: number; beats: any[]; }; /** * Tempo estimation from a pre-computed onset envelope. * @param {Float32Array|Array} onsetEnvelope * @param {Object} [opts] - see tempo() * @returns {number} BPM */ tempoEstimation(onsetEnvelope: Float32Array | any[], opts?: any): number; /** * Onset strength (delegates to xa-onset). * @param {Float32Array|Array} y * @param {number} [sr=22050] * @param {number} [hopLength=512] * @returns {Float32Array} */ onsetStrength(y: Float32Array | any[], sr?: number, hopLength?: number): Float32Array; }