/// <summary>
        /// Multiply the profile by the given gain factor.
        /// </summary>
        /// <param name="scale"></param>
        /// <returns></returns>
        public FilterProfile Scale(double scale)
        {
            FilterProfile lfg = new FilterProfile();

            for (int j = 0; j < lfg.Count; j++)
            {
                FreqGain fg = lfg[j];
                lfg.Add(new FreqGain(fg.Freq, fg.Gain * scale));
            }
            return(lfg);
        }
        /// <summary>
        /// Create a subset of the profile, within the given frequency range.
        /// </summary>
        /// <param name="fMin"></param>
        /// <param name="fMax"></param>
        /// <returns></returns>
        public FilterProfile FreqRange(double fMin, double fMax)
        {
            FilterProfile lfg = new FilterProfile();

            foreach (FreqGain fg in this)
            {
                if (fg.Freq >= fMin && fg.Freq <= fMax)
                {
                    lfg.Add(fg);
                }
            }
            return(lfg);
        }
Beispiel #3
0
        public static FilterProfile DifferentialSPL(double phon0, double phon1, double scale)
        {
            FilterProfile spl  = new FilterProfile();
            FilterProfile spl0 = Loudness.SPL(phon0);
            FilterProfile spl1 = Loudness.SPL(phon1);

            for (int j = 0; j < spl1.Count; j++)
            {
                FreqGain fg = spl1[j];
                fg.Gain = scale * (spl0[j].Gain - fg.Gain);
                spl.Add(fg);
            }
            return(spl);
        }
        /// <summary>
        /// Compute the filter profile of an impulse.
        /// NOTE: very memory-intensive!
        /// </summary>
        /// <param name="impulse">The impulse file</param>
        /// <param name="fractionsOfERB">1.0 for ERB-spaced bands. Smaller for less smoothing</param>
        public FilterProfile(ISoundObj impulse, double fractionsOfERB)
            : base()
        {
            /*
             * double[] muff = magbands(impulse, 300);
             *
             * // smooth the muff
             * double[] smoo = ERB.smooth(muff, (int)(38 / fractionsOfERB));
             *
             * // sample frequency response at ERB band centers
             * FilterProfile lfg = ERB.profile(smoo, impulse.SampleRate, fractionsOfERB);
             */
            FilterProfile lfg = Smoothing.Profile(impulse, SmoothingType.OCTAVE, fractionsOfERB);

            AddRange(lfg);
        }
