Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
vactrol.hpp File Reference

The vactrol control-conditioning law: an asymmetric one-pole whose rise and fall are deliberately different. More...

#include <pulp/signal/denormal.hpp>
#include <algorithm>
#include <cmath>

Go to the source code of this file.

Classes

class  pulp::signal::VactrolConditionerT< SampleType >
 The asymmetric one-pole that lags a control signal the way a photoresistor lags its LED. More...

Namespaces

namespace  pulp
namespace  pulp::signal

Typedefs

using pulp::signal::VactrolConditioner = VactrolConditionerT<float>
using pulp::signal::VactrolConditioner64 = VactrolConditionerT<double>

Detailed Description

The vactrol control-conditioning law: an asymmetric one-pole whose rise and fall are deliberately different.

A vactrol is an LED facing a photoresistor in a sealed package. The resistance falls quickly when the LED lights and recovers slowly when it goes dark, and that asymmetry is not a design choice anyone made — it is a property of the material. Several very different-sounding circuits are built on exactly that one behaviour:

  • the Buchla lowpass gate, where it produces the unhurried decay that makes struck sounds read as physical (LowpassGateT);
  • the Univibe's four staggered phase stages, where an LED and four photocells lag the LFO into the uneven, "not-quite-a-phaser" sweep the circuit is known for;
  • any optical compressor's gain element.

They share the conditioner and differ in what they do with its output, so the conditioner lives here on its own and each circuit supplies its own constants. Duplicating the law per circuit is how two modules end up disagreeing about whether "rise" means the LED's or the photoresistor's.

Model family: Parker & D'Angelo, "A Digital Model of the Buchla Lowpass Gate", DAFx-13. The asymmetric one-pole here is the tractable core that paper identifies; the power-law control-to-gain mapping that LowpassGateT applies on top is a separate stage and stays there.

This is deliberately NOT SlewLimiterT in exponential mode, even though the arithmetic is the same shape. A slew limiter is a control-rate utility whose contract is "bound the rate of change of this signal"; a vactrol is a physical model whose contract is "reproduce this component's lag". They are spelled differently so a spec citing one cannot be satisfied by the other, and so the vactrol can grow a more detailed model later without changing what glide means.

RT contract: prepare() recomputes two coefficients and allocates nothing. set_*, process(), and reset() allocate nothing, take no locks, and perform no I/O. All state is POD; zero-init is a valid closed state.