← Motion modes and chip-side reactivity

SIREN / compact envelopes / CPU-first prototype

Keep the gesture.
Squeeze the bytes.

How many heights does a dip need? How many bits does a swell deserve? Turn the knobs and watch the piano's eight envelopes survive — or lose their personality.

Curve budget · Inside the packed bytes · A tiny envelope program · The 600 Hz route

Storage and playback are separate. Eight stored heights can describe a curve that the CPU evaluates thousands of times. A smaller instrument does not require a slower control clock.

Loading the piano curves…

Listen to the native 16-point, 4-bit rounded player → A fixed version of these defaults now runs in FANCO at 600 Hz, including the exponential tail. Complete program: 1,109 bytes. The controls below explore descriptors; they do not change that published sound.

01 / Three independent budgets

Points. Precision. Playback.

The white line is the current 440-reduced piano envelope. Green is reconstructed from the actual packed bytes. Orange shows that curve sampled by the CPU and held by the existing chip between updates.

Try a budget:
—shape bytes · all eight partials
—descriptor bytes · peaks, decay + header included
—CPU vector writes · through final silence
Current curveDecoded compact curveCPU-held gain

All eight envelopes with these settings

02 / Nothing up the sleeve

Count every byte.

The diagram is drawn after encoding and decoding the descriptor. The time grid is generated from its header; no list of timestamps or large expansion table is stored.

Part Contents Bytes
Header Version, modes, count, duration, time expansion, log range 8
Partial peaks Eight 12-bit gain peaks 12
Exponential tails Eight response bytes · mode 11 + six-bit T₉₀ 8
Curve heights — —
Total One eight-partial envelope descriptor —

These are envelope bytes, not the whole instrument. Frequencies, pan, hammer, reverb, decoder code, and moving CPU state are separate. If a bank shares timing and peak rules, some overhead can be amortized; it is counted here rather than hidden.

Download these exact bytes

Inspect the packed descriptor

Little-endian fields and least-significant-bit-first packing. Version byte 0 = 2. Byte 1: precision index in bits 0–1; log encoding bit 2; expanding time bit 3; S-curve bit 4; log interpolation bit 5. Bytes 2–3: destination count. Bytes 4–5: shape-to-decay handoff in 600 Hz ticks. Byte 6: expansion × 10. Byte 7: log range in dB. Next 12 bytes: eight packed 12-bit peaks. Next 8 bytes: exponential response bytes, 11qqqqqq, with T₉₀ = 2^(q/5)/600 seconds. Remaining bytes: destination-major heights, eight per row. Version 1 downloads remain decodable with their original final-zero behavior.


          

The preview shows up to 256 bytes; the download includes the complete descriptor.

Decoded destinations for this partial
Point Time Packed code Gain / peak dB
Decoded decay settings — included in the download
Partial Response byte T₉₀ Handoff gain / peak Silence by

The last point starts the tail

gain(t) = lastGain · 10^(-(t − handoff) / T₉₀)

The tail starts at the final landmark's level and keeps falling. S-curves shape the stored body; they do not ease the ending into an artificial zero. T₉₀ is fitted from the last 1.5 seconds before handoff. A flat or rising ending uses the broader decay trend, then an 8-second fallback. Response times round to the six-bit time code, whose longest value is about 10.35 s.

The moving value keeps fractional precision. Once it drops below half a mixer-gain unit, it becomes exact zero. That prevents a tiny integer gain from getting stuck forever. A tail already below that threshold is silent immediately. A zero endpoint needs no decay work.

Why log heights?

With 4-bit linear heights, the smallest nonzero value is 1/15 of peak — about −23.5 dB. Much of a piano's tail falls below that. Log heights distribute codes across the selected dB range instead, with one reserved silence code.

For 4 bits and 60 dB, the 15 nonzero codes are about 4.29 dB apart. More bits reduce the height error; more points capture extra bends. Neither substitutes for the other.

Why expanding time?

Uniformly storing eight points over eight seconds misses the whole strike. An exponential time warp spends points near the beginning and gradually widens the intervals.

t(k) = T · expm1(a · k/K) / expm1(a) k = 1…K; t(0) = 0

a = 0 gives uniform spacing. Times land on 600 Hz ticks and are kept strictly increasing. Changing the expansion moves detail between attack and tail.

03 / Store behavior instead of a trail of heights

A tiny envelope program.

A second format can describe changes of motion. Instead of spending a new height on every segment, keep moving toward the same target and change the rule when it matters.

Tick Instruction Meaning
0 · 0 ms S-curve → 1.0, duration 12 ticks A rounded 20 ms rise
1 · 1.667 ms Linear; keep target and deadline Continue from the current height toward 1.0 at 20 ms
4 · 6.667 ms Exponential; T₉₀ = 5 ms Keep heading toward 1.0, now closing 90% of the gap every 5 ms
Green is the continuous path defined by the three instructions. Orange is its 600 Hz CPU-held version. Switching motion preserves the current height; a change of slope is allowed.

“Keep target” is not “hold”

Keep target preserves the destination and continues moving. Hold captures the current height and stops. Mode changes rebase from the current value, not the old segment start. An exponential mode uses settling time instead of an arrival deadline.

Compact event encoding

A delta tick and a field mask can say which fields change. A mode-only event need not repeat target or duration. All partials can share a motion script while keeping their own heights and decay parameters.

The example is a behavior proposal, separate from the packed-height format above. It is not included in that descriptor's byte count.

04 / Use the chip we already have

600 Hz is a practical bridge.

A CPU routine can keep a small amount of state per envelope, read the next compact destination when needed, and calculate intermediate gains at the existing 600 Hz latch cadence. The SIREN synthesizer still generates audio at 48 kHz.

What gets cheaper

The stored shape can shrink from 30,720 bytes to a small descriptor. There is no need to expand eight seconds of values in RAM. Linear motion is incremental addition; exponential following can use a precomputed multiplier; an S-curve can use cubic forward differences.

Those arithmetic rules can be adapted to fixed point for the guest CPU. Log-domain ramps need domain conversion, so gain-space linear ramps are the simplest first player.

What still costs work

At 600 Hz, eight gains require 4,800 lane evaluations per second, versus 1,920 at the current 240 Hz. Over eight seconds that is 4,800 vector updates and 38,400 gain writes. A smaller file is not proof of fewer guest instructions.

At 48 kHz, each 600 Hz gain value lasts 80 audio samples. The orange line shows these held steps and the current 12-bit mixer gain rounding. A later audio-rate smoother could remove that last staircase if listening finds it matters.

Choose the description first. CPU interpolation lets us audition compact curves with no chipset changes. Chip-side motion remains an option if reducing CPU traffic or smoothing the final sample steps earns its place.

The curves here use the existing 240 Hz parameter snapshot, joined linearly as the reference. This page packs, decodes, and draws envelopes in the browser; it does not alter the listening programs or run a guest CPU player. No audio autoplay.