Beispiel #5
0
        /// <summary>
        /// Return a list of freq/gain, at the ERB centers
        /// Assuming you smoothed the data...
        /// </summary>
        /// <param name="data">data from ERB.smooth</param>
        /// <param name="sr">sample rate</param>
        /// <param name="scaleFactor">1.0 for ~38 bands.  0.5 for twice as many...</param>
        /// <returns></returns>
        public static FilterProfile profile(double[] data, uint sr, double scaleFactor)
        {
            FilterProfile pts = new FilterProfile();
            int           dl  = data.Length;

            for (double j = 1; j < ERB.ERBVal(sr / 2) + 1; j += scaleFactor)
            {
                double f = ERB.invERBVal(j);
                double n = f * 2 * dl / sr;
                if (n < dl)
                {
                    double g = data[(int)n];
                    pts.Add(new FreqGain(f, g));
                }
            }
            return(pts);
        }
        public FilterProfile Inverse(double maxGain)
        {
            FilterProfile lfg = new FilterProfile();

            foreach (FreqGain fg in this)
            {
                double newGain = -fg.Gain;
                if (maxGain != 0)
                {
                    // Don't make more than +/-maxGain dB difference!
                    newGain = Math.Min(newGain, maxGain);
                    newGain = Math.Max(newGain, -maxGain);
                    lfg.Add(new FreqGain(fg.Freq, newGain));
                }
            }
            return(lfg);
        }
        /// <summary>
        /// Create a linear-phase filter impulse.
        /// </summary>
        /// <param name="nSize">Size: determines length of the final filter - suggest 4096 or 8192 (or 0 to auto-set)</param>
        /// <param name="coefficients">List of {frequency Hz, gain dB}</param>
        /// <param name="interpolation">type of interpolation (cosine)</param>
        public FilterImpulse(int nSize, FilterProfile coefficients, FilterInterpolation interpolation, uint sampleRate)
        {
            if (sampleRate == 0)
            {
                throw new Exception("Sample rate cannot be zero");
            }

            _nSamples  = nSize;
            _coeffs    = coefficients;
            _int       = interpolation;
            SampleRate = sampleRate;

            // Check the coefficients are sorted and non-overlapping
            _coeffs.Sort(new FreqGainComparer());
            FilterProfile co = new FilterProfile();

            _allZero = true;
            double prevFreq = -1;
            double freqDiff = double.MaxValue;

            foreach (FreqGain fg in _coeffs)
            {
                if (fg.Freq > prevFreq && fg.Freq >= 0)
                {
                    co.Add(fg);
                    freqDiff = Math.Min(freqDiff, fg.Freq - prevFreq);
                    prevFreq = fg.Freq;
                }
                if (fg.Gain != 0)
                {
                    _allZero = false;
                }
            }
            _coeffs = co;

            if (_nSamples == 0)
            {
                // Make up a length from 4k to 32k, based on the closest-together frequencies
                _nSamples = _allZero ? 1024 : Math.Max(4096, (int)Math.Min(32768.0, 327680 / freqDiff));
            }
            _nSamples = MathUtil.NextPowerOfTwo(_nSamples);
        }
        /// <summary>
        /// Subtract one profile from another.
        /// Only valid if they share the same frequency set.
        /// </summary>
        /// <param name="c1"></param>
        /// <param name="c2"></param>
        /// <returns></returns>
        public static FilterProfile operator -(FilterProfile c1, FilterProfile c2)
        {
            if (c1.Count != c2.Count)
            {
                return(null);
            }
            FilterProfile newProfile = new FilterProfile();

            for (int j = 0; j < c1.Count; j++)
            {
                if (c1[j].Freq != c2[j].Freq)
                {
                    return(null);
                }
                double g1 = c1[j].Gain;
                double g2 = c2[j].Gain;
                newProfile.Add(new FreqGain(c1[j].Freq, g1 - g2));
            }
            return(newProfile);
        }
Beispiel #9
0
        /// <summary>
        /// Create a list of dB SPL equal-loudness values for a given 'phon' loudness
        /// (from zero, threshold, to 90)
        /// </summary>
        /// <param name="phon"></param>
        /// <returns>list of {frequency Hz, dB SPL}</returns>
        public static FilterProfile SPL(double phon)
        {
            FilterProfile lfg = new FilterProfile();

            if ((phon < 0) | (phon > 120))
            {
                throw new ArgumentException("Phon value out of bounds!");
            }
            // Setup user-defined values for equation
            double Ln = phon;

            for (int j = 0; j < f.Length; j++)
            {
                // Deriving sound pressure level from loudness level (iso226 sect 4.1)
                double Af = 4.47E-3 * Math.Pow(10, (0.025 * Ln) - 1.15) + Math.Pow(0.4 * Math.Pow(10, (((Tf[j] + Lu[j]) / 10) - 9)), af[j]);
                double Lp = ((10 / af[j]) * Math.Log10(Af)) - Lu[j] + 94;

                // Return user data
                FreqGain fg = new FreqGain(f[j], Lp);
                lfg.Add(fg);
            }
            return(lfg);
        }
