# time

> Musical time from @audio-ui/engine: tempos and signatures, bars and beats, grid divisions and their labels, tempo-synced note values, warp markers, the metronome, and the look-ahead scheduler a transport clock runs on.

```bash
npm install @audio-ui/engine
```

```ts
import { adjacentDivision, barLabelInterval, DOTTED_FACTOR, divisionAt, divisionSeconds, /* … */ } from "@audio-ui/engine/time";
```

- Used by: `arrangement`, `arrangement-engine`, `dawproject`, `demo-song`, `demo-sound`, `synced-rate`, `use-arrangement`, `use-piano-roll-playback`, `use-timeline-grid`, `use-transport-clock`

| Export | Kind | What it is |
| --- | --- | --- |
| `adjacentDivision` | function | The fixed division next to `division`: a finer one (`direction` 1, twice as dense) or a coarser one (-1), held at the ends of the list. |
| `barLabelInterval` | function | Seconds between labelled bars on a ruler at `zoom` px per second: always a whole number of bars, doubled until labels are at least `minSpacing` px apart, so they never collide or fall mid-bar. |
| `DOTTED_FACTOR` | const | Three halves: a dotted note is its straight one and half again. |
| `divisionAt` | function | The fixed division whose step is nearest `seconds` at `tempo`: what a grid that follows the zoom becomes when it is fixed where it is. |
| `divisionSeconds` | function | How long one fixed division lasts at `tempo`, in seconds. |
| `FixedGridDivision` | type | The id of a fixed grid division: `"4-bars"` to `"1/32"`. |
| `GRID_DIVISIONS` | const | The fixed grid divisions, coarsest first: a number of bars, or a note value. |
| `GridDivision` | type | `adaptive` follows the zoom; a fixed division stays put however far you zoom. |
| `GridIntervalOptions` | interface | How close adaptive grid lines may be, and whether the grid is in triplets. |
| `gridInterval` | function | Seconds between grid lines at `zoom` px per second: the lines a timeline draws and the step it snaps to, so what you see is where you land. |
| `gridLabel` | function | Names an interval the way a grid readout does: "1 bar", "4 bars", "1/16", "1/8T". |
| `METRONOME_RHYTHMS` | const | How often a metronome clicks: with the beat, or a note value, straight or triplet. |
| `MetronomeRhythm` | type | The id of a metronome rhythm: `"auto"` (the beat), a bar, or a note value, straight or triplet. |
| `metronomeRhythmSeconds` | function | Seconds between clicks for a rhythm, or `null` for `auto`, which has no interval of its own: it is the beat, whatever the signature makes one. |
| `SYNCED_DIVISIONS` | const | The note values a time parameter that follows the tempo can take, shortest first: `1/16` is a sixteenth note, `1/8t` a triplet eighth (two thirds of it) and `1/8d` a dotted eighth (one and a half times it). |
| `SyncedDivision` | type | A note value as `syncedSeconds` reads it: `"1/8"`, its triplet `"1/8t"` or its dotted `"1/8d"`. |
| `syncedSeconds` | function | How long a synced note value lasts at `tempo`, in seconds: `1/8` an eighth, `1/8t` its triplet, `1/8d` its dotted one. |
| `TRIPLET_FACTOR` | const | Three in the space of two: a triplet division is 2/3 of its straight one. |
| `Bar` | interface | A bar as a ruler draws it. |
| `barsBeatsWith` | function | Where `seconds` falls in bars, beats and sixteenths through the signature changes, each counted from one. |
| `barsOf` | function | The bars from 0 to `until` seconds, through the signature changes: whole bars of each signature, and a partial bar where a change cuts one short. |
| `isSignature` | function | Whether a signature is one a bar can have: 1 to 99 beats of a whole, half, quarter, eighth or sixteenth note. |
| `MetronomeClick` | interface | A click of a metronome. |
| `metronomeClicks` | function | The clicks of a metronome from 0 to `until` seconds, through the signature changes. |
| `SignatureChange` | interface | A new signature from `at` on, in seconds: `beatsPerBar` beats of a `beatUnit` note. |
| `advance` | function | Advances `cursor`, emitting every step boundary now within `SCHEDULE_AHEAD_SECONDS` of `now`. |
| `anchoredCursor` | function | A cursor that emits `step` at `now`, the seed for `start()` and for every re-anchor (seek, region commit). |
| `anchorForTempoChange` | function | The anchor to carry on with when the tempo changes while playing. |
| `MAX_CATCH_UP_SECONDS` | const | How late a boundary may be and still be played, half a second. |
| `positionAt` | function | The continuous playhead position, in fractional full-grid steps, at `now`. |
| `SCHEDULE_AHEAD_SECONDS` | const | How far ahead of `now` boundaries are committed, in seconds: the article's 100 ms. |
| `SCHEDULER_POLL_MS` | const | How often to poll the scheduler, in milliseconds: the article's 25 ms. |
| `SchedulerAnchor` | interface | The audio-time / step pair a running clock is anchored to, for deriving the display position. |
| `SchedulerConfig` | interface | What the scheduler steps through: the window of steps it loops over and how long a step lasts, read on every call. |
| `SchedulerCursor` | interface | Where the scheduler is: the next step it will emit and when. |
| `StepBoundary` | interface | A step to play and the audio time it starts at. |
| `BarsBeats` | interface | A position in bars, beats and sixteenths, each counted from one. |
| `barsBeatsAt` | function | Where `seconds` falls in bars, beats and sixteenths, each counted from one. |
| `bpmToMicrosecondsPerQuarterNote` | function | A tempo in BPM as microseconds per quarter note, the unit a MIDI file stores: 120 BPM is 500000. |
| `DEFAULT_MICROSECONDS_PER_QUARTER_NOTE` | const | What a file with no Set Tempo event plays at: 120 BPM, 500,000 microseconds a quarter note. |
| `DEFAULT_TEMPO` | const | 120 BPM in 4/4. |
| `describeBarsBeats` | function | "Bar 3, beat 2", the way a position is read out to a screen reader. |
| `microsecondsPerQuarterNoteToBpm` | function | The BPM of a Set Tempo's microseconds per quarter note: 500000 is 120. |
| `secondsPerBar` | function | Seconds per bar: a beat times the beats in a bar. |
| `secondsPerBeat` | function | Seconds per beat, a beat being one `beatUnit` note: in 6/8, half a quarter. |
| `secondsPerQuarter` | function | Seconds per quarter note: BPM counts quarters whatever the signature says. |
| `Tempo` | interface | Tempo and time signature: how long a quarter note, a beat and a bar last in seconds, and where a position in seconds falls in bars and beats. |
| `addWarpMarker` | function | Adds a marker at a time on the clip, pinning what plays there; nothing changes in how it plays until it moves. |
| `moveWarpMarker` | function | Moves the marker at `index` to a new time on the clip, stretching the recording on either side of it: it stops short of its neighbours. |
| `removeWarpMarker` | function | Takes the marker at `index` away, as long as two are left to make a map. |
| `scaleWarp` | function | Plays the whole map `factor` times as long: 2 is half the speed, an octave down; 0.5 twice the speed. |
| `unwarpedTime` | function | What time in the source plays at a time on the clip. |
| `WarpMarker` | interface | A time in the source, pinned to a time on the clip. |
| `warpedTime` | function | Where on the clip a time in the source plays. |
| `warpMarkers` | function | The markers that make a map: finite ones, in order, each later than the one before in both times. |
| `warpRate` | function | How fast the source plays at a time on the clip: 1 as recorded, 2 twice as fast. |

