@miadi/capture
v0.2.6
Published
The capture core abstracted from gmtermux — a take lifecycle state machine over a pluggable capture driver, one TLID naming rule, provenance that survives a restart, and streamed sha256 for the bytes themselves. A take is durable before it belongs to anyt
Readme
@miadi/capture
Record a take from a device and keep its provenance: when it started, how long it ran, what recorded it, and whether it can ever be made again.
In the Miadi stack, this is where the evidence of a working session begins: the audio, video or MIDI captured while the work happened. It owns the take lifecycle (start, pause, resume, stop), one naming rule, and a provenance sidecar that survives the process that recorded it. It does not know what a microphone is: a driver you supply owns the device.
A capture is any take a device makes in one unrepeatable instant. Kinds:
audio | video | midi | other. The lifecycle, the naming rule and the sidecar are the same for
every kind.
Works with:
@miadi/episodic-memory-schema: the vocabulary (CaptureProvenance,ArtifactOrigin,ArtifactReference), consumed and never re-declared.@miadi/capture-clientand@miadi/capture-service: the HTTP envelope and the service that puts this package behind it.@miadi/episode-capture: files a finished take into an episode.
What this package owns
Recorder— start / pause / resume / stop with lossless segment join. Context freezes atstart(); every failure leaves more than nothing (graded degradation): a join that cannot happen retains its segments and the recorder stays paused.- TLID —
YYMMDDHHMMSS, the take's local-instant name, in one place. TakeStore— the flat take library plus a<take>.take.jsonprovenance sidecar, closing the defect where provenance lived only in process memory and degraded to file mtime after a restart.CapturePairController(@miadi/capture/pair) — two captures, sound and movement, started and stopped as one take. It stops every channel that started, waits through their processing, and settlescomplete,partialorfailedwithout discarding a sibling that succeeded. Adapters own the devices; the controller imports nothing, so a browser page runs it.CaptureDriver/SegmentJoiner— the device seam. Termux, ALSA, or any host that owns a capture device implements these; the lifecycle never learns which.
What this package refuses to own
- Association. A take is durable before it belongs to anything. Binding a
take to a musical-composition is the studio domain's act
(
@miadi/musical-composition); binding to a chronicle episode belongs to@miadi/inquiry-weave/@miadi/musical-composition-to-episode. This package only guarantees there is something whole to associate, andtoArtifactReference()to speak the episode vocabulary when asked. - Transport. The HTTP envelope lives in
@miadi/capture-client. - Bytes at rest beyond the library directory. Registries (medicine-wheel's capture records) hold records and URIs, never media.
The origin law
A take is captured: a device, an instant, one chance — irreplaceable. Its
transcription is derived — regenerable for exactly as long as the voice is
kept. TakeStore.readTakeRecord refuses a sidecar whose origin fails the
guard rather than defaulting it, because defaulting to derived marks an
unrepeatable take safe to delete.
Example
import { Recorder, TakeStore } from "@miadi/capture"
const store = new TakeStore(process.env.CAPTURES_DIR ?? "./captures")
const recorder = new Recorder({
driver: platformDriver, // your CaptureDriver
joiner: ffmpegJoiner, // your lossless SegmentJoiner
recordingsDir: store.dir,
device: "larix",
})
await recorder.start({ composition: "ep097-ceremony" }) // context freezes here
await recorder.pause()
await recorder.resume()
const take = await recorder.stop() // provenance: startedAt, duration, bytes, device
await store.recordCompletedTake(take) // provenance now survives a restart