Confirmed — the mod matrix documents a clamping contract the voice builder half-implements
src/core/audio/modMatrix.ts:12-13 states the contract explicitly:
The result for a target is Σ(sourceValue × amount) over its routes, left un-clamped so the voice builder can clamp against each target's own range.
The voice builder honours that for two of the four targets it consumes.
Clamped, correctly — src/core/audio/voicePool.ts:252-257:
filter.frequency.value = clamp(
spec.filter!.cutoff * stat.cutoffFactor,
FILTER_CUTOFF_RANGE[0],
FILTER_CUTOFF_RANGE[1],
);
filter.Q.value = clamp(spec.filter!.resonance, FILTER_RESONANCE_RANGE[0], FILTER_RESONANCE_RANGE[1]);
Not clamped — voicePool.ts:242 then :276:
const baseDetune = spec.tuneSemitones * 100 + spec.tuneCents + stat.detuneCents;
...
source.detune.value = baseDetune;
Not clamped — voicePool.ts:280:
const peak = velocityToGain(spec.velocity, spec.gainDb) * stat.ampFactor;
scheduleAmpAttack(ampGain.gain, peak, spec.amp, now);
Nothing upstream constrains the sum. ranges.ts:61 sets MAX_MOD_ROUTES = 32, program.ts:143 and :178 validate z.array(modRouteSchema).max(MAX_MOD_ROUTES), each route's amount is −1..1 — and nothing forbids all 32 routes targeting the same destination. §6 likewise caps the matrix at 32 routes without constraining per-target totals.
Measured:
| Program |
Result |
32 × {source:'velocity', target:'pitch', amount:1} at velocity 127 |
detuneCents = 38400 → 32 octaves up → playbackRate ×2³² → the buffer is consumed instantly |
32 × {source:'velocity', target:'amp', amount:1} |
ampFactor = 33 → peak gain 33× → hard clipping |
Consequence. A pad that either makes no sound (a click as the buffer is exhausted in a fraction of a millisecond) or is grossly distorted, with no error anywhere. The relevant clamps already exist and are used elsewhere — TUNE_SEMITONES_RANGE is [-36, 36] and LEVEL_RANGE is [0, 1.2].
Reachability matters here. This is not only a hand-authored-program concern: a .mpcweb pack is external content (§9.6) that is Zod-validated on import, and such a program passes validation. So an imported pack — the mechanism §9.8 intends to use for shipping factory content — can produce silent or clipping pads.
Suggested fix: clamp both at the point of use in voicePool.ts, matching the two lines above, so the module contract modMatrix.ts documents is actually met for all four targets. Alternatively tighten the schema to bound per-target route sums, but the per-target clamp is simpler and is what the code already says it does.
Coverage context
modMatrix.test.ts and voiceModulation.test.ts only ever use one or two routes per target, so the summing overflow is never exercised. A test with routes summing past each target's range — for all four targets, asserting the clamp — closes this and documents the contract.
Confirmed — the mod matrix documents a clamping contract the voice builder half-implements
src/core/audio/modMatrix.ts:12-13states the contract explicitly:The voice builder honours that for two of the four targets it consumes.
Clamped, correctly —
src/core/audio/voicePool.ts:252-257:Not clamped —
voicePool.ts:242then:276:Not clamped —
voicePool.ts:280:Nothing upstream constrains the sum.
ranges.ts:61setsMAX_MOD_ROUTES = 32,program.ts:143and:178validatez.array(modRouteSchema).max(MAX_MOD_ROUTES), each route'samountis −1..1 — and nothing forbids all 32 routes targeting the same destination. §6 likewise caps the matrix at 32 routes without constraining per-target totals.Measured:
{source:'velocity', target:'pitch', amount:1}at velocity 127detuneCents = 38400→ 32 octaves up →playbackRate×2³² → the buffer is consumed instantly{source:'velocity', target:'amp', amount:1}ampFactor = 33→ peak gain 33× → hard clippingConsequence. A pad that either makes no sound (a click as the buffer is exhausted in a fraction of a millisecond) or is grossly distorted, with no error anywhere. The relevant clamps already exist and are used elsewhere —
TUNE_SEMITONES_RANGEis[-36, 36]andLEVEL_RANGEis[0, 1.2].Reachability matters here. This is not only a hand-authored-program concern: a
.mpcwebpack is external content (§9.6) that is Zod-validated on import, and such a program passes validation. So an imported pack — the mechanism §9.8 intends to use for shipping factory content — can produce silent or clipping pads.Suggested fix: clamp both at the point of use in
voicePool.ts, matching the two lines above, so the module contractmodMatrix.tsdocuments is actually met for all four targets. Alternatively tighten the schema to bound per-target route sums, but the per-target clamp is simpler and is what the code already says it does.Coverage context
modMatrix.test.tsandvoiceModulation.test.tsonly ever use one or two routes per target, so the summing overflow is never exercised. A test with routes summing past each target's range — for all four targets, asserting the clamp — closes this and documents the contract.