frac32 poti
frac32 set0
frac32 set1
frac32 set2
int32.positive select the layer to be edited by the poti control
bool32.rising rising edge loads the values from the set input into the layer outputs (patch loading!)
frac32 out0
frac32 out1
frac32 out2
combo size of the potentiometer deadband (see description)
combo mode of operation (see description)
static const int kNumLayers = 3;
static const s32 deadbandSize = (attr_deadbandSize << 19);
s32 latch[kNumLayers];
u32 timeoutCounter;
s32 lastLoad;
s8 isMoving; // 0 == stopped, 1 == up, -1 == down
s32 motionTrackPos;
#if attr_mode == 2
bool catched;
u32 lastLayer;
s32 lastPotValue;
#endif
#if attr_mode == 3
u32 lastLayer;
s32 lastPotValue;
float scale;
s32 potiStart, valueStart;
s8 lastDirection; // 0 == invalid, 1 == up, 2 == down
#endif
for (int i = 0; i < kNumLayers; i++)
latch[i] = 0;
timeoutCounter = 10000;
lastLoad = 0;
isMoving = 0;
motionTrackPos = 0;
#if attr_mode == 2
catched = false;
lastLayer = 0;
lastPotValue = 0;
#endif
#if attr_mode == 3
lastLayer = 0;
lastPotValue = 0;
scale = 0;
potiStart = 0;
valueStart = 0;
lastDirection = 0; // 0 == invalid, 1 == up, 2 == down
#endif
u32 layer = inlet_layer;
// detect layer switching and update "catch" status
#if attr_mode == 2 || attr_mode == 3
if (lastLayer != layer) {
#if attr_mode == 2
catched = false;
if ((layer >= 0) && (layer < 3)) {
s32 deviation = latch[layer] - inlet_poti;
if ((deviation < deadbandSize) && (deviation > -deadbandSize)) {
catched = true;
}
}
#elif attr_mode == 3
lastDirection = 0; // reset to invalid
#endif
}
#endif
// pot was untouched for some time
if (!isMoving) {
// check for a change in the value
s32 change = inlet_poti - motionTrackPos;
if (change > deadbandSize) {
timeoutCounter = 0;
motionTrackPos = inlet_poti;
isMoving = 1;
} else if (change < -deadbandSize) {
timeoutCounter = 0;
motionTrackPos = inlet_poti;
isMoving = -1;
}
}
// the poti is moving. But did it stop just now?
if (isMoving) // no else!
{
timeoutCounter++;
if (timeoutCounter >= 50) {
s32 change = inlet_poti - motionTrackPos;
if (change > deadbandSize >> 1) {
timeoutCounter = 0;
motionTrackPos = inlet_poti;
isMoving = 1;
} else if (change<-deadbandSize> > 1) {
timeoutCounter = 0;
motionTrackPos = inlet_poti;
isMoving = -1;
} else if (timeoutCounter > 2000) {
#if attr_mode == 3
lastDirection = 0;
#endif
isMoving = 0;
}
}
}
// apply new value if there was a change recently
if (isMoving) {
if ((layer >= 0) && (layer < 3)) {
#if attr_mode == 1
latch[layer] = inlet_poti;
#elif attr_mode == 2
if (!catched) {
if (((lastPotValue <= latch[layer]) && (inlet_poti >= latch[layer])) ||
((lastPotValue > latch[layer]) && (inlet_poti <= latch[layer]))) {
catched = true;
}
}
if (catched) // no else!
{
latch[layer] = inlet_poti;
}
#elif attr_mode == 3
if (inlet_poti >= 64 << 21)
latch[layer] = 64 << 21;
else if (inlet_poti <= 0)
latch[layer] = 0;
else {
if ((lastDirection < 1) && (isMoving >= 1) && (inlet_poti < 64 << 21)) {
potiStart = inlet_poti;
valueStart = latch[layer];
s32 remainingPotiTravel = (64 << 21) - inlet_poti;
s32 remainingValueTravel = (64 << 21) - latch[layer];
scale = ((float)remainingValueTravel) / ((float)remainingPotiTravel);
} else if ((lastDirection > -1) && (isMoving <= -1) && (inlet_poti > 0)) {
potiStart = inlet_poti;
valueStart = latch[layer];
scale = (float)(latch[layer]) / (float)(inlet_poti);
}
if (isMoving == 1) {
latch[layer] = valueStart + scale * (inlet_poti - potiStart);
} else if (isMoving == -1) {
latch[layer] = valueStart + scale * (inlet_poti - potiStart);
}
}
lastDirection = isMoving;
#endif
}
#if attr_mode == 2 || attr_mode == 3
lastPotValue = inlet_poti;
#endif
}
// load values if trigger received
if (inlet_load && !lastLoad) {
latch[0] = inlet_set0;
latch[1] = inlet_set1;
latch[2] = inlet_set2;
}
lastLoad = inlet_load;
// write outputs
outlet_out0 = latch[0];
outlet_out1 = latch[1];
outlet_out2 = latch[2];
#if attr_mode == 2 || attr_mode == 3
lastLayer = inlet_layer;
#endif