Beispiel #10
0
        /// <summary>
        /// Return a list of freq/gain, only including inflection points (where the curve is flat).
        /// </summary>
        /// <param name="data"></param>
        /// <param name="sr"></param>
        /// <returns></returns>
        public static FilterProfile inflections(double[] data, uint sr)
        {
            // Differentiate
            double bins = data.Length + 1;

            double[] diff = new double[data.Length];

            double n = data[0];

            for (int j = 0; j < data.Length; j++)
            {
                double d = data[j];
                diff[j] = d - n;
                n       = d;
            }

            // Look for zero-crossings of the first derivative of data[]
            // (always include [0] and [end])
            FilterProfile pts = new FilterProfile();

            int    bin;
            double pt   = 0.1;
            int    last = -1;
            double freq;
            double lastfreq = -1;

            // Always start with points for zero and 10 Hz
            pts.Add(new FreqGain(0, MathUtil.dB(data[0])));

            freq = 10;
            bin  = (int)f2bin(freq, sr, bins);
            pts.Add(new FreqGain(freq, MathUtil.dB(data[bin])));
            pt = diff[bin];

            for (int j = bin + 1; j < data.Length; j++)
            {
                if ((pt > 0 && diff[j] <= 0) || (pt < 0 && diff[j] >= 0))
                {
                    freq = bin2f(j, sr, bins);
                    pts.Add(new FreqGain(freq, MathUtil.dB(data[j])));
                    last     = j;
                    lastfreq = freq;
                }
                pt = diff[j];
            }
            // Fill in the last few target samples
            if (lastfreq < (sr / 2) - 2050)
            {
                freq = (sr / 2) - 2050;
                bin  = (int)f2bin(freq, sr, bins);
                pts.Add(new FreqGain(freq, MathUtil.dB(data[bin])));
            }
            if (lastfreq < (sr / 2) - 1550)
            {
                freq = (sr / 2) - 1550;
                bin  = (int)f2bin(freq, sr, bins);
                pts.Add(new FreqGain(freq, MathUtil.dB(data[bin])));
            }
            if (lastfreq < sr / 2)
            {
                freq = sr / 2;
                pts.Add(new FreqGain(freq, MathUtil.dB(data[data.Length - 1])));
            }

            return(pts);
        }
