These inline and need no construction. They import from @msh/device-sdk/device/assembly and are
real-time safe, so they run in process. The curve set is also importable in paint.ts
from @msh/device-sdk/device/assembly/paint, so DSP and canvas draw identical curves.
Math
| Function | Returns |
|---|
dbToGain(db) | Decibels to linear gain. |
gainToDb(g) | Linear gain to decibels. |
tanhFast(x) | Cheap tanh approximation for soft saturation. |
softClip(x) | Cubic soft clip (linear near zero, saturating toward ±2/3). |
hardClip(x) | Hard clip to [-1, 1]. |
evalPowerCurve(progress, curve) | Vital-style power-curve shaper, curve in [-1, 1]. |
Curve, interpolation, easing
| Function | Returns |
|---|
clamp01(x) | Clamp to [0, 1]. |
clampf(x, lo, hi) | Clamp to [lo, hi]. |
lerp(a, b, t) | Linear interpolation (t unclamped). |
unlerp(a, b, v) | Where v sits in [a, b] as a 0..1 fraction. |
smoothstep(t) | Hermite smoothstep 3t²−2t³ (t clamped). |
smootherstep(t) | Perlin smootherstep 6t⁵−15t⁴+10t³ (t clamped). |
shapePower(t, power) | Power-curve shape (parity with the on-screen CurveEditor). |
powerCurve(t, y0, y1, power) | Interpolate y0→y1 along the power-curve shape. |
bias(t, b) | Schlick bias: b in (0,1), 0.5 linear; pushes mass toward 0 or 1. |
gain(t, g) | Schlick gain: g in (0,1), 0.5 linear; S-curve or inverse-S. |
easeInExpo(t) / easeOutExpo(t) | Exponential ease-in / ease-out. |
easeInOutSine(t) / easeInOutCubic(t) | Sine / cubic ease-in-out. |
catmullRom(y0, y1, y2, y3, t) | Catmull-Rom cubic between y1 and y2 (the sweet spot for variable-rate buffer reads). |
hermite(p0, m0, p1, m1, t) | Cubic Hermite between p0, p1 with tangents m0, m1. |
tanhApprox(x) | Padé tanh, pure and cheap (for canvas paint, where tanhFast isn't available). |
evalCurvePoints(xs, ys, powers, count, x) | Evaluate a piecewise power curve from sorted control points. |
CurveLut
Bake a curve once, then sample it O(1) per call with no pow() in the hot loop. Backed
by a StaticArray<f32> of evenly spaced samples over x in [0, 1].
let lut: CurveLut;
prepare(sampleRate: f64, maxBlock: i32): void {
lut = new CurveLut(256);
lut.bakePower(0.5);
}
| Method | Does |
|---|
new CurveLut(size) | Allocate a LUT of size samples (min 2). |
bakePower(power) | Bake a single power curve (y rises 0→1). |
bakeFn(fn) | Bake from an arbitrary f(x), x in [0, 1]. |
bakePoints(xs, ys, powers, count) | Bake a piecewise curve from control points. |
sample(x) | Sample at x in [0, 1], clamped and linearly interpolated. |
data() / size() | The backing array / its length. |
Mixing
| Function | Returns |
|---|
crossfade(dry, wet, amt) | Linear crossfade: amt 0 → dry, 1 → wet. |
mixParam(id?, name?) | A ready-made 0..1 modulatable "Mix" param (percent knob). |
Pair them: crossfade(dry, wet, ctx.modulatedParam(mixIdx, i)).
Persistent state
Pack and unpack m.state bytes without manual offset math. StateWriter writes a version
tag first; StateReader reads it back so older saves keep loading. See
Parameters for declaring state.
getState(): Uint8Array {
const w = new StateWriter(1, 64);
w.i32(this.steps);
w.f32(this.rate);
return w.bytes();
}
setState(bytes: Uint8Array): void {
const r = new StateReader(bytes);
this.steps = r.i32();
if (r.version >= 1) this.rate = r.f32();
}
StateWriter | Does |
|---|
new StateWriter(version, capacity) | Allocate a buffer (writes the version tag). |
u8(v) / i32(v) / f32(v) / f64(v) | Append a field. |
bytes() | The bytes written so far (return from getState). |
StateReader | Does |
|---|
new StateReader(bytes) | Read the version tag (exposed as version). |
u8() / i32() / f32() / f64() | Pull the next field, in write order. |
remaining() | Bytes left unread (guard newer fields with it). |
Notes
- Use the
Mathf namespace (Mathf.sqrt, Mathf.pow, Mathf.sin, ...) in hot loops. It
takes and returns f32 directly, with no f64 round-trip. - Size fixed buffers as
StaticArray<T> allocated in prepare. Release builds strip array
bounds checks, so keep loop bounds derived from the sizes you allocated.
For audio DSP blocks see DSP blocks; for
oscillators, envelopes, and meters see
Synth blocks.