analoglogicmaths
analogLogicMaths · utilitiesAnalog-logic mixer inspired by Mystic Instruments ANA (hardware-only — this is a from-spec implementation, not a port). Two continuous-signal inputs A and B feed bipolar attenuverters (-1..+1) and the post-attenuverter signals fan out into FIVE simultaneous algebraic outputs: MIN = min(A',B'), MAX = max(A',B'), DIFF = A'-B', SUM = tanh(A'+B') (soft-clipped), PRODUCT = tanh(A'*B') (soft-clipped, gives ring-mod-ish behavior for audio + smooth blending for CV). MIN/MAX of two waveforms mashes shapes; MAX of two envelopes = "either-trigger fires"; DIFF of two LFOs is anti-correlated motion; PRODUCT of two CVs is smooth blending. Continuous-signal "analog logic" — NOT the digital boolean logic that ILLOGIC ships. Tanh soft-clip on SUM + PRODUCT only (the operations that can leave [-1, +1]); MIN/MAX/DIFF stay bounded naturally.
the faceplate
inputs
| id | cable | what it does |
|---|---|---|
a | cv | Input A (bipolar CV or audio). Scaled by the ATT A attenuverter before feeding all five math operations. control voltage (CV) |
b | cv | Input B (bipolar CV or audio). Scaled by the ATT B attenuverter before the math. control voltage (CV) |
attA_cv | cv | CV control over the ATT A attenuverter knob — patch an LFO or envelope here to sweep how much of input A reaches the outputs. It ADDS to the knob's position and the sum is clamped to the knob's own -1..+1 range. ⚠ AT THE SHIPPED DEFAULT THIS INPUT IS HALF-DEAD: ATT A ships at +1, which IS the top of that range, so a positive CV of any size — +1, +5, anything — changes the output by bit-exactly zero, and a bipolar LFO patched here is half-wave rectified (measured). Turn ATT A down to give the cable room: from a knob at 0, a +0.5 CV lands exactly where the knob at +0.5 does. control voltage (CV); modulates attA (additive offset — ±1 CV sweeps the full range, centered on the knob) |
attB_cv | cv | CV control over the ATT B attenuverter knob — sweep how much of input B reaches the outputs. Adds to the knob and clamps to -1..+1, with the same half-dead-at-the-default behaviour as ATT A CV: at the shipped +1 only the downward half of a bipolar CV does anything. control voltage (CV); modulates attB (additive offset — ±1 CV sweeps the full range, centered on the knob) |
outputs
| id | cable | what it does |
|---|---|---|
min | cv | The sample-wise minimum of the two attenuverted inputs, min(A', B') — follows whichever signal is lower at each moment. ⚠ WITH INPUT B UNPATCHED THIS IS A HALF-WAVE RECTIFIER: the missing input reads 0, so min(A', 0) passes only the NEGATIVE half of A and holds 0 for the rest (measured — a 0.8 sine on A alone leaves MIN swinging -0.80 to 0.00). Useful, and not what the label suggests. control voltage (CV) |
max | cv | The sample-wise maximum, max(A', B') — follows whichever signal is higher; MAX of two envelopes acts as an OR-style 'either triggers'. ⚠ WITH INPUT B UNPATCHED IT IS THE OPPOSITE HALF-WAVE RECTIFIER to MIN: max(A', 0) passes only the POSITIVE half of A. MIN and MAX together therefore give a free full-wave pair off one input. control voltage (CV) |
diff | cv | The signed difference A' - B' — zero when the two match, swinging positive or negative as they diverge. ⚠ THE ONLY JACK ON THIS MODULE THAT CAN LEAVE THE ±1 RAIL, and the only one with NO soft-clip. Its worst case is |ATT A| + |ATT B| — ×2.00 at the shipped defaults on a bus whose convention is ±1, reached whenever the two inputs are anti-phase, and a modest 0.9 / -0.9 pair already reads 1.80 (measured). SUM and PRODUCT are held under 1 by their tanh and MIN/MAX cannot exceed their own inputs, so this is the jack to attenuate downstream; the faceplate prints its live ceiling as `peak`. ⚠ AND AT THE SHIPPED DEFAULTS IT IS A COMMON-MODE NULL: its gain on a signal present at BOTH inputs is ATT A - ATT B = 0.00 with both dials at +1, so patching one CV into both jacks leaves DIFF silent until you unbalance a dial — which is what makes it a difference-taker rather than a second mixer. The faceplate prints that gain live as `diff`. control voltage (CV) |
sum | cv | The sum A' + B' run through a tanh soft-clipper, so it stays within ±1 and saturates instead of hard-clipping when both inputs are loud. ⚠ IT IS A SATURATOR, NOT A MIXER, AND THE KNEE IS LOW. Against the un-clipped sum: -0.11 dB at ±0.1 in each input, -0.68 dB at ±0.25, -0.96 dB at ±0.3, -1.62 dB at ±0.4 (the 1 dB crossing is between those two), -2.37 dB at ±0.5, -6.34 dB at full scale and -12.05 dB for two ±2 sources (measured on the shipping worklet). So two dials reading +1 have a nameplate gain of ×2.00 and deliver ×0.96, and the compression is a JOIN over BOTH dials — with ATT B at 0 the same full-scale input compresses by only -2.37 dB. The faceplate prints the live figure as `sum`, beside a `peak` of ×2.00; the gap between them IS the tanh. control voltage (CV) |
product | cv | The product A' × B' through a tanh soft-clip: ring modulation for two audio inputs, or a smooth multiplicative blend for two CVs. ⚠ THE SOFT-CLIP HERE PROTECTS NOTHING FOR IN-RANGE MATERIAL — |A' × B'| can never exceed 1 when both inputs are inside ±1, so the tanh is a fixed -2.37 dB of soft distortion at the corner rather than a limiter (it only starts limiting for over-range sources; two ±2 inputs compress by -12.05 dB). It is the module's shipped voice and is left alone. ⚠ IT IS ALSO THE ONE JACK THAT NEEDS BOTH INPUTS: with either input unpatched it is bit-exactly silent, and it is the only place the two dials MULTIPLY rather than add — halve both and this quarters. The faceplate prints its gain as `ring`. control voltage (CV) |
params
| id | label | range | default | curve |
|---|---|---|---|---|
attA | Att A | -1..1 | 1 | linear |
attB | Att B | -1..1 | 1 | linear |
controls
| control | what it does |
|---|---|
| Att A | Bipolar attenuverter for input A (-1 to +1, default +1): +1 passes A through, 0 removes it from the math, negative values invert its sign. The ATT A CV input adds to this position and is clamped with it. ⚠ IT REACHES ALL FIVE JACKS, AND ITS SIGN IS THE ONE ASYMMETRY BETWEEN THE TWO DIALS: DIFF is A' - B', so ATT A enters every jack with the polarity the panel implies while ATT B inverts that one. ⚠ IT IS ALSO NOT A LEVEL CONTROL ON SUM: because SUM saturates, turning this dial from +0.5 to +1 with a full-scale input moves SUM by 0.20, not by 0.48. ⚠ AND A LEVEL METER CANNOT SEE HALF OF WHAT IT DOES — -1 and +1 differ only in SIGN, so ATT A's rms and peak on MIN/MAX are identical at both ends of the dial while DIFF and PRODUCT invert. |
| Att B | Bipolar attenuverter for input B (-1 to +1, default +1): +1 passes B, 0 removes it, negative inverts. The ATT B CV input adds to this position and is clamped with it. ⚠ THE TWO DIALS ARE NOT INTERCHANGEABLE, in exactly one respect: SUM, PRODUCT, MIN and MAX are symmetric in A and B, but DIFF subtracts this channel, so swapping the two dial positions moves DIFF and nothing else. That is also why inverting this dial turns the DIFF null into the module's loudest jack and SUM into silence. |
source
analog-logic-maths.ts on GitHub.