Device API
The methods a device implements, the manifest it declares, and the process context.A device extends Device and registers itself once at module top level:
import {
Device,
Manifest,
Ctx,
register,
} from "@msh/device-sdk/device/assembly";
class MyDevice extends Device {
describe(): Manifest {
/* ... */
}
process(ctx: Ctx): void {
/* ... */
}
}
register(new MyDevice());Below are its methods, what you declare in the manifest, and everything on ctx.
Device methods
Only describe and process are required. Everything else has a default.
| Method | When it runs | Purpose |
|---|---|---|
describe(): Manifest | Once, on load | Declare controls and ports. Required. |
prepare(sampleRate: f64, maxBlock: i32): void | Before audio, and on format change | Allocate filters, buffers, LUTs. |
process(ctx: Ctx): void | Once per block, on the audio thread | Process the sound. Required. |
processSpectrum(frame: SpectralFrame, ctx: Ctx): void | Once per STFT hop | Edit the spectrum when using Spectral. See DSP blocks. |
getState(): Uint8Array | On save and before hot-reload | Return bytes to persist. |
setState(bytes: Uint8Array): void | On load and after hot-reload | Restore from saved bytes. |
onCommand(id, event, ctx): void | A button or canvas command region | React to a UI command. See Control surface. |
onParamChanged(index, ctx): void | A discrete param edit | Build macros and linked params. See Control surface. |
onAsset(slot, ctx): void | After a requested file/sample is installed | Decode the asset (loadAsset / decodeWav) once it is available. |
onCommand and onParamChanged run off the audio thread and take a ControlCtx,
not a Ctx. Allocation and branching are fine there.
Manifest
Build it in describe, chaining calls, then return it. Each call returns the
manifest so they chain.
| Call | Purpose |
|---|---|
addParam(def) | Add a modulatable control. See Parameters. |
addSetting(def) | Add a non-modulatable setting (same ParamDef, no depth wheel). |
addPort(port) | Add an audio, MIDI, or modulation plug. See Ports. |
channel(name, size, role) | Declare a live display feed. Roles: CHANNEL_SPECTRUM, CHANNEL_SPECTRUM_POST, CHANNEL_CURVE. |
meter(name, segments) | Declare a scalar DSP-to-UI readout, updated with ctx.setMeter(idx, value). |
curveParam(id, name, size, defaultPoints) | Declare a user-drawable curve, read with ctx.curve(idx, x). size defaults to 256; defaultPoints (from curvePoint(x, y, power)) sets the starting shape and the resetCurve target. |
bucket(name, shape, dim0, dim1, format, transport) | Declare a realtime data bucket for a shader. See Data buckets. |
texture(name, w, h, format) | A 2D bucket. See Data buckets. |
ring(name, w, frames, format) | A scrolling-history bucket. See Data buckets. |
array(name, len, format) | A flat 1D bucket. See Data buckets. |
latency(samples) | Report any delay the device adds, for delay compensation. |
state(maxBytes) | Reserve room for getState / setState. 0 (default) means stateless. |
gpuAudioData(floats) | Reserve the per-block CPU-to-GPU payload for a GPU audio stage. |
gpuAnalysis(floats) | Reserve GPU-to-CPU analysis readback. |
gpuStatic(floats) / gpuState(floats) | Reserve bulk read-only GPU data / grow GPU persistent state. |
gpuParamRamps([ids]) / gpuPipelineDepth(n) | Stream params to the GPU as per-sample ramps / set pipeline depth (1-4). |
The gpu* builders pair with a gpuAudio.ts program. See GPU
audio.
The process context (ctx)
ctx is a typed, per-sample view handed to process. Members marked as a call
(()) are methods; the rest are fields.
Block and audio
| Member | Returns | Meaning |
|---|---|---|
ctx.n | i32 | Samples in this block. |
ctx.sampleRate | f64 | Current sample rate. |
ctx.inChannels() / ctx.outChannels() | i32 | Channel counts. Loop to these, don't hardcode 2. |
ctx.input(ch, i) | f32 | Read an input sample. In-bounds for ch < inChannels(). |
ctx.output(ch, i, v) | Write an output sample. | |
ctx.inPtr(ch) / ctx.outPtr(ch) | i32 | Byte pointer to a channel's sample plane (for block-oriented DSP). |
Parameters and modulation
| Member | Returns | Meaning |
|---|---|---|
ctx.param(idx) | f32 | A param's value, no modulation. |
ctx.modulatedParam(idx, i) | f32 | A param's per-sample value with modulation folded in. Read this for anything modulatable. |
ctx.paramIndex(id) | i32 | Resolve a param's index by name. Call in prepare, cache it. -1 if absent. |
ctx.modActive(ord) | bool | Is a raw modulation source connected on ordinal ord? |
ctx.mod(ord, i) | f32 | A raw modulation source's per-sample value, 0..1. |
idx is the order you declared params in describe, starting at 0. Resolve by
name with paramIndex so reordering can't silently read the wrong param.
MIDI
See MIDI for the full typed surface
(ctx.midiEvent, ctx.noteOn, ctx.cc, and the rest). The raw accessors:
| Member | Returns | Meaning |
|---|---|---|
ctx.midiInCount() | i32 | Incoming events this block. |
ctx.midiInOffset(e) | i32 | Event e's sample offset. |
ctx.midiInByte(e, b) | i32 | Byte b of event e (0 = status, 1 = note, 2 = velocity). |
ctx.emitMidi(offset, status, d1, d2) | Send a MIDI event. 0x90 = note on, 0x80 = note off. |
Modulation and display output
| Member | Meaning |
|---|---|
ctx.modOut(i, value) | Write this device's primary modulation output (needs a modulationOut port). |
ctx.modOutAt(out, i, value) | Write modulation output out (declared modulationOut ports in order, 0 = the primary). |
ctx.writeChannel(idx, data) | Fill a display channel (data is a Float32Array). Once per block. |
ctx.setMeter(idx, value) | Push a scalar to a m.meter readout. |
ctx.writeBucket(idx, data) | Fill a data bucket from f32s (32-bit formats and ring rows). See Data buckets. |
ctx.writeBucketBytes(idx, bytes) | Fill a bucket from pre-packed bytes (half/byte formats). |
ctx.curve(idx, x) | Read a drawn curve at x (0 to 1). Safe per sample. |
Transport
| Member | Returns | Meaning |
|---|---|---|
ctx.tempo() | f64 | Tempo in BPM, 0 when stopped. |
ctx.isPlaying() | bool | Is the transport running? |
ctx.ppqPosition() | f64 | Song position in quarter notes. |
ctx.bar() / ctx.beat() | i32 | Current bar and beat within the bar (0-based). |
ctx.beatPhase() | f64 | Progress through the current beat, 0 to 1. |
ctx.timeSigNumerator() / ctx.timeSigDenominator() | i32 | Time signature, 0 if unknown. |
Scale and key
| Member | Returns | Meaning |
|---|---|---|
ctx.meshKey() / ctx.meshScaleMask() | i32 | The mesh's key (pitch class 0-11) and 12-bit scale mask. |
ctx.globalKey() / ctx.globalScaleMask() | i32 | The session override key and scale mask. |
ctx.noteInScale(note, mask) | bool | Is a note's pitch class in the given scale mask? |
ctx.meshScale() / ctx.globalScale() | Scale | Build a Scale from the project key/scale (allocates: call in prepare). See Harmony. |
Runtime reconfiguration
| Member | Meaning |
|---|---|
ctx.setLatency(samples) | Re-report latency when it changes (e.g. FFT size). Declare the max in m.latency. |
ctx.setPorts(audioIn, audioOut, midiIn, midiOut, modOut) | Activate the first N of each declared port. Call when the active set changes, not every block. |
GPU audio
For a device with a gpuAudio.ts compute post-stage. Full detail in GPU
audio.
| Member | Meaning |
|---|---|
ctx.writeGpuAudioData(i, v) | Write slot i of the per-block CPU-to-GPU payload (m.gpuAudioData). |
ctx.gpuAnalysis(i) / ctx.gpuAnalysisCount() | Read back a GPU analysis result and its length (m.gpuAnalysis). |
ctx.setGpuDispatch(pass, threads) | Set a dynamic pass's per-block thread count. |
ctx.gpuActive | true while the GPU stage runs this session. Fall back to CPU DSP when false. |
Assets
Bundle a file with the device, or ask the user for one, and read it on the audio
thread. Request from a ControlCtx (inside an on* handler), then decode in
onAsset once it lands.
| Member | Meaning |
|---|---|
ctx.requestFile(slot) / ctx.requestSample(slot) | On a ControlCtx: prompt the user for a file / audio sample into slot. |
loadAsset(name) | Read a bundled asset's bytes as a Uint8Array. |
pickedAssetName(slot) | The file name the user picked for slot, or empty. |
decodeWav(bytes) | Decode WAV bytes to a WavAudio (planar f32 channels). |