Beispiel #11
0
        public static FilterProfile diffuseDiff15()
        {
            // from Farina data -15 degrees
            FilterProfile lfg = new FilterProfile();

            lfg.Add(new FreqGain(29.8999517172724, -0.0863917163326701));
            lfg.Add(new FreqGain(45.9318520170928, -0.086646594026467));
            lfg.Add(new FreqGain(62.7349359370437, -0.0874548658683244));
            lfg.Add(new FreqGain(80.348144199439, -0.0879751392064135));
            lfg.Add(new FreqGain(98.812561979239, -0.0890868621043947));
            lfg.Add(new FreqGain(118.171554124747, -0.0902608074810529));
            lfg.Add(new FreqGain(138.470910523652, -0.0909038889250574));
            lfg.Add(new FreqGain(159.759002525445, -0.0923344140142375));
            lfg.Add(new FreqGain(182.086951427111, -0.0937822151583515));
            lfg.Add(new FreqGain(205.508810136376, -0.0951728613131329));
            lfg.Add(new FreqGain(230.081759247243, -0.0964831892699499));
            lfg.Add(new FreqGain(255.866318897917, -0.0977855409466679));
            lfg.Add(new FreqGain(282.926577933456, -0.0996764404835705));
            lfg.Add(new FreqGain(311.330442067148, -0.100486603558354));
            lfg.Add(new FreqGain(341.14990292827, -0.100051270274286));
            lfg.Add(new FreqGain(372.461330102897, -0.0979260196990259));
            lfg.Add(new FreqGain(405.345788522409, -0.0908775515206414));
            lfg.Add(new FreqGain(439.889383835671, -0.0782636965770721));
            lfg.Add(new FreqGain(476.183638720577, -0.0589294155247667));
            lfg.Add(new FreqGain(514.325903454604, -0.0331101724182802));
            lfg.Add(new FreqGain(554.419804479247, 0.0100958113611724));
            lfg.Add(new FreqGain(596.575735167586, 0.0479470506982144));
            lfg.Add(new FreqGain(640.911393547776, 0.105430778442781));
            lfg.Add(new FreqGain(687.552372358488, 0.168896217319817));
            lfg.Add(new FreqGain(736.632807529586, 0.237255771124081));
            lfg.Add(new FreqGain(788.296092007413, 0.328490953798301));
            lfg.Add(new FreqGain(842.695662798627, 0.402734259074768));
            lfg.Add(new FreqGain(899.99587021156, 0.494326782264423));
            lfg.Add(new FreqGain(960.372939556513, 0.578128079437876));
            lfg.Add(new FreqGain(1024.01603705869, 0.660125601312093));
            lfg.Add(new FreqGain(1091.12845347812, 0.712681005041455));
            lfg.Add(new FreqGain(1161.92892096669, 0.732542794364541));
            lfg.Add(new FreqGain(1236.65308108085, 0.726404101177543));
            lfg.Add(new FreqGain(1315.55512467678, 0.698273367243763));
            lfg.Add(new FreqGain(1398.90962772937, 0.645682099120009));
            lfg.Add(new FreqGain(1487.01361103779, 0.571255784106514));
            lfg.Add(new FreqGain(1580.18885643692, 0.4830388210465));
            lfg.Add(new FreqGain(1678.7845176806, 0.408070371811873));
            lfg.Add(new FreqGain(1783.18007079301, 0.35550515378515));
            lfg.Add(new FreqGain(1893.78865663959, 0.319200925184918));
            lfg.Add(new FreqGain(2011.06087804797, 0.311247539991447));
            lfg.Add(new FreqGain(2135.48912539139, 0.320676353553954));
            lfg.Add(new FreqGain(2267.61251860637, 0.337219551748223));
            lfg.Add(new FreqGain(2408.02257075748, 0.396218572472187));
            lfg.Add(new FreqGain(2557.3696992537, 0.477239191635716));
            lfg.Add(new FreqGain(2716.3707366486, 0.49349820475482));
            lfg.Add(new FreqGain(2885.81762489105, 0.454308524133459));
            lfg.Add(new FreqGain(3066.58751658265, 0.202619261440745));
            lfg.Add(new FreqGain(3259.65455639083, -0.229775101327912));
            lfg.Add(new FreqGain(3466.1036780904, -0.679735290459132));
            lfg.Add(new FreqGain(3687.14683149463, -1.14273604455762));
            lfg.Add(new FreqGain(3924.14215377249, -1.58712231737431));
            lfg.Add(new FreqGain(4178.61672801844, -2.24464955682634));
            lfg.Add(new FreqGain(4452.29373750316, -2.95221883480249));
            lfg.Add(new FreqGain(4747.12503915768, -3.59713042788595));
            lfg.Add(new FreqGain(5065.3304615832, -3.95400511725521));
            lfg.Add(new FreqGain(5409.44550497149, -4.26734231473008));
            lfg.Add(new FreqGain(5782.37961614996, -4.29752236704959));
            lfg.Add(new FreqGain(6187.48787900699, -3.80417940781499));
            lfg.Add(new FreqGain(6628.65986711531, -3.42269750300152));
            lfg.Add(new FreqGain(7110.43065099071, -2.67952601614751));
            lfg.Add(new FreqGain(7638.12068410502, -1.40074317089712));
            lfg.Add(new FreqGain(8218.013729816, -0.278815569277744));
            lfg.Add(new FreqGain(8857.58547111898, -0.10133776498712));
            lfg.Add(new FreqGain(9565.80048575836, -1.16608058344807));
            lfg.Add(new FreqGain(10353.5026895216, -1.11758243515913));
            lfg.Add(new FreqGain(11233.9354678215, 0.278943448347119));
            lfg.Add(new FreqGain(12223.4446965003, 0.908362838092288));
            lfg.Add(new FreqGain(13342.444347283, 0.57561474694365));
            lfg.Add(new FreqGain(14616.7666969568, -0.0622868258733881));
            lfg.Add(new FreqGain(16079.5885672628, -0.254955438747692));
            lfg.Add(new FreqGain(17774.2422466263, -0.24984582194041));
            lfg.Add(new FreqGain(19758.4244207167, -0.00233095236861375));
            lfg.Add(new FreqGain(22110.6876081231, -0.000536752738788648));
            return(lfg);
        }
