public void ProcessEnvelope(double val)
        {
            double combinedFiltered;
            double decay;

            // 1. Rectify the input signal
            val = Math.Abs(val);

            // 2. Band pass filter to ~  100hz - 2Khz
            //lpValue = lpAlpha * val + (1 - lpAlpha) * lpValue;
            var lpValue = inputFilter.Process(val);

            //hpSignal = hipassAlpha * lpSignal + (1 - hipassAlpha) * hpSignal

            // rectify the lpValue again, because the resonance in the filter can cause a tiny bit of ringing and cause the values to go negative again
            lpValue = Math.Abs(lpValue);

            var mainInput = lpValue;

            // 3. Compute the EMA and SMA of the band-filtered signal. Also compute the per-sample dB decay baed on the SMA
            var emaValue = ema.Update(mainInput);
            var smaValue = sma.Update(mainInput);

            // 4. use a latching low-pass classifier to determine if signal strength is generally increasing or decreasing.
            // This removes spike from the signal where the SMA may move in the opposite direction for a short period
            var movementValue = movementLatch.Update(sma.GetDbDecayPerSample() > 0);

            // 5. If the movement is going up, prefer the faster moving EMA signal if it's above the SMA
            // If the movement is going down, prefer the faster moving EMA signal if it's below the SMA
            // otherwise, use SMA
            if (movementValue > 0)             // going up
            {
                combinedFiltered = emaValue > smaValue ? emaValue : smaValue;
            }
            else             // going down
            {
                combinedFiltered = emaValue < smaValue ? emaValue : smaValue;
            }

            // 6. use a hold mechanism to store the peak
            if (combinedFiltered > hold)
            {
                hold = combinedFiltered;
                lastTriggerCounter = 0;
            }

            // 7. Choosing the decay speed
            // Under normal conditions, use the decay from the SMA, scaled by a fudge factor to make it slightly faster decaying.
            // The reason for this is so that we gently bump into the peaks of the signal once in a while.
            // If the hold mechanism hasn't been triggered for a specific timeout, then the current hold value is too high, and we need to rapidly decay downwards.
            // Use the fastDecay (based on the user- specified release value) as a slew limited value
            if (lastTriggerCounter > triggerCounterTimeoutSamples)
            {
                decay = fastDecay;
            }
            else
            {
                decay = Utils.Db2Gain(sma.GetDbDecayPerSample() * 1.2);                 // 1.2 is fudge factor to make the follower decay slightly faster than actual signal, so we gently bump into the peaks
            }
            // 7.5 Limit the decay speed in the general range of slowDecay...fastDecay, the slow decay is currently a fixed 3 seconds to -60dB value
            if (decay > slowDecay)
            {
                decay = slowDecay;
            }
            if (decay < fastDecay)
            {
                decay = fastDecay;
            }

            hold = hold * decay;

            // 8. Filter the resulting hold signal to retrieve a smooth envelope.
            // Currently using 4x 1 pole lowpass, should replace with a proper 4th order butterworth
            h1 = holdAlpha * hold + (1 - holdAlpha) * h1;
            h2 = holdAlpha * h1 + (1 - holdAlpha) * h2;
            h3 = holdAlpha * h2 + (1 - holdAlpha) * h3;
            h4 = holdAlpha * h3 + (1 - holdAlpha) * h4;

            holdFiltered = h4;
            lastTriggerCounter++;
        }