Hi @Thor_Madsen,
It depends what the problem is… If you’re getting multiple triggers on decay, it could be that the signal needs to be smoothed more, or the high pass frequency needs to be increased to filter out low frequency variation that can cause a messy envelope.
If you’re getting triggers when your signal is very low, you could either gate it, or increase the changeThresh
.
There could be smarter ways of using triggers here, but I tried to limit the complexity.
The phase of Impulse can’t be reset in a straightforward way, it’s like an oscillator in that sense. If you want to reset a periodic signal, something like Phasor
would work.
I’ve refactored the code to be a bit more clear (sorry I rushed out the last version and wasn’t very good about variable naming and comments)
(
s.waitForBoot {
{
var checkPeakTrig, peakVal, peakHold, peakChange;
var isIncreasing, isDecreasing, wasIncreasing, isDecayingTrig, decayTrigViz;
/* Tuning variables */
// Smoothing window size (sec)
var smoothWin = 0.05;
// High pass frequency to reduce variation at low frequencies
// which can make the envelope messy
var hpFreq = 150;
// Rate at which the peak value is sampled
// Should be less than your signal's frequency
var checkPeakRate = 90;
// Threshold level change for detecting rising or falling signal
var changeThresh = 1e-7;
/* Source signals */
// oscillator
// var sigFreq = 100;
// var sig = LFSaw.ar(sigFreq) * Env.perc(0.2, 0.2, 1, 0).ar(0, Impulse.ar(2));
// noise
var sig = PinkNoise.ar * Env.perc(0.2, 0.2, 1, 0).ar(0, Impulse.ar(2));
/* Signal smoothing */
sig = HPF.ar(sig, hpFreq); // highpass to reduce low frequency variation
sig = MovingAverage.ar( // smooth the signal if it's chaotic
sig.abs * 2, // rectify and amplify (averaged signal will have less amplitude)
numsamp: smoothWin * s.sampleRate,
maxsamp: 0.2 * s.sampleRate);
/* Measure change in the running peak value */
checkPeakTrig = Impulse.ar(checkPeakRate);
peakVal = Peak.ar(sig, Delay1.ar(checkPeakTrig));
peakHold = Latch.ar(peakVal, checkPeakTrig);
peakChange = peakHold - Delay1.ar(peakHold);
/* Generate a single trigger for a decaying peak value */
isIncreasing = peakChange > changeThresh;
isDecreasing = peakChange < changeThresh.neg;
wasIncreasing = Delay1.ar(SetResetFF.ar(isIncreasing, isDecreasing));
isDecayingTrig = wasIncreasing & isDecreasing; // <- your decay trigger
decayTrigViz = Decay.ar(isDecayingTrig, 0.1); // to hear trigger: * SinOsc.ar(300);
[sig, peakHold, wasIncreasing, decayTrigViz]
}.plot(1);
})
I’ve brought all the tunable parameters to the top to make testing easier, and if you have this running as a synth, these are the parameters you can use as arguments for testing in real-time.