void Process(float[] samples, int offset, bool loop)
    {
        for (int iii = 0; SubEffects != null && iii < SubEffects.Count; iii++)
        {
            if (SubEffects[iii] == null)
            {
                continue;
            }
            SubEffects[iii].Process(samples, offset, loop);
        }

        float dur = Duration;

        SetupFilters();

        double samplePeriod = 1.0f / SampleRate;

        bool flange       = flangerAmplitude > .0f && (Math.Abs(flangerOffset) > .0f || Math.Abs(flangerOffsetDelta) > .0f);
        bool phaseEchoing = phaseReset > float.Epsilon;
        bool started      = delay < (offset * samplePeriod) + float.Epsilon;
        bool echoing      = (echoTime > float.Epsilon) && (echoValue > float.Epsilon);
        bool lfo          = LFOAmplitude > float.Epsilon;

        double time = .0f;

        float[] lfoTable  = Oscillator.GetWaveTable(LFOForm);
        float[] waveTable = Oscillator.GetWaveTable(waveForm);

        float value = .0f;

        double phase     = .0f;
        double frequency = .0f;

        double amplitudeTime = offset * samplePeriod;

        float coreDuration = CoreDuration;

        for (int iii = 0; iii < samples.Length && iii < coreDuration * SampleRate; iii++)
        {
            if (amplitudeTime > dur)
            {
                if (loop)
                {
                    amplitudeTime = dur;
                }
                else
                {
                    break;
                }
            }
            amplitudeTime += samplePeriod;

            if (!started)
            {
                if (amplitudeTime < delay)
                {
                    continue;
                }
                amplitudeTime -= delay;
                started        = true;
            }

            time += samplePeriod;

            value     = AmplitudeCurve.Evaluate((float)amplitudeTime);
            frequency = FrequencyCurve.Evaluate((float)time);

            phase = time * Oscillator.tableResolution;

            uint waveIndex = (uint)(phase * frequency);

            float sample = waveTable[waveIndex % waveTable.Length];

            if (phaseEchoing)
            {
                if (time > phaseReset)
                {
                    time = .0f;
                }
            }

            if (flange)
            {
                double foff = flangerOffsetDelta * time + flangerOffset;
                waveIndex += (uint)System.Math.Round(foff * waveTable.Length);
                sample    += waveTable[waveIndex % waveTable.Length] * flangerAmplitude;
            }

            if (lfo)
            {
                uint  lfoIndex = (uint)(phase * LFOFrequency);
                float temp     = -lfoTable[lfoIndex % lfoTable.Length];
                temp   += 1.0f;
                temp   *= .5f;
                temp    = 1.0f - temp * LFOAmplitude;
                sample *= temp;
            }

            samples[iii] += sample * value;

            if (lowFilter != null)
            {
                lowFilter.FilterValue(ref samples[iii]);
            }
            if (highFilter != null)
            {
                highFilter.FilterValue(ref samples[iii]);
            }

            samples[iii] = Mathf.Clamp(samples[iii], -1.0f, 1.0f);
        }

        if (echoing)
        {
            float evolume = echoValue;
            for (int eee = 1; eee < (EchoCount + 1); eee++)
            {
                int echoIndex = (int)(echoTime * eee * (float)sampleRate);
                int max       = (int)(echoIndex + coreDuration * SampleRate);

                for (int iii = echoIndex; iii < max && iii < samples.Length; iii++)
                {
                    samples[iii] += samples[iii - echoIndex] * evolume;
                }

                evolume *= echoValue;
            }
        }
    }