Lab

useTransportClock

A look-ahead transport clock on the audio clock: it calls back with the audio time of each step so notes are scheduled sample-accurately, with a loop region, seek and tempo changes.

pnpm dlx shadcn@latest add @audio-ui/use-transport-clock
import { useTransportClock } from "@/hooks/use-transport-clock";
Fileshooks/use-transport-clock.ts
Depends onweb-audio
npm@audio-ui/engine
Used bysequencer, use-piano-roll-playback, use-playback-clock, use-simulated-clock
ExportKindWhat it is
TransportRegioninterface
UseTransportClockOptionsinterface
UseTransportClockReturninterface
useTransportClockfunctionThe region-aware {@link https://web.dev/audio-scheduling | look-ahead} transport clock, the seam between musical time (tempo, steps, loop region, seek) and Web Audio scheduling.

Usage

A timer in JavaScript drifts and stalls when the page is busy or in the background; the audio clock does not. useTransportClock looks a little ahead on the audio clock and calls you back with the exact audio time of each step, so you schedule the sound at that time and it plays on the beat whatever the page is doing.

import { useTransportClock } from "@/hooks/use-transport-clock";

const clock = useTransportClock({
  bpm: 120,
  stepsPerBeat: 4, // a step is a sixteenth note
  totalSteps: 64, // four bars
  region: loop, // { start, end } in steps, or null for all of it
  onStep: (step, time) => {
    for (const note of notesAt(step)) {
      voices.triggerNote(note.pitch, envelope, note.velocity, time);
    }
  },
  onReset: () => voices.releaseAll(),
});

<Button onClick={clock.isPlaying ? clock.stop : clock.start}>Play</Button>;

The clock knows when, never what: onStep decides what plays. onReset runs on every start, stop, seek and loop change, to drop what was already scheduled ahead. For a playhead, read getPosition() in an animation frame and push it to a source: it gives fractional steps, so the playhead glides between them.

The piano roll plays its notes with this clock through usePianoRollPlayback, which is a good example to copy.

Options · 6

Returns · 5

The scheduling itself is plain functions in @audio-ui/engine/time (advance, anchoredCursor, positionAt, SCHEDULE_AHEAD_SECONDS): the hook only connects them to React and the audio context, so an engine outside React uses them directly.

Built by Ouest Labs, the source code is available on GitHub.
RSS