Beispiel #12
0
        public static FilterProfile diffuseDiff0()
        {
            // from Farina data 0 degrees
            FilterProfile lfg = new FilterProfile();

            lfg.Add(new FreqGain(29.8999517172724, -0.819594013962942));
            lfg.Add(new FreqGain(45.9318520170928, -0.825206846036483));
            lfg.Add(new FreqGain(62.7349359370437, -0.843228404280093));
            lfg.Add(new FreqGain(80.348144199439, -0.85549279781466));
            lfg.Add(new FreqGain(98.812561979239, -0.885552104079416));
            lfg.Add(new FreqGain(118.171554124747, -0.921814975716754));
            lfg.Add(new FreqGain(138.470910523652, -0.941989434053033));
            lfg.Add(new FreqGain(159.759002525445, -0.986288515963084));
            lfg.Add(new FreqGain(182.086951427111, -1.03487811152306));
            lfg.Add(new FreqGain(205.508810136376, -1.08724309366587));
            lfg.Add(new FreqGain(230.081759247243, -1.14301616694228));
            lfg.Add(new FreqGain(255.866318897917, -1.20202072457563));
            lfg.Add(new FreqGain(282.926577933456, -1.29716987120868));
            lfg.Add(new FreqGain(311.330442067148, -1.36375538636994));
            lfg.Add(new FreqGain(341.14990292827, -1.4644642435199));
            lfg.Add(new FreqGain(372.461330102897, -1.52904718749126));
            lfg.Add(new FreqGain(405.345788522409, -1.61553093677067));
            lfg.Add(new FreqGain(439.889383835671, -1.68163798221837));
            lfg.Add(new FreqGain(476.183638720577, -1.71733965267451));
            lfg.Add(new FreqGain(514.325903454604, -1.71900339686128));
            lfg.Add(new FreqGain(554.419804479247, -1.66747850462173));
            lfg.Add(new FreqGain(596.575735167586, -1.59447747686689));
            lfg.Add(new FreqGain(640.911393547776, -1.45582456727674));
            lfg.Add(new FreqGain(687.552372358488, -1.28169168214036));
            lfg.Add(new FreqGain(736.632807529586, -1.08266101402942));
            lfg.Add(new FreqGain(788.296092007413, -0.799257236450344));
            lfg.Add(new FreqGain(842.695662798627, -0.550308170104235));
            lfg.Add(new FreqGain(899.99587021156, -0.216876477890536));
            lfg.Add(new FreqGain(960.372939556513, 0.123762097833653));
            lfg.Add(new FreqGain(1024.01603705869, 0.504501005258036));
            lfg.Add(new FreqGain(1091.12845347812, 0.806009630861022));
            lfg.Add(new FreqGain(1161.92892096669, 0.970563802808751));
            lfg.Add(new FreqGain(1236.65308108085, 0.993384317252108));
            lfg.Add(new FreqGain(1315.55512467678, 0.899269754624433));
            lfg.Add(new FreqGain(1398.90962772937, 0.71574567174392));
            lfg.Add(new FreqGain(1487.01361103779, 0.42413561491627));
            lfg.Add(new FreqGain(1580.18885643692, 0.0143087139306365));
            lfg.Add(new FreqGain(1678.7845176806, -0.374163000274005));
            lfg.Add(new FreqGain(1783.18007079301, -0.604206586990272));
            lfg.Add(new FreqGain(1893.78865663959, -0.643361845768994));
            lfg.Add(new FreqGain(2011.06087804797, -0.450261422187758));
            lfg.Add(new FreqGain(2135.48912539139, -0.117143308385737));
            lfg.Add(new FreqGain(2267.61251860637, 0.0726448007728625));
            lfg.Add(new FreqGain(2408.02257075748, 0.149673576192565));
            lfg.Add(new FreqGain(2557.3696992537, -0.0705597943707172));
            lfg.Add(new FreqGain(2716.3707366486, -0.615399531580617));
            lfg.Add(new FreqGain(2885.81762489105, -0.715844747528019));
            lfg.Add(new FreqGain(3066.58751658265, -0.80980936924732));
            lfg.Add(new FreqGain(3259.65455639083, -0.724599496650513));
            lfg.Add(new FreqGain(3466.1036780904, -1.74219819410634));
            lfg.Add(new FreqGain(3687.14683149463, -3.60307539107681));
            lfg.Add(new FreqGain(3924.14215377249, -5.62149036113584));
            lfg.Add(new FreqGain(4178.61672801844, -7.30684974206415));
            lfg.Add(new FreqGain(4452.29373750316, -9.58452126557679));
            lfg.Add(new FreqGain(4747.12503915768, -12.7988548069547));
            lfg.Add(new FreqGain(5065.3304615832, -14.2817841410128));
            lfg.Add(new FreqGain(5409.44550497149, -14.3089505650728));
            lfg.Add(new FreqGain(5782.37961614996, -14.7676142885599));
            lfg.Add(new FreqGain(6187.48787900699, -15.4620314368829));
            lfg.Add(new FreqGain(6628.65986711531, -17.5471846623073));
            lfg.Add(new FreqGain(7110.43065099071, -16.7838733846363));
            lfg.Add(new FreqGain(7638.12068410502, -11.2810169858127));
            lfg.Add(new FreqGain(8218.013729816, -6.43017437119144));
            lfg.Add(new FreqGain(8857.58547111898, -2.58756224649037));
            lfg.Add(new FreqGain(9565.80048575836, -3.18112947019392));
            lfg.Add(new FreqGain(10353.5026895216, -5.40667046909438));
            lfg.Add(new FreqGain(11233.9354678215, -3.35732869042161));
            lfg.Add(new FreqGain(12223.4446965003, -1.40180859827503));
            lfg.Add(new FreqGain(13342.444347283, -2.18457352314182));
            lfg.Add(new FreqGain(14616.7666969568, -2.52559711716481));
            lfg.Add(new FreqGain(16079.5885672628, -2.64456253082918));
            lfg.Add(new FreqGain(17774.2422466263, -2.07661523855391));
            lfg.Add(new FreqGain(19758.4244207167, -0.0243216938532986));
            lfg.Add(new FreqGain(22110.6876081231, -0.00493030880131535));
            return(lfg);
        }
Beispiel #13
0
        public static FilterProfile diffuseDiff45()
        {
            // from Farina data -45 degrees
            FilterProfile lfg = new FilterProfile();

            lfg.Add(new FreqGain(29.8999517172724, 0.034493028904745));
            lfg.Add(new FreqGain(45.9318520170928, 0.0348965563859305));
            lfg.Add(new FreqGain(62.7349359370437, 0.0361962782805971));
            lfg.Add(new FreqGain(80.348144199439, 0.0370951759531601));
            lfg.Add(new FreqGain(98.812561979239, 0.0393802905089846));
            lfg.Add(new FreqGain(118.171554124747, 0.0422391555889454));
            lfg.Add(new FreqGain(138.470910523652, 0.0438547095733166));
            lfg.Add(new FreqGain(159.759002525445, 0.0474495412837798));
            lfg.Add(new FreqGain(182.086951427111, 0.0515476348543647));
            lfg.Add(new FreqGain(205.508810136376, 0.056162673196398));
            lfg.Add(new FreqGain(230.081759247243, 0.0612659549892737));
            lfg.Add(new FreqGain(255.866318897917, 0.0668005443605352));
            lfg.Add(new FreqGain(282.926577933456, 0.0758917506709455));
            lfg.Add(new FreqGain(311.330442067148, 0.0824530823635971));
            lfg.Add(new FreqGain(341.14990292827, 0.0929637778755104));
            lfg.Add(new FreqGain(372.461330102897, 0.100379371162514));
            lfg.Add(new FreqGain(405.345788522409, 0.111984167288103));
            lfg.Add(new FreqGain(439.889383835671, 0.123975744334166));
            lfg.Add(new FreqGain(476.183638720577, 0.136237010524912));
            lfg.Add(new FreqGain(514.325903454604, 0.148734117891156));
            lfg.Add(new FreqGain(554.419804479247, 0.165502936111769));
            lfg.Add(new FreqGain(596.575735167586, 0.178043988212559));
            lfg.Add(new FreqGain(640.911393547776, 0.194349156663897));
            lfg.Add(new FreqGain(687.552372358488, 0.209865869797881));
            lfg.Add(new FreqGain(736.632807529586, 0.22500194685938));
            lfg.Add(new FreqGain(788.296092007413, 0.243525065270957));
            lfg.Add(new FreqGain(842.695662798627, 0.257649467879212));
            lfg.Add(new FreqGain(899.99587021156, 0.273803874204412));
            lfg.Add(new FreqGain(960.372939556513, 0.28709311052957));
            lfg.Add(new FreqGain(1024.01603705869, 0.299481257886807));
            lfg.Add(new FreqGain(1091.12845347812, 0.309245022903803));
            lfg.Add(new FreqGain(1161.92892096669, 0.317179867687928));
            lfg.Add(new FreqGain(1236.65308108085, 0.321207380680425));
            lfg.Add(new FreqGain(1315.55512467678, 0.318824411496162));
            lfg.Add(new FreqGain(1398.90962772937, 0.307833522186889));
            lfg.Add(new FreqGain(1487.01361103779, 0.289293331349614));
            lfg.Add(new FreqGain(1580.18885643692, 0.261606526767296));
            lfg.Add(new FreqGain(1678.7845176806, 0.228997685797403));
            lfg.Add(new FreqGain(1783.18007079301, 0.197540714557954));
            lfg.Add(new FreqGain(1893.78865663959, 0.17295074128593));
            lfg.Add(new FreqGain(2011.06087804797, 0.156696169926535));
            lfg.Add(new FreqGain(2135.48912539139, 0.148455185344538));
            lfg.Add(new FreqGain(2267.61251860637, 0.154528024795868));
            lfg.Add(new FreqGain(2408.02257075748, 0.157020651297763));
            lfg.Add(new FreqGain(2557.3696992537, 0.147606277996199));
            lfg.Add(new FreqGain(2716.3707366486, 0.131041736855722));
            lfg.Add(new FreqGain(2885.81762489105, 0.0866347064265516));
            lfg.Add(new FreqGain(3066.58751658265, -0.0166654973944371));
            lfg.Add(new FreqGain(3259.65455639083, -0.191612322714693));
            lfg.Add(new FreqGain(3466.1036780904, -0.432511035136432));
            lfg.Add(new FreqGain(3687.14683149463, -0.658960079848589));
            lfg.Add(new FreqGain(3924.14215377249, -0.762774466055965));
            lfg.Add(new FreqGain(4178.61672801844, -0.72195332419533));
            lfg.Add(new FreqGain(4452.29373750316, -0.589733799295838));
            lfg.Add(new FreqGain(4747.12503915768, -0.42970971679252));
            lfg.Add(new FreqGain(5065.3304615832, -0.232527169811399));
            lfg.Add(new FreqGain(5409.44550497149, -0.0355174224726339));
            lfg.Add(new FreqGain(5782.37961614996, 0.226790461488208));
            lfg.Add(new FreqGain(6187.48787900699, 0.570687924885134));
            lfg.Add(new FreqGain(6628.65986711531, 0.902844690346035));
            lfg.Add(new FreqGain(7110.43065099071, 0.97846591522975));
            lfg.Add(new FreqGain(7638.12068410502, 0.785508262062104));
            lfg.Add(new FreqGain(8218.013729816, 0.635399466540685));
            lfg.Add(new FreqGain(8857.58547111898, 0.525129410649112));
            lfg.Add(new FreqGain(9565.80048575836, 0.366859907213853));
            lfg.Add(new FreqGain(10353.5026895216, 0.447897246086743));
            lfg.Add(new FreqGain(11233.9354678215, 0.36565051131466));
            lfg.Add(new FreqGain(12223.4446965003, 0.489904439751699));
            lfg.Add(new FreqGain(13342.444347283, 0.338111293138435));
            lfg.Add(new FreqGain(14616.7666969568, 0.237275309909941));
            lfg.Add(new FreqGain(16079.5885672628, 0.1220539710691));
            lfg.Add(new FreqGain(17774.2422466263, 0.0725148136373865));
            lfg.Add(new FreqGain(19758.4244207167, 0.00128859185038382));
            lfg.Add(new FreqGain(22110.6876081231, 6.13639214105897E-05));
            return(lfg);
        }
 /// <summary>
 /// Copy constructor
 /// </summary>
 /// <param name="lfg"></param>
 public FilterProfile(FilterProfile lfg)
     : base(lfg)
 {
 }
        private static IEnumerator <double> Arbitrary(int length, FilterProfile coeffs, uint sampleRate)
        {
            // Generate random-phase with specified magnitudes in the frequency domain, then IFFT.
            // This noise is periodic - length (next power of 2 from 'n')

            int l = MathUtil.NextPowerOfTwo(length);

            Complex[] data = new Complex[l];

            int    n     = 0;
            double freq1 = coeffs[n].Freq * 2 * l / sampleRate;
            double freq2 = coeffs[n + 1].Freq * 2 * l / sampleRate;
            double gain1 = coeffs[n].Gain;
            double gain2 = coeffs[n + 1].Gain;

            double logn = Math.Log(l);

            for (int j = 0; j < l; j++)
            {
                double gainDb;
                double gain;
                if (j > freq2)
                {
                    // Move to the next coefficient
                    n++;
                    if (n < coeffs.Count - 1)
                    {
                        freq1 = coeffs[n].Freq * 2 * l / sampleRate;
                        freq2 = coeffs[n + 1].Freq * 2 * l / sampleRate;
                        gain1 = coeffs[n].Gain;
                        gain2 = coeffs[n + 1].Gain;
                    }
                }
                if (j < freq1)
                {
                    gainDb = gain1;
                }
                else if (j > freq2)
                {
                    gainDb = gain2;
                }
                else
                {
                    // Raised Cosine: 0.5* ( cos(phi) + 1 ), from phi=pi to 2pi
                    //
                    double frac = (double)(j - freq1) / (double)(freq2 - freq1);
                    double ph   = Math.PI * (1 + frac);
                    double rcos = (1 + Math.Cos(ph)) / 2;
                    gainDb = gain1 + rcos * (gain2 - gain1);
                }
                gain = MathUtil.gain(gainDb);

                // Create a random phase value from 0 to 2pi
                double phi = NextRandom() * 2 * Math.PI;
                // Magnitude is 1, so just trig
                double re = Math.Cos(phi);
                double im = Math.Sin(phi);
                data[j] = new Complex(gain * logn * re, gain * logn * im);
            }

            // IFFT
            Fourier.IFFT((int)l, data);

            // Return the real component
            int k = 0;

            while (true)
            {
                yield return(data[k].Re * logn);

                k++;
                if (k >= l)
                {
                    k = 0;
                }
            }
        }