## Usage

A `Tempo` is a BPM and a signature. Every function that turns seconds into music, or music into seconds, reads one:

```ts
import { barsBeatsAt, secondsPerBar, secondsPerBeat, syncedSeconds } from "@audio-ui/engine/time";

const tempo = { bpm: 120, beatsPerBar: 6, beatUnit: 8 };

secondsPerBeat(tempo); // 0.25: an eighth note at 120 BPM
secondsPerBar(tempo); // 1.5
barsBeatsAt(2, tempo); // { bar: 2, beat: 3, sixteenth: 1 }
syncedSeconds("1/8d", tempo); // a dotted eighth, for a delay that follows the tempo
```

BPM counts quarter notes whatever the signature says, so a 6/8 bar at 120 BPM lasts three quarters. `describeBarsBeats` gives the same position as text for a screen reader, "Bar 2, beat 3".

## The grid

`gridInterval(division, zoom, tempo)` is the step between two grid lines at a zoom in pixels per second, and the step an edit snaps to, so what is drawn is where a drag lands. `"adaptive"` follows the zoom and keeps lines at least 24 px apart; a fixed division (an id of `GRID_DIVISIONS`, from `"4-bars"` to `"1/32"`) stays put. `gridLabel` names the interval as a readout does, "1 bar" or "1/8T", and `barLabelInterval` spaces the bar numbers of a ruler.

## Signature changes and the metronome

`barsOf(tempo, changes, until)` lists the bars up to a time through `SignatureChange`s, with a partial bar where a change cuts one short, and `barsBeatsWith(seconds, tempo, changes)` reads a position through them. `metronomeClicks(tempo, changes, until, rhythm)` lists the clicks over the same changes, each with `accent` on the first of its bar; `METRONOME_RHYTHMS` holds the rhythms it can click at, `"auto"` (the beat) by default.

## The scheduler

A transport clock that plays sound ahead of time calls `advance` on a timer: it returns every step boundary within the next 100 ms, each with the audio time to give to a node's `start()`, and the cursor to call it with next time.

```ts
import { advance, anchoredCursor, SCHEDULER_POLL_MS } from "@audio-ui/engine/time";

const config = { regionStart: 0, regionEnd: 16, secondsPerStep: 60 / 120 / 4 };
let cursor = anchoredCursor(ctx.currentTime, 0);

setInterval(() => {
  const next = advance(cursor, ctx.currentTime, config);
  for (const { step, time } of next.boundaries) {
    playStep(step, time);
  }
  cursor = next.cursor;
}, SCHEDULER_POLL_MS);
```

`config` is read fresh on every call, so a tempo change takes effect at the next boundary. `positionAt(now, anchor, config)` is the playhead between boundaries, in fractional steps, and `anchorForTempoChange` keeps it continuous when the tempo moves while playing. A boundary later than half a second is skipped rather than played late.

**In React**

The registry's [`useTransportClock`](/docs/hooks/use-transport-clock) runs this loop for a React page.

## Warp markers

A `WarpMarker` pins a time in a recording to a time on a clip. `warpMarkers` keeps the markers that make a valid map, `warpedTime` and `unwarpedTime` read it both ways, `warpRate` is how fast the recording plays at a point, and `addWarpMarker`, `moveWarpMarker`, `removeWarpMarker` and `scaleWarp` edit it.

## MIDI tempos

A MIDI file stores a tempo as microseconds per quarter note: `bpmToMicrosecondsPerQuarterNote(120)` is 500000, and `microsecondsPerQuarterNoteToBpm` goes back.
