Skip to content

About

Wasm version of and npm package for the auto offset crate

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

prpr-auto-offset-wasm

WebAssembly bindings for Phira's prpr-auto-offset delay-alignment library, plus a TypeScript-first npm package that wraps it.

Given an audio track and a chart's note events, the library estimates the timing offset between when notes are placed and when the corresponding hit sounds actually play. It runs entirely in the browser via WebAssembly.

  • Rust crate: crates/prpr-auto-offset-wasm — a thin wasm-bindgen wrapper over the upstream crate.
  • npm package: @teamflos/prpr-auto-offset-wasm — an ergonomic, validated TypeScript facade.

Browser demo

Demo.

To preview locally, run make demo, then serve site/ over HTTP (for example, python -m http.server 8080 --directory site). Without Make:

cd npm
npm ci
npm run build:wasm:web
cd ..
node scripts/build-demo.mjs
python -m http.server 8080 --directory site

For GitHub Pages, set Settings → Pages → Build and deployment → Source → GitHub Actions. The Pages workflow builds from source and deploys on pushes to main or manual dispatch. All asset URLs are relative, including the worker and WASM, so repository subpaths work.


How it works

audio PCM ──► audio frontend ──► "novelty" signal N(t)
note events ─► note frontend ──► note signal M(t)
N(t), M(t) ──► normalized cross-correlation ──► offset + confidence

Audio frontends: EnergyDiff, SpectralFlux (diagnostic) and SuperFlux (recommended). Note frontends: GaussianNote (diagnostic) and WeightedGaussianNote (recommended).


WASM API (what the npm package drives)

  • estimate_auto_offset(options) — one-call entry point. Builds a frontend + note signal from raw PCM and note events, then runs the alignment. Returns a result object with .offset, .correlation, .reliable, and .correlationCurve.
  • Low-level SignalHandle factories (superflux, energyDiff, spectralFlux, gaussianNote, weightedGaussianNote) + estimate / estimate_with.
  • compute_spectrogram for visualization.

npm usage

import { estimateAutoOffset } from "@teamflos/prpr-auto-offset-wasm";

const res = estimateAutoOffset({
  pcm: audioPcm,            // Float32Array, mono
  sampleRate: 44100,
  notes: [
    { time: 1.0, kind: "tap" },
    { time: 1.25, kind: "flick" },
  ],
});

// res: { offset, correlation, rawPeak, noteEnergy, audioEnergy, reliable, correlationCurve }

Important

offset is absolute time, not a chart offset. To get the value you should set on the chart, subtract searchCenterSec — i.e. the chart author's configured offset when it is set, otherwise 0:

chartOffset = offset − searchCenterSec

Example: if the chart author set offset = 0.05s and you pass searchCenterSec = 0.05, a detected offset = 0.112s means the chart needs a +62ms correction.

Note

reliable is only the algorithm's internal gate — correlation > 0.2 — a bare lower bound that real charts easily exceed. It is not a quality scale. To judge quality, use the reference bands that the Phira offset panel draws on the correlation curve:

  • 0.35 — poor / lower bound: below this the note pattern has essentially no usable match (in a 2000-chart sample only ~6 per 1000 scored below it).
  • 0.6–0.75 — typical / usual: the range where most charts land.

Treat reliable as a minimal sanity check, and interpret quality with the bands above.

No-bundler / CDN use

When you can't run a bundler (raw <script type="module">, CDN), use the ./web entry, which exports the raw wasm-bindgen API, plus an async init you must call first. Unlike the main TypeScript entry, it uses numeric enum codes, noteEvents, and alignConfig; results expose curve_offsets() / curve_values() and must be freed:

import init, { estimate_auto_offset } from "@teamflos/prpr-auto-offset-wasm/web";
await init();
const res = estimate_auto_offset({
  pcm: audioPcm, sampleRate: 44100,
  noteEvents: [{ time: 1, kind: 0 }], // 0=tap, 1=hold, 2=flick, 3=drag
  frontend: 2, noteMethod: 1,        // SuperFlux + weighted Gaussian
  alignConfig: { searchCenterSec: 0, searchRangeSec: 0.3, samplingIntervalSec: 0.005 },
});
try { console.log(res.offset, res.correlation); }
finally { res.free(); }

Low-level signal API

Build frontends individually and combine them:

import { superflux, weightedGaussianNote, estimateWith } from "@teamflos/prpr-auto-offset-wasm";

const audio = superflux(pcm, 44100);                          // or spectralFlux / energyDiff
const note  = weightedGaussianNote(notes, 0.02, noteConfig);   // or gaussianNote
const res   = estimateWith(audio, note, durationSec, { searchCenterSec: authorOffset });
const vals  = audio.sample(new Float64Array([1.0, 1.5, 2.0])); // sample at arbitrary times

Building

Prerequisites: Rust (with wasm32-unknown-unknown), wasm-pack, Node.js, and npm/pnpm.

# install the TypeScript build dependency first
cd npm && npm ci && cd ..

# wasm (bundler target) → npm/pkg
make wasm

# TypeScript facade → npm/dist
make npm

# Node smoke test (builds a nodejs-target wasm into tests/pkg-node)
make test

Run everything end-to-end:

make build

npm release checklist

From npm/, run:

npm ci
npm pack --dry-run  # rebuilds bundler + web WASM, compiles TS, checks package contents
npm publish --access public

prepack requires Rust, the wasm32 target, and wasm-pack. It copies the repository README and GPL license into the package and rejects missing JS, declarations, or WASM binaries. The package is not published by CI. Before a release, also run make test. The main entry is for WASM-capable bundlers; use /web for native browser modules. The version is currently 0.1.0; keep the npm and Cargo workspace versions aligned when bumping it.

Note on wasm-opt

wasm-opt is disabled in the crate's wasm-pack metadata. To optimize the shipped .wasm, run:

wasm-opt --enable-bulk-memory --enable-nontrapping-float-to-int -O \
  pkg/prpr_auto_offset_wasm_bg.wasm -o pkg/prpr_auto_offset_wasm_bg.wasm

License

GPL-3.0-only, matching the upstream prpr-auto-offset crate, which this project builds on.

About

Wasm version of and npm package for the auto offset crate

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages