Move docs/ package mirror into document-navigator plugin

Relocate the ~6k-file docs tree from the repo root into
plugins/document-navigator/docs/ so the plugin is self-contained and
portable. docs/superpowers/ (specs and plans) stays at the repo root.

Moved via cp+rm rather than git mv because directory rename() fails with
EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the
identical-content files at commit time.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-30 01:10:00 +01:00
parent fe3fedf42e
commit 9bf56a806b
6022 changed files with 12437 additions and 0 deletions

View File

@@ -0,0 +1,57 @@
# Error Codes
This module defines the canonical error codes, metadata, and error class for the `@suaveplan/audio-transport` package. Every throwing site in the library uses one of these codes so that callers can handle failures programmatically without parsing human-readable messages.
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Audio transport involves many operations that can fail in predictable ways: invalid time tokens, out-of-range BPM values, missing scheduled events, and operations on a disposed transport. Centralising the error codes in one module guarantees consistency across the package and gives consumers a stable contract for error handling.
## Features
- Five error codes covering time, BPM, scheduler, events, and disposal
- `TransportError` extends `SuaveplanError` with a public constructor
- `AUDIO_TRANSPORT_ERROR_METADATA` maps each code to a description and severity
- `registerTransportErrorCodes()` alias for spec compliance
- Self-registering on import
## Usage: Basic
```ts
import { AUDIO_TRANSPORT_CODES, TransportError } from "@suaveplan/audio-transport";
throw new TransportError(
AUDIO_TRANSPORT_CODES.INVALID_TIME,
"audio_transport.transport.invalid_loop_end",
{ context: { loopStart: "0:0:0", loopEnd: "0:0:0" } }
);
```
## Usage: Advanced
```ts
import {
AUDIO_TRANSPORT_CODES,
AUDIO_TRANSPORT_ERROR_METADATA,
TransportError,
} from "@suaveplan/audio-transport";
function describeFailure(err: TransportError): string {
const meta = AUDIO_TRANSPORT_ERROR_METADATA[err.code];
return `${meta.severity}: ${meta.description}`;
}
```
## API Reference
- `AUDIO_TRANSPORT_CODES` — `defineCodes("AUDIO_TRANSPORT", [...])` constant
- `AUDIO_TRANSPORT_ERROR_METADATA` — readonly map of code → `{ description, severity }`
- `TransportError` — error class with public constructor `(code, messageKey, options?)`
- `registerTransportErrorCodes()` / `registerAudioTransportErrorCodes()` — no-op aliases
## Implementation Notes
The registry is self-registering on import. `TransportError` widens the protected `SuaveplanError` constructor to public so that factory and class methods can instantiate it directly. All five codes are exercised by the test suite. The `TransportErrorCode` type alias and `registerTransportErrorCodes` function exist purely for spec compliance and resolve to the same runtime values as their `AudioTransport*` counterparts.

View File

@@ -0,0 +1,58 @@
# TransportScheduler
The `TransportScheduler` class drives the lookahead loop that polls the transport and fires scheduled callbacks. It bridges the `Transport` and the wall clock, ensuring that musical events are delivered with sample-accurate timing even when the underlying poll timer is coarse.
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
In real-time audio systems, callbacks must fire at precise musical times. A naive approach would poll the transport on every sample, which is prohibitively expensive. Instead, `TransportScheduler` polls at a coarse interval (~100 Hz) and asks the transport to process the entire time window in one go. The transport then uses `TickSource.forEachTickBetween` to visit every musical tick in the window and invoke callbacks at their exact audio times.
## Features
- Poll-driven lookahead using `@suaveplan/timing`'s `createScheduler`
- `start()` / `stop()` lifecycle
- `AbortSignal` support for mid-run cancellation
- OpenTelemetry `transport.tick` span per poll
- Throws `AUDIO_TRANSPORT_SCHEDULER_NOT_STARTED` for invalid operations
## Usage: Basic
```ts
import { Transport, TransportScheduler } from "@suaveplan/audio-transport";
const tr = new Transport();
const scheduler = new TransportScheduler(tr, () => Date.now() / 1000);
tr.start();
scheduler.start();
```
## Usage: Advanced
```ts
const ac = new AbortController();
scheduler.start({ signal: ac.signal });
// Later:
ac.abort();
```
## API Reference
### Constructor
`new TransportScheduler(transport, clock, options?)`
### Methods
- `start(options?)` — begin polling; accepts `AbortSignal`
- `stop()` — halt polling
### Properties
- `running` — boolean
## Implementation Notes
The scheduler uses real timers via `createScheduler`. Each poll creates an OpenTelemetry span named `transport.tick`. Calling `stop()` before `start()` throws `AUDIO_TRANSPORT_SCHEDULER_NOT_STARTED`. The scheduler does not emit FSM events directly; those are emitted synchronously by the `Transport` when `start`, `stop`, or `pause` are called. The `_tick` and `_scheduleNextPoll` methods contain defensive guards for the case where `stop()` races with a scheduled callback.

View File

@@ -0,0 +1,32 @@
# TransportSchedulerOptionsSchema
Zod boundary schema for `TransportScheduler` construction options.
## Purpose
Validates the options passed when constructing a `TransportScheduler`.
## Features
- Requires `transport` (any — runtime-validated)
- Requires `clock` as a function returning `number`
- Optional `pollIntervalMs` as positive number
## Usage
```ts
import { TransportSchedulerOptionsSchema } from "@suaveplan/audio-transport";
const parsed = TransportSchedulerOptionsSchema.safeParse({
transport: myTransport,
clock: () => Date.now() / 1000,
});
```
## API Reference
- `TransportSchedulerOptionsSchema` — `z.object({ transport, clock, pollIntervalMs })`
## Implementation Notes
`transport` is typed as `z.any()` because Zod cannot express the `Transport` class type at schema level. The constructor performs the actual instance check.

View File

@@ -0,0 +1,63 @@
# Signal
The `Signal` class implements a piecewise automation curve for scalar parameters such as BPM. It stores automation points and evaluates the curve at any audio time, supporting step, linear, and exponential ramps.
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Musical performances often require smooth tempo changes. `Signal` provides the mathematical foundation for these changes by scheduling automation points and interpolating between them. The `TickSource` reads the BPM curve through this `Signal` so that tempo ramps produce a continuously varying tick rate.
## Features
- `setValueAtTime` for step changes
- `linearRampToValueAtTime` for linear interpolation
- `exponentialRampToValueAtTime` for exponential curves
- `getValueAtTime` for curve evaluation at arbitrary times
- `cancelScheduledValues` for clearing future points
- Rejects non-positive and non-finite values with `AUDIO_TRANSPORT_INVALID_BPM`
## Usage: Basic
```ts
import { Signal } from "@suaveplan/audio-transport";
const bpm = new Signal({ initialValue: 120 });
bpm.linearRampToValueAtTime(240, 1);
console.log(bpm.getValueAtTime(0.5)); // 180
```
## Usage: Advanced
```ts
const bpm = new Signal({ initialValue: 100 });
bpm.setValueAtTime(120, 0.5);
bpm.exponentialRampToValueAtTime(240, 1.5);
console.log(bpm.getValueAtTime(1)); // ~169.7
```
## API Reference
### Constructor
`new Signal(options?)`
### Properties
- `initialValue` — value before any points
- `value` — convenience getter returning value at time 0
- `points` — readonly array of automation points
### Methods
- `setValueAtTime(value, time)` — step change
- `linearRampToValueAtTime(value, time)` — linear ramp
- `exponentialRampToValueAtTime(value, time)` — exponential ramp
- `getValueAtTime(time)` — evaluate curve
- `cancelScheduledValues(time)` — remove points at or after time
## Implementation Notes
Points are stored sorted by time. Exponential ramps require strictly positive start and target values; otherwise `AUDIO_TRANSPORT_INVALID_BPM` is thrown. The curve evaluation handles interpolation before the first point, between points, and after the last point.

View File

@@ -0,0 +1,27 @@
# SignalOptionsSchema
Zod boundary schema for `Signal` construction options.
## Purpose
Validates the options passed when constructing a `Signal`.
## Features
- Optional `initialValue` as positive number
## Usage
```ts
import { SignalOptionsSchema } from "@suaveplan/audio-transport";
const parsed = SignalOptionsSchema.safeParse({ initialValue: 130 });
```
## API Reference
- `SignalOptionsSchema` — `z.object({ initialValue })`
## Implementation Notes
The schema is minimal because `Signal` only needs an initial value. All other behavior is controlled via method calls after construction.

View File

@@ -0,0 +1,67 @@
# TickSource
The `TickSource` class converts between audio time (seconds) and musical ticks, integrating tempo curves for sample-accurate scheduling.
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`TickSource` is the mathematical engine behind `Transport`. It translates wall-clock seconds into musical ticks and back, accounting for tempo ramps and anchors. The integration is exact for constant, linear, and exponential tempo segments, ensuring that `getTicksAtTime` and `getTimeOfTick` remain mutual inverses within floating-point tolerance.
## Features
- Exact inverse conversions under constant tempo
- Integration of linear and exponential tempo ramps
- `forEachTickBetween` for sample-accurate tick iteration
- `setTicksAtTime` for anchoring the counter
- Start, stop, and pause lifecycle
- No wall-clock reads — all methods take explicit times
## Usage: Basic
```ts
import { TickSource, Signal } from "@suaveplan/audio-transport";
const ts = new TickSource({ ppq: 192, bpm: new Signal({ initialValue: 120 }) });
ts.start(0);
const ticks = ts.getTicksAtTime(1); // 384
```
## Usage: Advanced
```ts
const bpm = new Signal({ initialValue: 120 });
bpm.linearRampToValueAtTime(240, 1);
const ts = new TickSource({ ppq: 192, bpm });
ts.start(0);
ts.forEachTickBetween(0, 1, (time, tick) => {
console.log("tick", tick, "at", time);
});
```
## API Reference
### Constructor
`new TickSource(options?)`
### Properties
- `ppq` — pulses per quarter note
- `bpm` — `SignalLike` tempo curve
### Methods
- `getTicksAtTime(time)` — ticks at audio time
- `getTimeOfTick(tick, before?)` — audio time of tick
- `setTicksAtTime(ticks, time)` — anchor counter
- `start(time, offset?)` — begin counting
- `stop(time)` — stop counting
- `pause(time)` — pause counting
- `forEachTickBetween(start, end, callback)` — iterate ticks
## Implementation Notes
Tick integration uses closed-form integrals for constant, linear, and exponential tempo segments. `getTimeOfTick` uses binary search over the integrated curve. The `forEachTickBetween` method guarantees no duplicate or skipped ticks across consecutive windows. The source maintains an internal `_running` flag and `_offsetTicks` value so that start, stop, and pause operations preserve the accumulated tick count correctly.

View File

@@ -0,0 +1,28 @@
# TickSourceOptionsSchema
Zod boundary schema for `TickSource` construction options.
## Purpose
Validates the options passed when constructing a `TickSource`.
## Features
- Optional `ppq` as positive integer
- Optional `bpm` as `Signal` instance
## Usage
```ts
import { TickSourceOptionsSchema } from "@suaveplan/audio-transport";
const parsed = TickSourceOptionsSchema.safeParse({ ppq: 96 });
```
## API Reference
- `TickSourceOptionsSchema` — `z.object({ ppq, bpm })`
## Implementation Notes
`bpm` uses `z.instanceof(Signal)` because the tick source needs the concrete `Signal` class for segment building.

View File

@@ -0,0 +1,59 @@
# Time Parsing and Conversion
This module parses musical time tokens and converts between ticks, seconds, and bars:beats:sixteenths notation.
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Musical time is expressed in many forms: subdivision notation, measure counts, bar positions, and raw seconds. `parseTimeToken` turns all of these into a canonical `{ ticks, seconds }` representation. The conversion helpers then provide round-tripping between ticks, seconds, and human-readable bar positions.
## Features
- Subdivision notation (`"4n"`, `"8n"`, `"16n"`, `"8t"`, `"16t"`)
- Measure notation (`"1m"`)
- Bars:beats:sixteenths (`"2:1:0"`)
- Relative seconds (`"+1"`)
- Absolute measures (`"@4m"`)
- Raw numeric ticks
- Bidirectional conversion helpers
## Usage: Basic
```ts
import { parseTimeToken } from "@suaveplan/audio-transport";
const ctx = { ppq: 192, timeSignature: 4, bpm: 120 };
const result = parseTimeToken("4n", ctx);
console.log(result.ticks); // 192
console.log(result.seconds); // 0.5
```
## Usage: Advanced
```ts
import {
parseTimeToken,
toBarsBeatsSixteenths,
fromBarsBeatsSixteenths,
} from "@suaveplan/audio-transport";
const ctx = { ppq: 192, timeSignature: 4, bpm: 120 };
const ticks = fromBarsBeatsSixteenths("1:2:3", ctx);
const bbs = toBarsBeatsSixteenths(ticks, ctx);
console.log(bbs); // "1:2:3"
```
## API Reference
- `parseTimeToken(token, ctx)` → `{ ticks, seconds }`
- `ticksToSeconds(ticks, ctx)` → `number`
- `secondsToTicks(seconds, ctx)` → `number`
- `toBarsBeatsSixteenths(ticks, ctx)` → `string`
- `fromBarsBeatsSixteenths(token, ctx)` → `number`
## Implementation Notes
All conversions assume constant tempo. `parseTimeToken` throws `AUDIO_TRANSPORT_INVALID_TIME` for unrecognised tokens. Numeric tokens are treated as raw ticks and returned directly. The regex-based parsers are ordered from most specific to least specific so that subdivision tokens are tried before relative tokens, avoiding ambiguity. The `bars:beats:sixteenths` format uses zero-based indexing for all three components. `toBarsBeatsSixteenths` floors each component rather than rounding, which is the conventional behaviour for DAW-style position displays. `fromBarsBeatsSixteenths` validates the input format with a strict regex and throws `AUDIO_TRANSPORT_INVALID_TIME` for malformed strings.

View File

@@ -0,0 +1,36 @@
# Time Schemas
Zod boundary schemas for time-related types.
## Purpose
Provides validation schemas for `TransportTime`, `Ticks`, `BarsBeatsSixteenths`, `TimeContext`, and `TimeParseResult`.
## Features
- `TransportTimeSchema` — string or non-negative number
- `TicksSchema` — non-negative number
- `BarsBeatsSixteenthsSchema` — regex `"bars:beats:sixteenths"`
- `TimeContextSchema` — `{ ppq, timeSignature, bpm }`
- `TimeParseResultSchema` — `{ ticks, seconds }`
## Usage
```ts
import { TransportTimeSchema } from "@suaveplan/audio-transport";
TransportTimeSchema.parse("4n");
TransportTimeSchema.parse(192);
```
## API Reference
- `TransportTimeSchema` — `z.union([z.string().min(1), z.number().nonnegative()])`
- `TicksSchema` — `z.number().nonnegative()`
- `BarsBeatsSixteenthsSchema` — `z.string().regex(/^(-?\d+):(-?\d+):(-?\d+)$/)`
- `TimeContextSchema` — `z.object({ ppq, timeSignature, bpm })`
- `TimeParseResultSchema` — `z.object({ ticks, seconds })`
## Implementation Notes
`TransportTimeSchema` accepts both string tokens and raw numeric ticks so that callers can pass either form interchangeably.

View File

@@ -0,0 +1,92 @@
# Transport
The `Transport` class is the core musical clock and scheduler. It manages playback state, event scheduling, loop regions, swing, and tempo automation.
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`Transport` provides a sample-accurate musical time base for audio applications. It converts between audio time (seconds) and musical ticks using a configurable PPQ and tempo curve, and it fires scheduled callbacks with sample-accurate times.
## Features
- Playback FSM with states `stopped`, `playing`, and `paused`
- Event scheduling: one-shot, repeat, and cancel
- Loop regions with automatic wrap and `loop` event
- Swing with configurable subdivision
- BPM automation via `Signal`
- Typed event bus (`start`, `stop`, `pause`, `loop`, `bpm`)
- Zod boundary validation on construction
- OpenTelemetry instrumentation for schedules and ticks
## Usage: Basic
```ts
import { Transport } from "@suaveplan/audio-transport";
const tr = new Transport({ bpm: 120, ppq: 192 });
const id = tr.scheduleOnce((time) => {
console.log("tick at", time);
}, "0:1:0");
tr.start();
```
## Usage: Advanced
```ts
import { Transport } from "@suaveplan/audio-transport";
const tr = new Transport({
bpm: 120,
ppq: 192,
loop: true,
loopStart: "0:0:0",
loopEnd: "1:0:0",
});
tr.on("loop", (time) => console.log("looped at", time));
tr.scheduleRepeat((time) => console.log("beat", time), "4n");
tr.start();
```
## API Reference
### Constructor
`new Transport(options?: TransportOptions)`
### Properties
- `bpm` — `SignalLike` with automation support
- `ppq` — pulses per quarter note (readonly)
- `timeSignature` — beats per measure (readonly)
- `swing` — value in `[0, 1]`
- `swingSubdivision` — `"8n"` or `"16n"`
- `loop` — boolean
- `loopStart` / `loopEnd` — `TransportTime`
- `state` — `"stopped" | "playing" | "paused"`
- `position` — `BarsBeatsSixteenths` string
- `ticks` — current tick count
- `seconds` — current clock time
### Methods
- `start(time?, offset?)` — start or resume playback
- `stop(time?)` — stop playback
- `pause(time?)` — pause playback
- `schedule(callback, time)` — schedule a one-shot callback
- `scheduleOnce(callback, time)` — schedule and auto-remove
- `scheduleRepeat(callback, interval, start?)` — repeating callback
- `cancel(eventId)` — remove a scheduled event
- `cancelAfter(time)` — remove events at or after time
- `toSeconds(time)` — convert token to seconds
- `toTicks(time)` — convert token to ticks
- `dispose()` — tear down
- `on(event, listener)` / `off(event, listener)` — event bus
## Implementation Notes
The constructor validates options via `TransportOptionsSchema`. All wall-clock reads go through the injected `Clock`. The default clock is `() => 0` to preserve universal purity.

View File

@@ -0,0 +1,33 @@
# TransportOptionsSchema
Zod boundary schema for `Transport` construction options.
## Purpose
Every public entry point validates its options before use. `TransportOptionsSchema` defines the shape, types, and constraints accepted by the `Transport` constructor.
## Features
- Validates `bpm`, `ppq`, `swing`, `timeSignature` as positive numbers
- Validates `loop` as boolean
- Accepts `loopStart`, `loopEnd`, `swingSubdivision` as string or number
- Accepts `clock` as a function returning `number`
## Usage
```ts
import { TransportOptionsSchema } from "@suaveplan/audio-transport";
const parsed = TransportOptionsSchema.safeParse({ ppq: 192 });
if (!parsed.success) {
console.error(parsed.error.issues);
}
```
## API Reference
- `TransportOptionsSchema` — `z.object({ bpm, ppq, swing, swingSubdivision, timeSignature, loop, loopStart, loopEnd, clock, logger })`
## Implementation Notes
The schema is used inside `validateOptions` in `transport.ts`. A parse failure throws `TransportError` with code `AUDIO_TRANSPORT_INVALID_TIME`.